Unverified Commit 6e5c3ab8 authored by Mark Brown's avatar Mark Brown
Browse files

Merge series "spi: pxa2xx: Set of cleanups" from Andy Shevchenko...

Merge series "spi: pxa2xx: Set of cleanups" from Andy Shevchenko <andriy.shevchenko@linux.intel.com>:

Set of cleanups here and there related to the SPI PXA2xx driver.
On top of them, adding the special type for Intel Merrifield.

In v3:
- rebased on top of v5.13-rc1 and/or spi/for-5,14

In v2:
- cover letter (Mark)
- drop moving the header in patch 5 (Mark)

Andy Shevchenko (14):
  spi: pxa2xx: Use one point of return when ->probe() fails
  spi: pxa2xx: Utilize MMIO and physical base from struct ssp_device
  spi: pxa2xx: Utilize struct device from struct ssp_device
  spi: pxa2xx: Replace header inclusions by forward declarations
  spi: pxa2xx: Unify ifdeffery used in the headers
  spi: pxa2xx: Group Intel Quark specific definitions
  spi: pxa2xx: Introduce int_stop_and_reset() helper
  spi: pxa2xx: Reuse int_error_stop() in pxa2xx_spi_slave_abort()
  spi: pxa2xx: Use pxa_ssp_enable()/pxa_ssp_disable() in the driver
  spi: pxa2xx: Extract pxa2xx_spi_update() helper
  spi: pxa2xx: Extract clear_SSCR1_bits() helper
  spi: pxa2xx: Extract read_SSSR_bits() helper
  spi: pxa2xx: Constify struct driver_data parameter
  spi: pxa2xx: Introduce special type for Merrifield SPIs

 drivers/spi/spi-pxa2xx-dma.c   |  37 +++----
 drivers/spi/spi-pxa2xx-pci.c   |   4 +-
 drivers/spi/spi-pxa2xx.c       | 190 +++++++++++++++++----------------
 drivers/spi/spi-pxa2xx.h       |  52 ++++-----
 include/linux/pxa2xx_ssp.h     |  42 +++++++-
 include/linux/spi/pxa2xx_spi.h |   9 +-
 sound/soc/pxa/pxa-ssp.c        |  16 ---
 7 files changed, 185 insertions(+), 165 deletions(-)

--
2.30.2
parents 532259bf 3fdb59cf
Loading
Loading
Loading
Loading
+5 −12
Original line number Diff line number Diff line
@@ -34,25 +34,18 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
		 * might not know about the error yet. So we re-check the
		 * ROR bit here before we clear the status register.
		 */
		if (!error) {
			u32 status = pxa2xx_spi_read(drv_data, SSSR)
				     & drv_data->mask_sr;
			error = status & SSSR_ROR;
		}
		if (!error)
			error = read_SSSR_bits(drv_data, drv_data->mask_sr) & SSSR_ROR;

		/* Clear status & disable interrupts */
		pxa2xx_spi_write(drv_data, SSCR1,
				 pxa2xx_spi_read(drv_data, SSCR1)
				 & ~drv_data->dma_cr1);
		clear_SSCR1_bits(drv_data, drv_data->dma_cr1);
		write_SSSR_CS(drv_data, drv_data->clear_sr);
		if (!pxa25x_ssp_comp(drv_data))
			pxa2xx_spi_write(drv_data, SSTO, 0);

		if (error) {
			/* In case we got an error we disable the SSP now */
			pxa2xx_spi_write(drv_data, SSCR0,
					 pxa2xx_spi_read(drv_data, SSCR0)
					 & ~SSCR0_SSE);
			pxa_ssp_disable(drv_data->ssp);
			msg->status = -EIO;
		}

@@ -123,7 +116,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{
	u32 status;

	status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
	status = read_SSSR_bits(drv_data, drv_data->mask_sr);
	if (status & SSSR_ROR) {
		dev_err(drv_data->ssp->dev, "FIFO overrun\n");

+1 −1
Original line number Diff line number Diff line
@@ -179,7 +179,7 @@ static struct pxa_spi_info spi_info_configs[] = {
		.rx_param = &bsw2_rx_param,
	},
	[PORT_MRFLD] = {
		.type = PXA27x_SSP,
		.type = MRFLD_SSP,
		.max_clk_rate = 25000000,
		.setup = mrfld_spi_setup,
	},
+88 −82
Original line number Diff line number Diff line
@@ -200,6 +200,17 @@ static bool is_mmp2_ssp(const struct driver_data *drv_data)
	return drv_data->ssp_type == MMP2_SSP;
}

static bool is_mrfld_ssp(const struct driver_data *drv_data)
{
	return drv_data->ssp_type == MRFLD_SSP;
}

static void pxa2xx_spi_update(const struct driver_data *drv_data, u32 reg, u32 mask, u32 value)
{
	if ((pxa2xx_spi_read(drv_data, reg) & mask) != value)
		pxa2xx_spi_write(drv_data, reg, value & mask);
}

static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data)
{
	switch (drv_data->ssp_type) {
@@ -241,7 +252,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
		break;
	}

	return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask;
	return read_SSSR_bits(drv_data, mask) == mask;
}

static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
@@ -286,13 +297,11 @@ static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data,
	case QUARK_X1000_SSP:
		return clk_div
			| QUARK_X1000_SSCR0_Motorola
			| QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits)
			| SSCR0_SSE;
			| QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits);
	default:
		return clk_div
			| SSCR0_Motorola
			| SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
			| SSCR0_SSE
			| (bits > 16 ? SSCR0_EDSS : 0);
	}
}
@@ -484,7 +493,7 @@ int pxa2xx_spi_flush(struct driver_data *drv_data)
	unsigned long limit = loops_per_jiffy << 1;

	do {
		while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
		while (read_SSSR_bits(drv_data, SSSR_RNE))
			pxa2xx_spi_read(drv_data, SSDR);
	} while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit);
	write_SSSR_CS(drv_data, SSSR_ROR);
@@ -498,8 +507,7 @@ static void pxa2xx_spi_off(struct driver_data *drv_data)
	if (is_mmp2_ssp(drv_data))
		return;

	pxa2xx_spi_write(drv_data, SSCR0,
			 pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
	pxa_ssp_disable(drv_data->ssp);
}

static int null_writer(struct driver_data *drv_data)
@@ -520,8 +528,7 @@ static int null_reader(struct driver_data *drv_data)
{
	u8 n_bytes = drv_data->n_bytes;

	while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
	       && (drv_data->rx < drv_data->rx_end)) {
	while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
		pxa2xx_spi_read(drv_data, SSDR);
		drv_data->rx += n_bytes;
	}
@@ -543,8 +550,7 @@ static int u8_writer(struct driver_data *drv_data)

static int u8_reader(struct driver_data *drv_data)
{
	while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
	       && (drv_data->rx < drv_data->rx_end)) {
	while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
		*(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
		++drv_data->rx;
	}
@@ -566,8 +572,7 @@ static int u16_writer(struct driver_data *drv_data)

static int u16_reader(struct driver_data *drv_data)
{
	while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
	       && (drv_data->rx < drv_data->rx_end)) {
	while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
		*(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
		drv_data->rx += 2;
	}
@@ -589,8 +594,7 @@ static int u32_writer(struct driver_data *drv_data)

static int u32_reader(struct driver_data *drv_data)
{
	while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
	       && (drv_data->rx < drv_data->rx_end)) {
	while (read_SSSR_bits(drv_data, SSSR_RNE) && drv_data->rx < drv_data->rx_end) {
		*(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
		drv_data->rx += 4;
	}
@@ -620,47 +624,51 @@ static void reset_sccr1(struct driver_data *drv_data)
	pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
}

static void int_error_stop(struct driver_data *drv_data, const char *msg)
static void int_stop_and_reset(struct driver_data *drv_data)
{
	/* Stop and reset SSP */
	/* Clear and disable interrupts */
	write_SSSR_CS(drv_data, drv_data->clear_sr);
	reset_sccr1(drv_data);
	if (!pxa25x_ssp_comp(drv_data))
	if (pxa25x_ssp_comp(drv_data))
		return;

	pxa2xx_spi_write(drv_data, SSTO, 0);
}

static void int_error_stop(struct driver_data *drv_data, const char *msg, int err)
{
	int_stop_and_reset(drv_data);
	pxa2xx_spi_flush(drv_data);
	pxa2xx_spi_off(drv_data);

	dev_err(drv_data->ssp->dev, "%s\n", msg);

	drv_data->controller->cur_msg->status = -EIO;
	drv_data->controller->cur_msg->status = err;
	spi_finalize_current_transfer(drv_data->controller);
}

static void int_transfer_complete(struct driver_data *drv_data)
{
	/* Clear and disable interrupts */
	write_SSSR_CS(drv_data, drv_data->clear_sr);
	reset_sccr1(drv_data);
	if (!pxa25x_ssp_comp(drv_data))
		pxa2xx_spi_write(drv_data, SSTO, 0);
	int_stop_and_reset(drv_data);

	spi_finalize_current_transfer(drv_data->controller);
}

static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
{
	u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ?
		       drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
	u32 irq_status;

	u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask;
	irq_status = read_SSSR_bits(drv_data, drv_data->mask_sr);
	if (!(pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE))
		irq_status &= ~SSSR_TFS;

	if (irq_status & SSSR_ROR) {
		int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
		int_error_stop(drv_data, "interrupt_transfer: fifo overrun", -EIO);
		return IRQ_HANDLED;
	}

	if (irq_status & SSSR_TUR) {
		int_error_stop(drv_data, "interrupt_transfer: fifo underrun");
		int_error_stop(drv_data, "interrupt_transfer: fifo underrun", -EIO);
		return IRQ_HANDLED;
	}

@@ -727,8 +735,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
static void handle_bad_msg(struct driver_data *drv_data)
{
	pxa2xx_spi_off(drv_data);
	pxa2xx_spi_write(drv_data, SSCR1,
			 pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1);
	clear_SSCR1_bits(drv_data, drv_data->int_cr1);
	if (!pxa25x_ssp_comp(drv_data))
		pxa2xx_spi_write(drv_data, SSTO, 0);
	write_SSSR_CS(drv_data, drv_data->clear_sr);
@@ -1081,42 +1088,40 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
			dma_mapped ? "DMA" : "PIO");

	if (is_lpss_ssp(drv_data)) {
		if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
		    != chip->lpss_rx_threshold)
			pxa2xx_spi_write(drv_data, SSIRF,
					 chip->lpss_rx_threshold);
		if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff)
		    != chip->lpss_tx_threshold)
			pxa2xx_spi_write(drv_data, SSITF,
					 chip->lpss_tx_threshold);
		pxa2xx_spi_update(drv_data, SSIRF, GENMASK(7, 0), chip->lpss_rx_threshold);
		pxa2xx_spi_update(drv_data, SSITF, GENMASK(15, 0), chip->lpss_tx_threshold);
	}

	if (is_quark_x1000_ssp(drv_data) &&
	    (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate))
		pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate);
	if (is_mrfld_ssp(drv_data)) {
		u32 thresh = 0;

	/* see if we need to reload the config registers */
	if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0)
	    || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask)
	    != (cr1 & change_mask)) {
		/* stop the SSP, and update the other bits */
		thresh |= SFIFOTT_RxThresh(chip->lpss_rx_threshold);
		thresh |= SFIFOTT_TxThresh(chip->lpss_tx_threshold);

		pxa2xx_spi_update(drv_data, SFIFOTT, 0xffffffff, thresh);
	}

	if (is_quark_x1000_ssp(drv_data))
		pxa2xx_spi_update(drv_data, DDS_RATE, GENMASK(23, 0), chip->dds_rate);

	/* Stop the SSP */
	if (!is_mmp2_ssp(drv_data))
			pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE);
		pxa_ssp_disable(drv_data->ssp);

	if (!pxa25x_ssp_comp(drv_data))
		pxa2xx_spi_write(drv_data, SSTO, chip->timeout);

	/* first set CR1 without interrupt and service enables */
		pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask);
		/* restart the SSP */
		pxa2xx_spi_write(drv_data, SSCR0, cr0);
	pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1);

	} else {
		if (!pxa25x_ssp_comp(drv_data))
			pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
	}
	/* see if we need to reload the config registers */
	pxa2xx_spi_update(drv_data, SSCR0, GENMASK(31, 0), cr0);

	/* Restart the SSP */
	pxa_ssp_enable(drv_data->ssp);

	if (is_mmp2_ssp(drv_data)) {
		u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR)
					& SSSR_TFL_MASK) >> 8;
		u8 tx_level = read_SSSR_bits(drv_data, SSSR_TFL_MASK) >> 8;

		if (tx_level) {
			/* On MMP2, flipping SSE doesn't to empty TXFIFO. */
@@ -1151,18 +1156,7 @@ static int pxa2xx_spi_slave_abort(struct spi_controller *controller)
{
	struct driver_data *drv_data = spi_controller_get_devdata(controller);

	/* Stop and reset SSP */
	write_SSSR_CS(drv_data, drv_data->clear_sr);
	reset_sccr1(drv_data);
	if (!pxa25x_ssp_comp(drv_data))
		pxa2xx_spi_write(drv_data, SSTO, 0);
	pxa2xx_spi_flush(drv_data);
	pxa2xx_spi_off(drv_data);

	dev_dbg(drv_data->ssp->dev, "transfer aborted\n");

	drv_data->controller->cur_msg->status = -EINTR;
	spi_finalize_current_transfer(drv_data->controller);
	int_error_stop(drv_data, "transfer aborted", -EINTR);

	return 0;
}
@@ -1176,9 +1170,7 @@ static void pxa2xx_spi_handle_err(struct spi_controller *controller,
	pxa2xx_spi_off(drv_data);
	/* Clear and disable interrupts and service requests */
	write_SSSR_CS(drv_data, drv_data->clear_sr);
	pxa2xx_spi_write(drv_data, SSCR1,
			 pxa2xx_spi_read(drv_data, SSCR1)
			 & ~(drv_data->int_cr1 | drv_data->dma_cr1));
	clear_SSCR1_bits(drv_data, drv_data->int_cr1 | drv_data->dma_cr1);
	if (!pxa25x_ssp_comp(drv_data))
		pxa2xx_spi_write(drv_data, SSTO, 0);

@@ -1275,6 +1267,11 @@ static int setup(struct spi_device *spi)
		tx_hi_thres = 0;
		rx_thres = RX_THRESH_QUARK_X1000_DFLT;
		break;
	case MRFLD_SSP:
		tx_thres = TX_THRESH_MRFLD_DFLT;
		tx_hi_thres = 0;
		rx_thres = RX_THRESH_MRFLD_DFLT;
		break;
	case CE4100_SSP:
		tx_thres = TX_THRESH_CE4100_DFLT;
		tx_hi_thres = 0;
@@ -1350,9 +1347,16 @@ static int setup(struct spi_device *spi)
		chip->cr1 |= SSCR1_SPH;
	}

	if (is_lpss_ssp(drv_data)) {
		chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
	chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
				| SSITF_TxHiThresh(tx_hi_thres);
		chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres) |
					  SSITF_TxHiThresh(tx_hi_thres);
	}

	if (is_mrfld_ssp(drv_data)) {
		chip->lpss_rx_threshold = rx_thres;
		chip->lpss_tx_threshold = tx_thres;
	}

	/* set dma burst and threshold outside of chip_info path so that if
	 * chip_info goes away after setting chip->enable_dma, the
@@ -1794,8 +1798,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
		controller->min_speed_hz =
			DIV_ROUND_UP(controller->max_speed_hz, 512);

	pxa_ssp_disable(ssp);

	/* Load default SSP configuration */
	pxa2xx_spi_write(drv_data, SSCR0, 0);
	switch (drv_data->ssp_type) {
	case QUARK_X1000_SSP:
		tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) |
@@ -1936,7 +1941,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
	spi_unregister_controller(drv_data->controller);

	/* Disable the SSP at the peripheral and SOC level */
	pxa2xx_spi_write(drv_data, SSCR0, 0);
	pxa_ssp_disable(ssp);
	clk_disable_unprepare(ssp->clk);

	/* Release DMA */
@@ -1965,7 +1970,8 @@ static int pxa2xx_spi_suspend(struct device *dev)
	status = spi_controller_suspend(drv_data->controller);
	if (status != 0)
		return status;
	pxa2xx_spi_write(drv_data, SSCR0, 0);

	pxa_ssp_disable(ssp);

	if (!pm_runtime_suspended(dev))
		clk_disable_unprepare(ssp->clk);
+13 −3
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ static inline void pxa2xx_spi_write(const struct driver_data *drv_data, u32 reg,

#define DMA_ALIGNMENT		8

static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
static inline int pxa25x_ssp_comp(const struct driver_data *drv_data)
{
	switch (drv_data->ssp_type) {
	case PXA25x_SSP:
@@ -105,11 +105,21 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
	}
}

static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
static inline void clear_SSCR1_bits(const struct driver_data *drv_data, u32 bits)
{
	pxa2xx_spi_write(drv_data, SSCR1, pxa2xx_spi_read(drv_data, SSCR1) & ~bits);
}

static inline u32 read_SSSR_bits(const struct driver_data *drv_data, u32 bits)
{
	return pxa2xx_spi_read(drv_data, SSSR) & bits;
}

static inline void write_SSSR_CS(const struct driver_data *drv_data, u32 val)
{
	if (drv_data->ssp_type == CE4100_SSP ||
	    drv_data->ssp_type == QUARK_X1000_SSP)
		val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK;
		val |= read_SSSR_bits(drv_data, SSSR_ALT_FRM_MASK);

	pxa2xx_spi_write(drv_data, SSSR, val);
}
+32 −0
Original line number Diff line number Diff line
@@ -183,6 +183,21 @@ struct device_node;
#define SSACD_ACPS(x)		((x) << 4)	/* Audio clock PLL select */
#define SSACD_SCDX8		BIT(7)		/* SYSCLK division ratio select */

/* Intel Merrifield SSP */
#define SFIFOL			0x68		/* FIFO level */
#define SFIFOTT			0x6c		/* FIFO trigger threshold */

#define RX_THRESH_MRFLD_DFLT	16
#define TX_THRESH_MRFLD_DFLT	16

#define SFIFOL_TFL_MASK		GENMASK(15, 0)	/* Transmit FIFO Level mask */
#define SFIFOL_RFL_MASK		GENMASK(31, 16)	/* Receive FIFO Level mask */

#define SFIFOTT_TFT		GENMASK(15, 0)	/* Transmit FIFO Threshold (mask) */
#define SFIFOTT_TxThresh(x)	(((x) - 1) << 0)	/* TX FIFO trigger threshold / level */
#define SFIFOTT_RFT		GENMASK(31, 16)	/* Receive FIFO Threshold (mask) */
#define SFIFOTT_RxThresh(x)	(((x) - 1) << 16)	/* RX FIFO trigger threshold / level */

/* LPSS SSP */
#define SSITF			0x44		/* TX FIFO trigger level */
#define SSITF_TxHiThresh(x)	(((x) - 1) << 0)
@@ -205,6 +220,7 @@ enum pxa_ssp_type {
	MMP2_SSP,
	PXA910_SSP,
	CE4100_SSP,
	MRFLD_SSP,
	QUARK_X1000_SSP,
	LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */
	LPSS_BYT_SSP,
@@ -254,6 +270,22 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
	return __raw_readl(dev->mmio_base + reg);
}

static inline void pxa_ssp_enable(struct ssp_device *ssp)
{
	u32 sscr0;

	sscr0 = pxa_ssp_read_reg(ssp, SSCR0) | SSCR0_SSE;
	pxa_ssp_write_reg(ssp, SSCR0, sscr0);
}

static inline void pxa_ssp_disable(struct ssp_device *ssp)
{
	u32 sscr0;

	sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~SSCR0_SSE;
	pxa_ssp_write_reg(ssp, SSCR0, sscr0);
}

#if IS_ENABLED(CONFIG_PXA_SSP)
struct ssp_device *pxa_ssp_request(int port, const char *label);
void pxa_ssp_free(struct ssp_device *);
Loading