diff options
Diffstat (limited to 'drivers/spi')
36 files changed, 3695 insertions, 327 deletions
| diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 671d078349cc..f756450a8914 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -129,7 +129,7 @@ config SPI_BCM63XX  config SPI_BCM63XX_HSSPI  	tristate "Broadcom BCM63XX HS SPI controller driver" -	depends on BCM63XX || COMPILE_TEST +	depends on BCM63XX || ARCH_BCM_63XX || COMPILE_TEST  	help  	  This enables support for the High Speed SPI controller present on  	  newer Broadcom BCM63XX SoCs. @@ -520,6 +520,12 @@ config SPI_RSPI  	help  	  SPI driver for Renesas RSPI and QSPI blocks. +config SPI_QCOM_QSPI +	tristate "QTI QSPI controller" +	depends on ARCH_QCOM +	help +	  QSPI(Quad SPI) driver for Qualcomm QSPI controller. +  config SPI_QUP  	tristate "Qualcomm SPI controller with QUP interface"  	depends on ARCH_QCOM || (ARM && COMPILE_TEST) @@ -533,6 +539,18 @@ config SPI_QUP  	  This driver can also be built as a module.  If so, the module  	  will be called spi_qup. +config SPI_QCOM_GENI +	tristate "Qualcomm GENI based SPI controller" +	depends on QCOM_GENI_SE +	help +	  This driver supports GENI serial engine based SPI controller in +	  master mode on the Qualcomm Technologies Inc.'s SoCs. If you say +	  yes to this option, support will be included for the built-in SPI +	  interface on the Qualcomm Technologies Inc.'s SoCs. + +	  This driver can also be built as a module.  If so, the module +	  will be called spi-geni-qcom. +  config SPI_S3C24XX  	tristate "Samsung S3C24XX series SPI"  	depends on ARCH_S3C24XX @@ -596,6 +614,22 @@ config SPI_SIRF  	help  	  SPI driver for CSR SiRFprimaII SoCs +config SPI_SLAVE_MT27XX +	tristate "MediaTek SPI slave device" +	depends on ARCH_MEDIATEK || COMPILE_TEST +	depends on SPI_SLAVE +	help +	  This selects the MediaTek(R) SPI slave device driver. +	  If you want to use MediaTek(R) SPI slave interface, +	  say Y or M here.If you are not sure, say N. +	  SPI slave drivers for Mediatek MT27XX series ARM SoCs. + +config SPI_SPRD +	tristate "Spreadtrum SPI controller" +	depends on ARCH_SPRD || COMPILE_TEST +	help +	  SPI driver for Spreadtrum SoCs. +  config SPI_SPRD_ADI  	tristate "Spreadtrum ADI controller"  	depends on ARCH_SPRD || COMPILE_TEST @@ -613,6 +647,15 @@ config SPI_STM32  	  is not available, the driver automatically falls back to  	  PIO mode. +config SPI_STM32_QSPI +	tristate "STMicroelectronics STM32 QUAD SPI controller" +	depends on ARCH_STM32 || COMPILE_TEST +	depends on OF +	help +	  This enables support for the Quad SPI controller in master mode. +	  This driver does not support generic SPI. The implementation only +	  supports spi-mem interface. +  config SPI_ST_SSC4  	tristate "STMicroelectronics SPI SSC-based driver"  	depends on ARCH_STI || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a90d55970036..df04dfbe7d70 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -74,6 +74,8 @@ obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o  spi-pxa2xx-platform-objs		:= spi-pxa2xx.o spi-pxa2xx-dma.o  obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o  obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o +obj-$(CONFIG_SPI_QCOM_GENI)		+= spi-geni-qcom.o +obj-$(CONFIG_SPI_QCOM_QSPI)		+= spi-qcom-qspi.o  obj-$(CONFIG_SPI_QUP)			+= spi-qup.o  obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o  obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o @@ -88,8 +90,11 @@ obj-$(CONFIG_SPI_SH_HSPI)		+= spi-sh-hspi.o  obj-$(CONFIG_SPI_SH_MSIOF)		+= spi-sh-msiof.o  obj-$(CONFIG_SPI_SH_SCI)		+= spi-sh-sci.o  obj-$(CONFIG_SPI_SIRF)		+= spi-sirf.o +obj-$(CONFIG_SPI_SLAVE_MT27XX)          += spi-slave-mt27xx.o +obj-$(CONFIG_SPI_SPRD)			+= spi-sprd.o  obj-$(CONFIG_SPI_SPRD_ADI)		+= spi-sprd-adi.o  obj-$(CONFIG_SPI_STM32) 		+= spi-stm32.o +obj-$(CONFIG_SPI_STM32_QSPI) 		+= spi-stm32-qspi.o  obj-$(CONFIG_SPI_ST_SSC4)		+= spi-st-ssc4.o  obj-$(CONFIG_SPI_SUN4I)			+= spi-sun4i.o  obj-$(CONFIG_SPI_SUN6I)			+= spi-sun6i.o diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 3f890d162934..74fddcd3282b 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1767,10 +1767,8 @@ static int atmel_spi_suspend(struct device *dev)  	/* Stop the queue running */  	ret = spi_master_suspend(master); -	if (ret) { -		dev_warn(dev, "cannot suspend master\n"); +	if (ret)  		return ret; -	}  	if (!pm_runtime_suspended(dev))  		atmel_spi_runtime_suspend(dev); @@ -1799,11 +1797,7 @@ static int atmel_spi_resume(struct device *dev)  	}  	/* Start the queue running */ -	ret = spi_master_resume(master); -	if (ret) -		dev_err(dev, "problem starting queue (%d)\n", ret); - -	return ret; +	return spi_master_resume(master);  }  #endif diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 8612525fa4e3..584bcb018a62 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -89,7 +89,7 @@  #define BSPI_BPP_MODE_SELECT_MASK		BIT(8)  #define BSPI_BPP_ADDR_SELECT_MASK		BIT(16) -#define BSPI_READ_LENGTH			512 +#define BSPI_READ_LENGTH			256  /* MSPI register offsets */  #define MSPI_SPCR0_LSB				0x000 @@ -355,7 +355,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,  	int bpc = 0, bpp = 0;  	u8 command = op->cmd.opcode;  	int width  = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE; -	int addrlen = op->addr.nbytes * 8; +	int addrlen = op->addr.nbytes;  	int flex_mode = 1;  	dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n", diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index c23849f7aa7b..9a06ffdb73b8 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -101,6 +101,7 @@ struct bcm63xx_hsspi {  	struct platform_device *pdev;  	struct clk *clk; +	struct clk *pll_clk;  	void __iomem *regs;  	u8 __iomem *fifo; @@ -332,7 +333,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)  	struct resource *res_mem;  	void __iomem *regs;  	struct device *dev = &pdev->dev; -	struct clk *clk; +	struct clk *clk, *pll_clk = NULL;  	int irq, ret;  	u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS; @@ -358,7 +359,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)  	rate = clk_get_rate(clk);  	if (!rate) { -		struct clk *pll_clk = devm_clk_get(dev, "pll"); +		pll_clk = devm_clk_get(dev, "pll");  		if (IS_ERR(pll_clk)) {  			ret = PTR_ERR(pll_clk); @@ -373,19 +374,20 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)  		clk_disable_unprepare(pll_clk);  		if (!rate) {  			ret = -EINVAL; -			goto out_disable_clk; +			goto out_disable_pll_clk;  		}  	}  	master = spi_alloc_master(&pdev->dev, sizeof(*bs));  	if (!master) {  		ret = -ENOMEM; -		goto out_disable_clk; +		goto out_disable_pll_clk;  	}  	bs = spi_master_get_devdata(master);  	bs->pdev = pdev;  	bs->clk = clk; +	bs->pll_clk = pll_clk;  	bs->regs = regs;  	bs->speed_hz = rate;  	bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0)); @@ -440,6 +442,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)  out_put_master:  	spi_master_put(master); +out_disable_pll_clk: +	clk_disable_unprepare(pll_clk);  out_disable_clk:  	clk_disable_unprepare(clk);  	return ret; @@ -453,6 +457,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev)  	/* reset the hardware and block queue progress */  	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG); +	clk_disable_unprepare(bs->pll_clk);  	clk_disable_unprepare(bs->clk);  	return 0; @@ -465,6 +470,7 @@ static int bcm63xx_hsspi_suspend(struct device *dev)  	struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);  	spi_master_suspend(master); +	clk_disable_unprepare(bs->pll_clk);  	clk_disable_unprepare(bs->clk);  	return 0; @@ -480,6 +486,12 @@ static int bcm63xx_hsspi_resume(struct device *dev)  	if (ret)  		return ret; +	if (bs->pll_clk) { +		ret = clk_prepare_enable(bs->pll_clk); +		if (ret) +			return ret; +	} +  	spi_master_resume(master);  	return 0; diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index a02099c90c5c..56adec83f8fc 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -208,13 +208,11 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits)  static void davinci_spi_chipselect(struct spi_device *spi, int value)  {  	struct davinci_spi *dspi; -	struct davinci_spi_platform_data *pdata;  	struct davinci_spi_config *spicfg = spi->controller_data;  	u8 chip_sel = spi->chip_select;  	u16 spidat1 = CS_DEFAULT;  	dspi = spi_master_get_devdata(spi->master); -	pdata = &dspi->pdata;  	/* program delay transfers if tx_delay is non zero */  	if (spicfg && spicfg->wdelay) @@ -232,7 +230,8 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)  				!(spi->mode & SPI_CS_HIGH));  	} else {  		if (value == BITBANG_CS_ACTIVE) { -			spidat1 |= SPIDAT1_CSHOLD_MASK; +			if (!(spi->mode & SPI_CS_WORD)) +				spidat1 |= SPIDAT1_CSHOLD_MASK;  			spidat1 &= ~(0x1 << chip_sel);  		}  	} @@ -421,26 +420,17 @@ static int davinci_spi_setup(struct spi_device *spi)  {  	int retval = 0;  	struct davinci_spi *dspi; -	struct davinci_spi_platform_data *pdata;  	struct spi_master *master = spi->master;  	struct device_node *np = spi->dev.of_node;  	bool internal_cs = true;  	dspi = spi_master_get_devdata(spi->master); -	pdata = &dspi->pdata;  	if (!(spi->mode & SPI_NO_CS)) {  		if (np && (master->cs_gpios != NULL) && (spi->cs_gpio >= 0)) {  			retval = gpio_direction_output(  				      spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));  			internal_cs = false; -		} else if (pdata->chip_sel && -			   spi->chip_select < pdata->num_chipselect && -			   pdata->chip_sel[spi->chip_select] != SPI_INTERN_CS) { -			spi->cs_gpio = pdata->chip_sel[spi->chip_select]; -			retval = gpio_direction_output( -				      spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); -			internal_cs = false;  		}  		if (retval) { @@ -449,8 +439,9 @@ static int davinci_spi_setup(struct spi_device *spi)  			return retval;  		} -		if (internal_cs) +		if (internal_cs) {  			set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); +		}  	}  	if (spi->mode & SPI_READY) @@ -985,7 +976,7 @@ static int davinci_spi_probe(struct platform_device *pdev)  	dspi->prescaler_limit = pdata->prescaler_limit;  	dspi->version = pdata->version; -	dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; +	dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_WORD;  	if (dspi->version == SPI_VERSION_2)  		dspi->bitbang.flags |= SPI_READY; diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index e80f60ed6fdf..3ffb6a40fe0c 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -34,8 +34,9 @@ struct dw_spi_mmio {  };  #define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL	0x24 -#define OCELOT_IF_SI_OWNER_MASK			GENMASK(5, 4)  #define OCELOT_IF_SI_OWNER_OFFSET		4 +#define JAGUAR2_IF_SI_OWNER_OFFSET		6 +#define MSCC_IF_SI_OWNER_MASK			GENMASK(1, 0)  #define MSCC_IF_SI_OWNER_SISL			0  #define MSCC_IF_SI_OWNER_SIBM			1  #define MSCC_IF_SI_OWNER_SIMC			2 @@ -76,7 +77,8 @@ static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)  }  static int dw_spi_mscc_init(struct platform_device *pdev, -			    struct dw_spi_mmio *dwsmmio) +			    struct dw_spi_mmio *dwsmmio, +			    const char *cpu_syscon, u32 if_si_owner_offset)  {  	struct dw_spi_mscc *dwsmscc;  	struct resource *res; @@ -92,7 +94,7 @@ static int dw_spi_mscc_init(struct platform_device *pdev,  		return PTR_ERR(dwsmscc->spi_mst);  	} -	dwsmscc->syscon = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon"); +	dwsmscc->syscon = syscon_regmap_lookup_by_compatible(cpu_syscon);  	if (IS_ERR(dwsmscc->syscon))  		return PTR_ERR(dwsmscc->syscon); @@ -101,8 +103,8 @@ static int dw_spi_mscc_init(struct platform_device *pdev,  	/* Select the owner of the SI interface */  	regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL, -			   OCELOT_IF_SI_OWNER_MASK, -			   MSCC_IF_SI_OWNER_SIMC << OCELOT_IF_SI_OWNER_OFFSET); +			   MSCC_IF_SI_OWNER_MASK << if_si_owner_offset, +			   MSCC_IF_SI_OWNER_SIMC << if_si_owner_offset);  	dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;  	dwsmmio->priv = dwsmscc; @@ -110,6 +112,28 @@ static int dw_spi_mscc_init(struct platform_device *pdev,  	return 0;  } +static int dw_spi_mscc_ocelot_init(struct platform_device *pdev, +				   struct dw_spi_mmio *dwsmmio) +{ +	return dw_spi_mscc_init(pdev, dwsmmio, "mscc,ocelot-cpu-syscon", +				OCELOT_IF_SI_OWNER_OFFSET); +} + +static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev, +				    struct dw_spi_mmio *dwsmmio) +{ +	return dw_spi_mscc_init(pdev, dwsmmio, "mscc,jaguar2-cpu-syscon", +				JAGUAR2_IF_SI_OWNER_OFFSET); +} + +static int dw_spi_alpine_init(struct platform_device *pdev, +			      struct dw_spi_mmio *dwsmmio) +{ +	dwsmmio->dws.cs_override = 1; + +	return 0; +} +  static int dw_spi_mmio_probe(struct platform_device *pdev)  {  	int (*init_func)(struct platform_device *pdev, @@ -212,7 +236,9 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)  static const struct of_device_id dw_spi_mmio_of_match[] = {  	{ .compatible = "snps,dw-apb-ssi", }, -	{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_init}, +	{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init}, +	{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init}, +	{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},  	{ /* end of table */}  };  MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index ac2eb89ef7a5..b705f2bdb8b9 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -144,6 +144,8 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)  	if (!enable)  		dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select)); +	else if (dws->cs_override) +		dw_writel(dws, DW_SPI_SER, 0);  }  EXPORT_SYMBOL_GPL(dw_spi_set_cs); @@ -308,15 +310,10 @@ static int dw_spi_transfer_one(struct spi_controller *master,  		dws->current_freq = transfer->speed_hz;  		spi_set_clk(dws, chip->clk_div);  	} -	if (transfer->bits_per_word == 8) { -		dws->n_bytes = 1; -		dws->dma_width = 1; -	} else if (transfer->bits_per_word == 16) { -		dws->n_bytes = 2; -		dws->dma_width = 2; -	} else { -		return -EINVAL; -	} + +	dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); +	dws->dma_width = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); +  	/* Default SPI mode is SCPOL = 0, SCPH = 0 */  	cr0 = (transfer->bits_per_word - 1)  		| (chip->type << SPI_FRF_OFFSET) @@ -468,6 +465,10 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)  		dws->fifo_len = (fifo == 1) ? 0 : fifo;  		dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);  	} + +	/* enable HW fixup for explicit CS deselect for Amazon's alpine chip */ +	if (dws->cs_override) +		dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);  }  int dw_spi_add_host(struct device *dev, struct dw_spi *dws) @@ -496,7 +497,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)  	}  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; -	master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); +	master->bits_per_word_mask =  SPI_BPW_RANGE_MASK(4, 16);  	master->bus_num = dws->bus_num;  	master->num_chipselect = dws->num_cs;  	master->setup = dw_spi_setup; @@ -572,13 +573,8 @@ EXPORT_SYMBOL_GPL(dw_spi_suspend_host);  int dw_spi_resume_host(struct dw_spi *dws)  { -	int ret; -  	spi_hw_init(&dws->master->dev, dws); -	ret = spi_controller_resume(dws->master); -	if (ret) -		dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); -	return ret; +	return spi_controller_resume(dws->master);  }  EXPORT_SYMBOL_GPL(dw_spi_resume_host); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 0168b08364d5..c9c15881e982 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -32,6 +32,7 @@  #define DW_SPI_IDR			0x58  #define DW_SPI_VERSION			0x5c  #define DW_SPI_DR			0x60 +#define DW_SPI_CS_OVERRIDE		0xf4  /* Bit fields in CTRLR0 */  #define SPI_DFS_OFFSET			0 @@ -109,6 +110,7 @@ struct dw_spi {  	u32			fifo_len;	/* depth of the FIFO buffer */  	u32			max_freq;	/* max bus freq supported */ +	int			cs_override;  	u32			reg_io_width;	/* DR I/O width in bytes */  	u16			bus_num;  	u16			num_cs;		/* supported slave numbers */ diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index f1526757aaf6..79fc3940245a 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -246,6 +246,19 @@ static int ep93xx_spi_read_write(struct spi_master *master)  	return -EINPROGRESS;  } +static enum dma_transfer_direction +ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir) +{ +	switch (dir) { +	case DMA_TO_DEVICE: +		return DMA_MEM_TO_DEV; +	case DMA_FROM_DEVICE: +		return DMA_DEV_TO_MEM; +	default: +		return DMA_TRANS_NONE; +	} +} +  /**   * ep93xx_spi_dma_prepare() - prepares a DMA transfer   * @master: SPI master @@ -257,7 +270,7 @@ static int ep93xx_spi_read_write(struct spi_master *master)   */  static struct dma_async_tx_descriptor *  ep93xx_spi_dma_prepare(struct spi_master *master, -		       enum dma_transfer_direction dir) +		       enum dma_data_direction dir)  {  	struct ep93xx_spi *espi = spi_master_get_devdata(master);  	struct spi_transfer *xfer = master->cur_msg->state; @@ -277,9 +290,9 @@ ep93xx_spi_dma_prepare(struct spi_master *master,  		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;  	memset(&conf, 0, sizeof(conf)); -	conf.direction = dir; +	conf.direction = ep93xx_dma_data_to_trans_dir(dir); -	if (dir == DMA_DEV_TO_MEM) { +	if (dir == DMA_FROM_DEVICE) {  		chan = espi->dma_rx;  		buf = xfer->rx_buf;  		sgt = &espi->rx_sgt; @@ -343,7 +356,8 @@ ep93xx_spi_dma_prepare(struct spi_master *master,  	if (!nents)  		return ERR_PTR(-ENOMEM); -	txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir, DMA_CTRL_ACK); +	txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, conf.direction, +				      DMA_CTRL_ACK);  	if (!txd) {  		dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);  		return ERR_PTR(-ENOMEM); @@ -360,13 +374,13 @@ ep93xx_spi_dma_prepare(struct spi_master *master,   * unmapped.   */  static void ep93xx_spi_dma_finish(struct spi_master *master, -				  enum dma_transfer_direction dir) +				  enum dma_data_direction dir)  {  	struct ep93xx_spi *espi = spi_master_get_devdata(master);  	struct dma_chan *chan;  	struct sg_table *sgt; -	if (dir == DMA_DEV_TO_MEM) { +	if (dir == DMA_FROM_DEVICE) {  		chan = espi->dma_rx;  		sgt = &espi->rx_sgt;  	} else { @@ -381,8 +395,8 @@ static void ep93xx_spi_dma_callback(void *callback_param)  {  	struct spi_master *master = callback_param; -	ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV); -	ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); +	ep93xx_spi_dma_finish(master, DMA_TO_DEVICE); +	ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);  	spi_finalize_current_transfer(master);  } @@ -392,15 +406,15 @@ static int ep93xx_spi_dma_transfer(struct spi_master *master)  	struct ep93xx_spi *espi = spi_master_get_devdata(master);  	struct dma_async_tx_descriptor *rxd, *txd; -	rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM); +	rxd = ep93xx_spi_dma_prepare(master, DMA_FROM_DEVICE);  	if (IS_ERR(rxd)) {  		dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));  		return PTR_ERR(rxd);  	} -	txd = ep93xx_spi_dma_prepare(master, DMA_MEM_TO_DEV); +	txd = ep93xx_spi_dma_prepare(master, DMA_TO_DEVICE);  	if (IS_ERR(txd)) { -		ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM); +		ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);  		dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));  		return PTR_ERR(txd);  	} diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 1e8ff6256079..cf2118dc91f4 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -798,10 +798,8 @@ static int of_fsl_espi_suspend(struct device *dev)  	int ret;  	ret = spi_master_suspend(master); -	if (ret) { -		dev_warn(dev, "cannot suspend master\n"); +	if (ret)  		return ret; -	}  	return pm_runtime_force_suspend(dev);  } diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index e6d5cc6ab108..51670976faa3 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -276,7 +276,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)  	fsl_lpspi_set_watermark(fsl_lpspi); -	temp = CFGR1_PCSCFG | CFGR1_MASTER | CFGR1_NOSTALL; +	temp = CFGR1_PCSCFG | CFGR1_MASTER;  	if (fsl_lpspi->config.mode & SPI_CS_HIGH)  		temp |= CFGR1_PCSPOL;  	writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1); diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c new file mode 100644 index 000000000000..6432ecc4e2ca --- /dev/null +++ b/drivers/spi/spi-geni-qcom.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/log2.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/qcom-geni-se.h> +#include <linux/spi/spi.h> +#include <linux/spinlock.h> + +/* SPI SE specific registers and respective register fields */ +#define SE_SPI_CPHA		0x224 +#define CPHA			BIT(0) + +#define SE_SPI_LOOPBACK		0x22c +#define LOOPBACK_ENABLE		0x1 +#define NORMAL_MODE		0x0 +#define LOOPBACK_MSK		GENMASK(1, 0) + +#define SE_SPI_CPOL		0x230 +#define CPOL			BIT(2) + +#define SE_SPI_DEMUX_OUTPUT_INV	0x24c +#define CS_DEMUX_OUTPUT_INV_MSK	GENMASK(3, 0) + +#define SE_SPI_DEMUX_SEL	0x250 +#define CS_DEMUX_OUTPUT_SEL	GENMASK(3, 0) + +#define SE_SPI_TRANS_CFG	0x25c +#define CS_TOGGLE		BIT(0) + +#define SE_SPI_WORD_LEN		0x268 +#define WORD_LEN_MSK		GENMASK(9, 0) +#define MIN_WORD_LEN		4 + +#define SE_SPI_TX_TRANS_LEN	0x26c +#define SE_SPI_RX_TRANS_LEN	0x270 +#define TRANS_LEN_MSK		GENMASK(23, 0) + +#define SE_SPI_PRE_POST_CMD_DLY	0x274 + +#define SE_SPI_DELAY_COUNTERS	0x278 +#define SPI_INTER_WORDS_DELAY_MSK	GENMASK(9, 0) +#define SPI_CS_CLK_DELAY_MSK		GENMASK(19, 10) +#define SPI_CS_CLK_DELAY_SHFT		10 + +/* M_CMD OP codes for SPI */ +#define SPI_TX_ONLY		1 +#define SPI_RX_ONLY		2 +#define SPI_FULL_DUPLEX		3 +#define SPI_TX_RX		7 +#define SPI_CS_ASSERT		8 +#define SPI_CS_DEASSERT		9 +#define SPI_SCK_ONLY		10 +/* M_CMD params for SPI */ +#define SPI_PRE_CMD_DELAY	BIT(0) +#define TIMESTAMP_BEFORE	BIT(1) +#define FRAGMENTATION		BIT(2) +#define TIMESTAMP_AFTER		BIT(3) +#define POST_CMD_DELAY		BIT(4) + +/* SPI M_COMMAND OPCODE */ +enum spi_mcmd_code { +	CMD_NONE, +	CMD_XFER, +	CMD_CS, +	CMD_CANCEL, +}; + + +struct spi_geni_master { +	struct geni_se se; +	struct device *dev; +	u32 tx_fifo_depth; +	u32 fifo_width_bits; +	u32 tx_wm; +	unsigned long cur_speed_hz; +	unsigned int cur_bits_per_word; +	unsigned int tx_rem_bytes; +	unsigned int rx_rem_bytes; +	const struct spi_transfer *cur_xfer; +	struct completion xfer_done; +	unsigned int oversampling; +	spinlock_t lock; +	unsigned int cur_mcmd; +	int irq; +}; + +static void handle_fifo_timeout(struct spi_master *spi, +				struct spi_message *msg); + +static int get_spi_clk_cfg(unsigned int speed_hz, +			struct spi_geni_master *mas, +			unsigned int *clk_idx, +			unsigned int *clk_div) +{ +	unsigned long sclk_freq; +	unsigned int actual_hz; +	struct geni_se *se = &mas->se; +	int ret; + +	ret = geni_se_clk_freq_match(&mas->se, +				speed_hz * mas->oversampling, +				clk_idx, &sclk_freq, false); +	if (ret) { +		dev_err(mas->dev, "Failed(%d) to find src clk for %dHz\n", +							ret, speed_hz); +		return ret; +	} + +	*clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz); +	actual_hz = sclk_freq / (mas->oversampling * *clk_div); + +	dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz, +				actual_hz, sclk_freq, *clk_idx, *clk_div); +	ret = clk_set_rate(se->clk, sclk_freq); +	if (ret) +		dev_err(mas->dev, "clk_set_rate failed %d\n", ret); +	return ret; +} + +static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) +{ +	struct spi_geni_master *mas = spi_master_get_devdata(slv->master); +	struct spi_master *spi = dev_get_drvdata(mas->dev); +	struct geni_se *se = &mas->se; +	unsigned long timeout; + +	reinit_completion(&mas->xfer_done); +	pm_runtime_get_sync(mas->dev); +	if (!(slv->mode & SPI_CS_HIGH)) +		set_flag = !set_flag; + +	mas->cur_mcmd = CMD_CS; +	if (set_flag) +		geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); +	else +		geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); + +	timeout = wait_for_completion_timeout(&mas->xfer_done, HZ); +	if (!timeout) +		handle_fifo_timeout(spi, NULL); + +	pm_runtime_put(mas->dev); +} + +static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, +					unsigned int bits_per_word) +{ +	unsigned int pack_words; +	bool msb_first = (mode & SPI_LSB_FIRST) ? false : true; +	struct geni_se *se = &mas->se; +	u32 word_len; + +	word_len = readl(se->base + SE_SPI_WORD_LEN); + +	/* +	 * If bits_per_word isn't a byte aligned value, set the packing to be +	 * 1 SPI word per FIFO word. +	 */ +	if (!(mas->fifo_width_bits % bits_per_word)) +		pack_words = mas->fifo_width_bits / bits_per_word; +	else +		pack_words = 1; +	word_len &= ~WORD_LEN_MSK; +	word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK); +	geni_se_config_packing(&mas->se, bits_per_word, pack_words, msb_first, +								true, true); +	writel(word_len, se->base + SE_SPI_WORD_LEN); +} + +static int setup_fifo_params(struct spi_device *spi_slv, +					struct spi_master *spi) +{ +	struct spi_geni_master *mas = spi_master_get_devdata(spi); +	struct geni_se *se = &mas->se; +	u32 loopback_cfg, cpol, cpha, demux_output_inv; +	u32 demux_sel, clk_sel, m_clk_cfg, idx, div; +	int ret; + +	loopback_cfg = readl(se->base + SE_SPI_LOOPBACK); +	cpol = readl(se->base + SE_SPI_CPOL); +	cpha = readl(se->base + SE_SPI_CPHA); +	demux_output_inv = 0; +	loopback_cfg &= ~LOOPBACK_MSK; +	cpol &= ~CPOL; +	cpha &= ~CPHA; + +	if (spi_slv->mode & SPI_LOOP) +		loopback_cfg |= LOOPBACK_ENABLE; + +	if (spi_slv->mode & SPI_CPOL) +		cpol |= CPOL; + +	if (spi_slv->mode & SPI_CPHA) +		cpha |= CPHA; + +	if (spi_slv->mode & SPI_CS_HIGH) +		demux_output_inv = BIT(spi_slv->chip_select); + +	demux_sel = spi_slv->chip_select; +	mas->cur_speed_hz = spi_slv->max_speed_hz; +	mas->cur_bits_per_word = spi_slv->bits_per_word; + +	ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div); +	if (ret) { +		dev_err(mas->dev, "Err setting clks ret(%d) for %ld\n", +							ret, mas->cur_speed_hz); +		return ret; +	} + +	clk_sel = idx & CLK_SEL_MSK; +	m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; +	spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word); +	writel(loopback_cfg, se->base + SE_SPI_LOOPBACK); +	writel(demux_sel, se->base + SE_SPI_DEMUX_SEL); +	writel(cpha, se->base + SE_SPI_CPHA); +	writel(cpol, se->base + SE_SPI_CPOL); +	writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV); +	writel(clk_sel, se->base + SE_GENI_CLK_SEL); +	writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); +	return 0; +} + +static int spi_geni_prepare_message(struct spi_master *spi, +					struct spi_message *spi_msg) +{ +	int ret; +	struct spi_geni_master *mas = spi_master_get_devdata(spi); +	struct geni_se *se = &mas->se; + +	geni_se_select_mode(se, GENI_SE_FIFO); +	reinit_completion(&mas->xfer_done); +	ret = setup_fifo_params(spi_msg->spi, spi); +	if (ret) +		dev_err(mas->dev, "Couldn't select mode %d\n", ret); +	return ret; +} + +static int spi_geni_init(struct spi_geni_master *mas) +{ +	struct geni_se *se = &mas->se; +	unsigned int proto, major, minor, ver; + +	pm_runtime_get_sync(mas->dev); + +	proto = geni_se_read_proto(se); +	if (proto != GENI_SE_SPI) { +		dev_err(mas->dev, "Invalid proto %d\n", proto); +		pm_runtime_put(mas->dev); +		return -ENXIO; +	} +	mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se); + +	/* Width of Tx and Rx FIFO is same */ +	mas->fifo_width_bits = geni_se_get_tx_fifo_width(se); + +	/* +	 * Hardware programming guide suggests to configure +	 * RX FIFO RFR level to fifo_depth-2. +	 */ +	geni_se_init(se, 0x0, mas->tx_fifo_depth - 2); +	/* Transmit an entire FIFO worth of data per IRQ */ +	mas->tx_wm = 1; +	ver = geni_se_get_qup_hw_version(se); +	major = GENI_SE_VERSION_MAJOR(ver); +	minor = GENI_SE_VERSION_MINOR(ver); + +	if (major == 1 && minor == 0) +		mas->oversampling = 2; +	else +		mas->oversampling = 1; + +	pm_runtime_put(mas->dev); +	return 0; +} + +static void setup_fifo_xfer(struct spi_transfer *xfer, +				struct spi_geni_master *mas, +				u16 mode, struct spi_master *spi) +{ +	u32 m_cmd = 0; +	u32 spi_tx_cfg, len; +	struct geni_se *se = &mas->se; + +	spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); +	if (xfer->bits_per_word != mas->cur_bits_per_word) { +		spi_setup_word_len(mas, mode, xfer->bits_per_word); +		mas->cur_bits_per_word = xfer->bits_per_word; +	} + +	/* Speed and bits per word can be overridden per transfer */ +	if (xfer->speed_hz != mas->cur_speed_hz) { +		int ret; +		u32 clk_sel, m_clk_cfg; +		unsigned int idx, div; + +		ret = get_spi_clk_cfg(xfer->speed_hz, mas, &idx, &div); +		if (ret) { +			dev_err(mas->dev, "Err setting clks:%d\n", ret); +			return; +		} +		/* +		 * SPI core clock gets configured with the requested frequency +		 * or the frequency closer to the requested frequency. +		 * For that reason requested frequency is stored in the +		 * cur_speed_hz and referred in the consecutive transfer instead +		 * of calling clk_get_rate() API. +		 */ +		mas->cur_speed_hz = xfer->speed_hz; +		clk_sel = idx & CLK_SEL_MSK; +		m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; +		writel(clk_sel, se->base + SE_GENI_CLK_SEL); +		writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); +	} + +	mas->tx_rem_bytes = 0; +	mas->rx_rem_bytes = 0; +	if (xfer->tx_buf && xfer->rx_buf) +		m_cmd = SPI_FULL_DUPLEX; +	else if (xfer->tx_buf) +		m_cmd = SPI_TX_ONLY; +	else if (xfer->rx_buf) +		m_cmd = SPI_RX_ONLY; + +	spi_tx_cfg &= ~CS_TOGGLE; + +	if (!(mas->cur_bits_per_word % MIN_WORD_LEN)) +		len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word; +	else +		len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1); +	len &= TRANS_LEN_MSK; + +	mas->cur_xfer = xfer; +	if (m_cmd & SPI_TX_ONLY) { +		mas->tx_rem_bytes = xfer->len; +		writel(len, se->base + SE_SPI_TX_TRANS_LEN); +	} + +	if (m_cmd & SPI_RX_ONLY) { +		writel(len, se->base + SE_SPI_RX_TRANS_LEN); +		mas->rx_rem_bytes = xfer->len; +	} +	writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); +	mas->cur_mcmd = CMD_XFER; +	geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); + +	/* +	 * TX_WATERMARK_REG should be set after SPI configuration and +	 * setting up GENI SE engine, as driver starts data transfer +	 * for the watermark interrupt. +	 */ +	if (m_cmd & SPI_TX_ONLY) +		writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); +} + +static void handle_fifo_timeout(struct spi_master *spi, +				struct spi_message *msg) +{ +	struct spi_geni_master *mas = spi_master_get_devdata(spi); +	unsigned long time_left, flags; +	struct geni_se *se = &mas->se; + +	spin_lock_irqsave(&mas->lock, flags); +	reinit_completion(&mas->xfer_done); +	mas->cur_mcmd = CMD_CANCEL; +	geni_se_cancel_m_cmd(se); +	writel(0, se->base + SE_GENI_TX_WATERMARK_REG); +	spin_unlock_irqrestore(&mas->lock, flags); +	time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); +	if (time_left) +		return; + +	spin_lock_irqsave(&mas->lock, flags); +	reinit_completion(&mas->xfer_done); +	geni_se_abort_m_cmd(se); +	spin_unlock_irqrestore(&mas->lock, flags); +	time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); +	if (!time_left) +		dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); +} + +static int spi_geni_transfer_one(struct spi_master *spi, +				struct spi_device *slv, +				struct spi_transfer *xfer) +{ +	struct spi_geni_master *mas = spi_master_get_devdata(spi); + +	/* Terminate and return success for 0 byte length transfer */ +	if (!xfer->len) +		return 0; + +	setup_fifo_xfer(xfer, mas, slv->mode, spi); +	return 1; +} + +static unsigned int geni_byte_per_fifo_word(struct spi_geni_master *mas) +{ +	/* +	 * Calculate how many bytes we'll put in each FIFO word.  If the +	 * transfer words don't pack cleanly into a FIFO word we'll just put +	 * one transfer word in each FIFO word.  If they do pack we'll pack 'em. +	 */ +	if (mas->fifo_width_bits % mas->cur_bits_per_word) +		return roundup_pow_of_two(DIV_ROUND_UP(mas->cur_bits_per_word, +						       BITS_PER_BYTE)); + +	return mas->fifo_width_bits / BITS_PER_BYTE; +} + +static void geni_spi_handle_tx(struct spi_geni_master *mas) +{ +	struct geni_se *se = &mas->se; +	unsigned int max_bytes; +	const u8 *tx_buf; +	unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); +	unsigned int i = 0; + +	max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word; +	if (mas->tx_rem_bytes < max_bytes) +		max_bytes = mas->tx_rem_bytes; + +	tx_buf = mas->cur_xfer->tx_buf + mas->cur_xfer->len - mas->tx_rem_bytes; +	while (i < max_bytes) { +		unsigned int j; +		unsigned int bytes_to_write; +		u32 fifo_word = 0; +		u8 *fifo_byte = (u8 *)&fifo_word; + +		bytes_to_write = min(bytes_per_fifo_word, max_bytes - i); +		for (j = 0; j < bytes_to_write; j++) +			fifo_byte[j] = tx_buf[i++]; +		iowrite32_rep(se->base + SE_GENI_TX_FIFOn, &fifo_word, 1); +	} +	mas->tx_rem_bytes -= max_bytes; +	if (!mas->tx_rem_bytes) +		writel(0, se->base + SE_GENI_TX_WATERMARK_REG); +} + +static void geni_spi_handle_rx(struct spi_geni_master *mas) +{ +	struct geni_se *se = &mas->se; +	u32 rx_fifo_status; +	unsigned int rx_bytes; +	unsigned int rx_last_byte_valid; +	u8 *rx_buf; +	unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); +	unsigned int i = 0; + +	rx_fifo_status = readl(se->base + SE_GENI_RX_FIFO_STATUS); +	rx_bytes = (rx_fifo_status & RX_FIFO_WC_MSK) * bytes_per_fifo_word; +	if (rx_fifo_status & RX_LAST) { +		rx_last_byte_valid = rx_fifo_status & RX_LAST_BYTE_VALID_MSK; +		rx_last_byte_valid >>= RX_LAST_BYTE_VALID_SHFT; +		if (rx_last_byte_valid && rx_last_byte_valid < 4) +			rx_bytes -= bytes_per_fifo_word - rx_last_byte_valid; +	} +	if (mas->rx_rem_bytes < rx_bytes) +		rx_bytes = mas->rx_rem_bytes; + +	rx_buf = mas->cur_xfer->rx_buf + mas->cur_xfer->len - mas->rx_rem_bytes; +	while (i < rx_bytes) { +		u32 fifo_word = 0; +		u8 *fifo_byte = (u8 *)&fifo_word; +		unsigned int bytes_to_read; +		unsigned int j; + +		bytes_to_read = min(bytes_per_fifo_word, rx_bytes - i); +		ioread32_rep(se->base + SE_GENI_RX_FIFOn, &fifo_word, 1); +		for (j = 0; j < bytes_to_read; j++) +			rx_buf[i++] = fifo_byte[j]; +	} +	mas->rx_rem_bytes -= rx_bytes; +} + +static irqreturn_t geni_spi_isr(int irq, void *data) +{ +	struct spi_master *spi = data; +	struct spi_geni_master *mas = spi_master_get_devdata(spi); +	struct geni_se *se = &mas->se; +	u32 m_irq; +	unsigned long flags; +	irqreturn_t ret = IRQ_HANDLED; + +	if (mas->cur_mcmd == CMD_NONE) +		return IRQ_NONE; + +	spin_lock_irqsave(&mas->lock, flags); +	m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); + +	if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) +		geni_spi_handle_rx(mas); + +	if (m_irq & M_TX_FIFO_WATERMARK_EN) +		geni_spi_handle_tx(mas); + +	if (m_irq & M_CMD_DONE_EN) { +		if (mas->cur_mcmd == CMD_XFER) +			spi_finalize_current_transfer(spi); +		else if (mas->cur_mcmd == CMD_CS) +			complete(&mas->xfer_done); +		mas->cur_mcmd = CMD_NONE; +		/* +		 * If this happens, then a CMD_DONE came before all the Tx +		 * buffer bytes were sent out. This is unusual, log this +		 * condition and disable the WM interrupt to prevent the +		 * system from stalling due an interrupt storm. +		 * If this happens when all Rx bytes haven't been received, log +		 * the condition. +		 * The only known time this can happen is if bits_per_word != 8 +		 * and some registers that expect xfer lengths in num spi_words +		 * weren't written correctly. +		 */ +		if (mas->tx_rem_bytes) { +			writel(0, se->base + SE_GENI_TX_WATERMARK_REG); +			dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", +				mas->tx_rem_bytes, mas->cur_bits_per_word); +		} +		if (mas->rx_rem_bytes) +			dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", +				mas->rx_rem_bytes, mas->cur_bits_per_word); +	} + +	if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) { +		mas->cur_mcmd = CMD_NONE; +		complete(&mas->xfer_done); +	} + +	writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); +	spin_unlock_irqrestore(&mas->lock, flags); +	return ret; +} + +static int spi_geni_probe(struct platform_device *pdev) +{ +	int ret; +	struct spi_master *spi; +	struct spi_geni_master *mas; +	struct resource *res; +	struct geni_se *se; + +	spi = spi_alloc_master(&pdev->dev, sizeof(*mas)); +	if (!spi) +		return -ENOMEM; + +	platform_set_drvdata(pdev, spi); +	mas = spi_master_get_devdata(spi); +	mas->dev = &pdev->dev; +	mas->se.dev = &pdev->dev; +	mas->se.wrapper = dev_get_drvdata(pdev->dev.parent); +	se = &mas->se; + +	spi->bus_num = -1; +	spi->dev.of_node = pdev->dev.of_node; +	mas->se.clk = devm_clk_get(&pdev->dev, "se"); +	if (IS_ERR(mas->se.clk)) { +		ret = PTR_ERR(mas->se.clk); +		dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); +		goto spi_geni_probe_err; +	} + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	se->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(se->base)) { +		ret = PTR_ERR(se->base); +		goto spi_geni_probe_err; +	} + +	spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; +	spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); +	spi->num_chipselect = 4; +	spi->max_speed_hz = 50000000; +	spi->prepare_message = spi_geni_prepare_message; +	spi->transfer_one = spi_geni_transfer_one; +	spi->auto_runtime_pm = true; +	spi->handle_err = handle_fifo_timeout; +	spi->set_cs = spi_geni_set_cs; + +	init_completion(&mas->xfer_done); +	spin_lock_init(&mas->lock); +	pm_runtime_enable(&pdev->dev); + +	ret = spi_geni_init(mas); +	if (ret) +		goto spi_geni_probe_runtime_disable; + +	mas->irq = platform_get_irq(pdev, 0); +	if (mas->irq < 0) { +		ret = mas->irq; +		dev_err(&pdev->dev, "Err getting IRQ %d\n", ret); +		goto spi_geni_probe_runtime_disable; +	} + +	ret = request_irq(mas->irq, geni_spi_isr, +			IRQF_TRIGGER_HIGH, "spi_geni", spi); +	if (ret) +		goto spi_geni_probe_runtime_disable; + +	ret = spi_register_master(spi); +	if (ret) +		goto spi_geni_probe_free_irq; + +	return 0; +spi_geni_probe_free_irq: +	free_irq(mas->irq, spi); +spi_geni_probe_runtime_disable: +	pm_runtime_disable(&pdev->dev); +spi_geni_probe_err: +	spi_master_put(spi); +	return ret; +} + +static int spi_geni_remove(struct platform_device *pdev) +{ +	struct spi_master *spi = platform_get_drvdata(pdev); +	struct spi_geni_master *mas = spi_master_get_devdata(spi); + +	/* Unregister _before_ disabling pm_runtime() so we stop transfers */ +	spi_unregister_master(spi); + +	free_irq(mas->irq, spi); +	pm_runtime_disable(&pdev->dev); +	return 0; +} + +static int __maybe_unused spi_geni_runtime_suspend(struct device *dev) +{ +	struct spi_master *spi = dev_get_drvdata(dev); +	struct spi_geni_master *mas = spi_master_get_devdata(spi); + +	return geni_se_resources_off(&mas->se); +} + +static int __maybe_unused spi_geni_runtime_resume(struct device *dev) +{ +	struct spi_master *spi = dev_get_drvdata(dev); +	struct spi_geni_master *mas = spi_master_get_devdata(spi); + +	return geni_se_resources_on(&mas->se); +} + +static int __maybe_unused spi_geni_suspend(struct device *dev) +{ +	struct spi_master *spi = dev_get_drvdata(dev); +	int ret; + +	ret = spi_master_suspend(spi); +	if (ret) +		return ret; + +	ret = pm_runtime_force_suspend(dev); +	if (ret) +		spi_master_resume(spi); + +	return ret; +} + +static int __maybe_unused spi_geni_resume(struct device *dev) +{ +	struct spi_master *spi = dev_get_drvdata(dev); +	int ret; + +	ret = pm_runtime_force_resume(dev); +	if (ret) +		return ret; + +	ret = spi_master_resume(spi); +	if (ret) +		pm_runtime_force_suspend(dev); + +	return ret; +} + +static const struct dev_pm_ops spi_geni_pm_ops = { +	SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend, +					spi_geni_runtime_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(spi_geni_suspend, spi_geni_resume) +}; + +static const struct of_device_id spi_geni_dt_match[] = { +	{ .compatible = "qcom,geni-spi" }, +	{} +}; +MODULE_DEVICE_TABLE(of, spi_geni_dt_match); + +static struct platform_driver spi_geni_driver = { +	.probe  = spi_geni_probe, +	.remove = spi_geni_remove, +	.driver = { +		.name = "geni_spi", +		.pm = &spi_geni_pm_ops, +		.of_match_table = spi_geni_dt_match, +	}, +}; +module_platform_driver(spi_geni_driver); + +MODULE_DESCRIPTION("SPI driver for GENI based QUP cores"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 421bfc7dda67..45973ee3ae11 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -295,9 +295,11 @@ static int spi_gpio_request(struct device *dev,  	spi_gpio->miso = devm_gpiod_get_optional(dev, "miso", GPIOD_IN);  	if (IS_ERR(spi_gpio->miso))  		return PTR_ERR(spi_gpio->miso); -	if (!spi_gpio->miso) -		/* HW configuration without MISO pin */ -		*mflags |= SPI_MASTER_NO_RX; +	/* +	 * No setting SPI_MASTER_NO_RX here - if there is only a MOSI +	 * pin connected the host can still do RX by changing the +	 * direction of the line. +	 */  	spi_gpio->sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);  	if (IS_ERR(spi_gpio->sck)) @@ -423,7 +425,7 @@ static int spi_gpio_probe(struct platform_device *pdev)  	spi_gpio->bitbang.chipselect = spi_gpio_chipselect;  	spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction; -	if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) { +	if ((master_flags & SPI_MASTER_NO_TX) == 0) {  		spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;  		spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;  		spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; @@ -447,10 +449,8 @@ static int spi_gpio_probe(struct platform_device *pdev)  static int spi_gpio_remove(struct platform_device *pdev)  {  	struct spi_gpio			*spi_gpio; -	struct spi_gpio_platform_data	*pdata;  	spi_gpio = platform_get_drvdata(pdev); -	pdata = dev_get_platdata(&pdev->dev);  	/* stop() unregisters child devices too */  	spi_bitbang_stop(&spi_gpio->bitbang); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 08dd3a31a3e5..dd1ce12aa386 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -63,6 +63,7 @@ struct spi_imx_devtype_data {  	void (*trigger)(struct spi_imx_data *);  	int (*rx_available)(struct spi_imx_data *);  	void (*reset)(struct spi_imx_data *); +	void (*setup_wml)(struct spi_imx_data *);  	void (*disable)(struct spi_imx_data *);  	bool has_dmamode;  	bool has_slavemode; @@ -216,7 +217,6 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,  			 struct spi_transfer *transfer)  {  	struct spi_imx_data *spi_imx = spi_master_get_devdata(master); -	unsigned int bytes_per_word, i;  	if (!master->dma_rx)  		return false; @@ -224,14 +224,9 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,  	if (spi_imx->slave_mode)  		return false; -	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); - -	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) { -		if (!(transfer->len % (i * bytes_per_word))) -			break; -	} +	if (transfer->len < spi_imx->devtype_data->fifo_size) +		return false; -	spi_imx->wml = i;  	spi_imx->dynamic_burst = 0;  	return true; @@ -583,18 +578,21 @@ static int mx51_ecspi_config(struct spi_device *spi)  	else			/* SCLK is _very_ slow */  		usleep_range(delay, delay + 10); +	return 0; +} + +static void mx51_setup_wml(struct spi_imx_data *spi_imx) +{  	/*  	 * Configure the DMA register: setup the watermark  	 * and enable DMA request.  	 */ -	writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml) | +	writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |  		MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |  		MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |  		MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |  		MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA); - -	return 0;  }  static int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx) @@ -931,6 +929,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {  	.trigger = mx51_ecspi_trigger,  	.rx_available = mx51_ecspi_rx_available,  	.reset = mx51_ecspi_reset, +	.setup_wml = mx51_setup_wml,  	.fifo_size = 64,  	.has_dmamode = true,  	.dynamic_burst = true, @@ -1138,7 +1137,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,  				 struct spi_transfer *t)  {  	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); -	int ret;  	if (!t)  		return 0; @@ -1179,12 +1177,6 @@ static int spi_imx_setupxfer(struct spi_device *spi,  	else  		spi_imx->usedma = 0; -	if (spi_imx->usedma) { -		ret = spi_imx_dma_configure(spi->master); -		if (ret) -			return ret; -	} -  	if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {  		spi_imx->rx = mx53_ecspi_rx_slave;  		spi_imx->tx = mx53_ecspi_tx_slave; @@ -1289,6 +1281,31 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,  	unsigned long timeout;  	struct spi_master *master = spi_imx->bitbang.master;  	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; +	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents); +	unsigned int bytes_per_word, i; +	int ret; + +	/* Get the right burst length from the last sg to ensure no tail data */ +	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word); +	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) { +		if (!(sg_dma_len(last_sg) % (i * bytes_per_word))) +			break; +	} +	/* Use 1 as wml in case no available burst length got */ +	if (i == 0) +		i = 1; + +	spi_imx->wml =  i; + +	ret = spi_imx_dma_configure(master); +	if (ret) +		return ret; + +	if (!spi_imx->devtype_data->setup_wml) { +		dev_err(spi_imx->dev, "No setup_wml()?\n"); +		return -EINVAL; +	} +	spi_imx->devtype_data->setup_wml(spi_imx);  	/*  	 * The TX DMA setup starts the transfer, so make sure RX is configured diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index e43842c7a31a..62a7b80801d2 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -12,6 +12,8 @@  #include "internals.h" +#define SPI_MEM_MAX_BUSWIDTH		4 +  /**   * spi_controller_dma_map_mem_op_data() - DMA-map the buffer attached to a   *					  memory operation @@ -149,6 +151,44 @@ static bool spi_mem_default_supports_op(struct spi_mem *mem,  }  EXPORT_SYMBOL_GPL(spi_mem_default_supports_op); +static bool spi_mem_buswidth_is_valid(u8 buswidth) +{ +	if (hweight8(buswidth) > 1 || buswidth > SPI_MEM_MAX_BUSWIDTH) +		return false; + +	return true; +} + +static int spi_mem_check_op(const struct spi_mem_op *op) +{ +	if (!op->cmd.buswidth) +		return -EINVAL; + +	if ((op->addr.nbytes && !op->addr.buswidth) || +	    (op->dummy.nbytes && !op->dummy.buswidth) || +	    (op->data.nbytes && !op->data.buswidth)) +		return -EINVAL; + +	if (!spi_mem_buswidth_is_valid(op->cmd.buswidth) || +	    !spi_mem_buswidth_is_valid(op->addr.buswidth) || +	    !spi_mem_buswidth_is_valid(op->dummy.buswidth) || +	    !spi_mem_buswidth_is_valid(op->data.buswidth)) +		return -EINVAL; + +	return 0; +} + +static bool spi_mem_internal_supports_op(struct spi_mem *mem, +					 const struct spi_mem_op *op) +{ +	struct spi_controller *ctlr = mem->spi->controller; + +	if (ctlr->mem_ops && ctlr->mem_ops->supports_op) +		return ctlr->mem_ops->supports_op(mem, op); + +	return spi_mem_default_supports_op(mem, op); +} +  /**   * spi_mem_supports_op() - Check if a memory device and the controller it is   *			   connected to support a specific memory operation @@ -166,12 +206,10 @@ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);   */  bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)  { -	struct spi_controller *ctlr = mem->spi->controller; - -	if (ctlr->mem_ops && ctlr->mem_ops->supports_op) -		return ctlr->mem_ops->supports_op(mem, op); +	if (spi_mem_check_op(op)) +		return false; -	return spi_mem_default_supports_op(mem, op); +	return spi_mem_internal_supports_op(mem, op);  }  EXPORT_SYMBOL_GPL(spi_mem_supports_op); @@ -196,7 +234,11 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)  	u8 *tmpbuf;  	int ret; -	if (!spi_mem_supports_op(mem, op)) +	ret = spi_mem_check_op(op); +	if (ret) +		return ret; + +	if (!spi_mem_internal_supports_op(mem, op))  		return -ENOTSUPP;  	if (ctlr->mem_ops) { @@ -346,10 +388,25 @@ EXPORT_SYMBOL_GPL(spi_mem_get_name);  int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)  {  	struct spi_controller *ctlr = mem->spi->controller; +	size_t len; + +	len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;  	if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size)  		return ctlr->mem_ops->adjust_op_size(mem, op); +	if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) { +		if (len > spi_max_transfer_size(mem->spi)) +			return -EINVAL; + +		op->data.nbytes = min3((size_t)op->data.nbytes, +				       spi_max_transfer_size(mem->spi), +				       spi_max_message_size(mem->spi) - +				       len); +		if (!op->data.nbytes) +			return -EINVAL; +	} +  	return 0;  }  EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 86bf45667a04..3dc31627c655 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -98,6 +98,7 @@ struct mtk_spi {  	struct clk *parent_clk, *sel_clk, *spi_clk;  	struct spi_transfer *cur_transfer;  	u32 xfer_len; +	u32 num_xfered;  	struct scatterlist *tx_sgl, *rx_sgl;  	u32 tx_sgl_len, rx_sgl_len;  	const struct mtk_spi_compatible *dev_comp; @@ -385,6 +386,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,  	mdata->cur_transfer = xfer;  	mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len); +	mdata->num_xfered = 0;  	mtk_spi_prepare_transfer(master, xfer);  	mtk_spi_setup_packet(master); @@ -415,6 +417,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master,  	mdata->tx_sgl_len = 0;  	mdata->rx_sgl_len = 0;  	mdata->cur_transfer = xfer; +	mdata->num_xfered = 0;  	mtk_spi_prepare_transfer(master, xfer); @@ -482,7 +485,7 @@ static int mtk_spi_setup(struct spi_device *spi)  static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)  { -	u32 cmd, reg_val, cnt, remainder; +	u32 cmd, reg_val, cnt, remainder, len;  	struct spi_master *master = dev_id;  	struct mtk_spi *mdata = spi_master_get_devdata(master);  	struct spi_transfer *trans = mdata->cur_transfer; @@ -497,36 +500,38 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)  		if (trans->rx_buf) {  			cnt = mdata->xfer_len / 4;  			ioread32_rep(mdata->base + SPI_RX_DATA_REG, -				     trans->rx_buf, cnt); +				     trans->rx_buf + mdata->num_xfered, cnt);  			remainder = mdata->xfer_len % 4;  			if (remainder > 0) {  				reg_val = readl(mdata->base + SPI_RX_DATA_REG); -				memcpy(trans->rx_buf + (cnt * 4), -					®_val, remainder); +				memcpy(trans->rx_buf + +					mdata->num_xfered + +					(cnt * 4), +					®_val, +					remainder);  			}  		} -		trans->len -= mdata->xfer_len; -		if (!trans->len) { +		mdata->num_xfered += mdata->xfer_len; +		if (mdata->num_xfered == trans->len) {  			spi_finalize_current_transfer(master);  			return IRQ_HANDLED;  		} -		if (trans->tx_buf) -			trans->tx_buf += mdata->xfer_len; -		if (trans->rx_buf) -			trans->rx_buf += mdata->xfer_len; - -		mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, trans->len); +		len = trans->len - mdata->num_xfered; +		mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len);  		mtk_spi_setup_packet(master); -		cnt = trans->len / 4; -		iowrite32_rep(mdata->base + SPI_TX_DATA_REG, trans->tx_buf, cnt); +		cnt = len / 4; +		iowrite32_rep(mdata->base + SPI_TX_DATA_REG, +				trans->tx_buf + mdata->num_xfered, cnt); -		remainder = trans->len % 4; +		remainder = len % 4;  		if (remainder > 0) {  			reg_val = 0; -			memcpy(®_val, trans->tx_buf + (cnt * 4), remainder); +			memcpy(®_val, +				trans->tx_buf + (cnt * 4) + mdata->num_xfered, +				remainder);  			writel(reg_val, mdata->base + SPI_TX_DATA_REG);  		} diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 508c61c669e7..f024c3fc3679 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -33,6 +33,7 @@  #include <linux/of.h>  #include <linux/of_device.h>  #include <linux/gcd.h> +#include <linux/iopoll.h>  #include <linux/spi/spi.h>  #include <linux/gpio.h> @@ -126,6 +127,7 @@ struct omap2_mcspi_regs {  };  struct omap2_mcspi { +	struct completion	txdone;  	struct spi_master	*master;  	/* Virtual base address of the controller */  	void __iomem		*base; @@ -135,6 +137,7 @@ struct omap2_mcspi {  	struct device		*dev;  	struct omap2_mcspi_regs ctx;  	int			fifo_depth; +	bool			slave_aborted;  	unsigned int		pin_dir:1;  }; @@ -274,19 +277,23 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)  	}  } -static void omap2_mcspi_set_master_mode(struct spi_master *master) +static void omap2_mcspi_set_mode(struct spi_master *master)  {  	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);  	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;  	u32 l;  	/* -	 * Setup when switching from (reset default) slave mode -	 * to single-channel master mode +	 * Choose master or slave mode  	 */  	l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); -	l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS); -	l |= OMAP2_MCSPI_MODULCTRL_SINGLE; +	l &= ~(OMAP2_MCSPI_MODULCTRL_STEST); +	if (spi_controller_is_slave(master)) { +		l |= (OMAP2_MCSPI_MODULCTRL_MS); +	} else { +		l &= ~(OMAP2_MCSPI_MODULCTRL_MS); +		l |= OMAP2_MCSPI_MODULCTRL_SINGLE; +	}  	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);  	ctx->modulctrl = l; @@ -299,7 +306,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,  	struct omap2_mcspi_cs *cs = spi->controller_state;  	struct omap2_mcspi *mcspi;  	unsigned int wcnt; -	int max_fifo_depth, fifo_depth, bytes_per_word; +	int max_fifo_depth, bytes_per_word;  	u32 chconf, xferlevel;  	mcspi = spi_master_get_devdata(master); @@ -315,10 +322,6 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,  		else  			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; -		fifo_depth = gcd(t->len, max_fifo_depth); -		if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0) -			goto disable_fifo; -  		wcnt = t->len / bytes_per_word;  		if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)  			goto disable_fifo; @@ -326,16 +329,17 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,  		xferlevel = wcnt << 16;  		if (t->rx_buf != NULL) {  			chconf |= OMAP2_MCSPI_CHCONF_FFER; -			xferlevel |= (fifo_depth - 1) << 8; +			xferlevel |= (bytes_per_word - 1) << 8;  		} +  		if (t->tx_buf != NULL) {  			chconf |= OMAP2_MCSPI_CHCONF_FFET; -			xferlevel |= fifo_depth - 1; +			xferlevel |= bytes_per_word - 1;  		}  		mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);  		mcspi_write_chconf0(spi, chconf); -		mcspi->fifo_depth = fifo_depth; +		mcspi->fifo_depth = max_fifo_depth;  		return;  	} @@ -353,18 +357,22 @@ disable_fifo:  static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)  { -	unsigned long timeout; - -	timeout = jiffies + msecs_to_jiffies(1000); -	while (!(readl_relaxed(reg) & bit)) { -		if (time_after(jiffies, timeout)) { -			if (!(readl_relaxed(reg) & bit)) -				return -ETIMEDOUT; -			else -				return 0; -		} -		cpu_relax(); +	u32 val; + +	return readl_poll_timeout(reg, val, val & bit, 1, MSEC_PER_SEC); +} + +static int mcspi_wait_for_completion(struct  omap2_mcspi *mcspi, +				     struct completion *x) +{ +	if (spi_controller_is_slave(mcspi->master)) { +		if (wait_for_completion_interruptible(x) || +		    mcspi->slave_aborted) +			return -EINTR; +	} else { +		wait_for_completion(x);  	} +  	return 0;  } @@ -517,7 +525,12 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,  	dma_async_issue_pending(mcspi_dma->dma_rx);  	omap2_mcspi_set_dma_req(spi, 1, 1); -	wait_for_completion(&mcspi_dma->dma_rx_completion); +	ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion); +	if (ret || mcspi->slave_aborted) { +		dmaengine_terminate_sync(mcspi_dma->dma_rx); +		omap2_mcspi_set_dma_req(spi, 1, 0); +		return 0; +	}  	for (x = 0; x < nb_sizes; x++)  		kfree(sg_out[x]); @@ -585,7 +598,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)  	struct dma_slave_config	cfg;  	enum dma_slave_buswidth width;  	unsigned es; -	u32			burst;  	void __iomem		*chstat_reg;  	void __iomem            *irqstat_reg;  	int			wait_res; @@ -605,34 +617,49 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)  	}  	count = xfer->len; -	burst = 1; - -	if (mcspi->fifo_depth > 0) { -		if (count > mcspi->fifo_depth) -			burst = mcspi->fifo_depth / es; -		else -			burst = count / es; -	}  	memset(&cfg, 0, sizeof(cfg));  	cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;  	cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;  	cfg.src_addr_width = width;  	cfg.dst_addr_width = width; -	cfg.src_maxburst = burst; -	cfg.dst_maxburst = burst; +	cfg.src_maxburst = es; +	cfg.dst_maxburst = es;  	rx = xfer->rx_buf;  	tx = xfer->tx_buf; -	if (tx != NULL) +	mcspi->slave_aborted = false; +	reinit_completion(&mcspi_dma->dma_tx_completion); +	reinit_completion(&mcspi_dma->dma_rx_completion); +	reinit_completion(&mcspi->txdone); +	if (tx) { +		/* Enable EOW IRQ to know end of tx in slave mode */ +		if (spi_controller_is_slave(spi->master)) +			mcspi_write_reg(spi->master, +					OMAP2_MCSPI_IRQENABLE, +					OMAP2_MCSPI_IRQSTATUS_EOW);  		omap2_mcspi_tx_dma(spi, xfer, cfg); +	}  	if (rx != NULL)  		count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);  	if (tx != NULL) { -		wait_for_completion(&mcspi_dma->dma_tx_completion); +		int ret; + +		ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion); +		if (ret || mcspi->slave_aborted) { +			dmaengine_terminate_sync(mcspi_dma->dma_tx); +			omap2_mcspi_set_dma_req(spi, 0, 0); +			return 0; +		} + +		if (spi_controller_is_slave(mcspi->master)) { +			ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone); +			if (ret || mcspi->slave_aborted) +				return 0; +		}  		if (mcspi->fifo_depth > 0) {  			irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; @@ -1089,6 +1116,36 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)  		gpio_free(spi->cs_gpio);  } +static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data) +{ +	struct omap2_mcspi *mcspi = data; +	u32 irqstat; + +	irqstat	= mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS); +	if (!irqstat) +		return IRQ_NONE; + +	/* Disable IRQ and wakeup slave xfer task */ +	mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0); +	if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW) +		complete(&mcspi->txdone); + +	return IRQ_HANDLED; +} + +static int omap2_mcspi_slave_abort(struct spi_master *master) +{ +	struct omap2_mcspi *mcspi = spi_master_get_devdata(master); +	struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels; + +	mcspi->slave_aborted = true; +	complete(&mcspi_dma->dma_rx_completion); +	complete(&mcspi_dma->dma_tx_completion); +	complete(&mcspi->txdone); + +	return 0; +} +  static int omap2_mcspi_transfer_one(struct spi_master *master,  				    struct spi_device *spi,  				    struct spi_transfer *t) @@ -1255,10 +1312,20 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,  				struct spi_device *spi,  				struct spi_transfer *xfer)  { +	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); +	struct omap2_mcspi_dma *mcspi_dma = +		&mcspi->dma_channels[spi->chip_select]; + +	if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) +		return false; + +	if (spi_controller_is_slave(master)) +		return true; +  	return (xfer->len >= DMA_MIN_BYTES);  } -static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) +static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)  {  	struct spi_master	*master = mcspi->master;  	struct omap2_mcspi_regs	*ctx = &mcspi->ctx; @@ -1275,7 +1342,7 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)  			OMAP2_MCSPI_WAKEUPENABLE_WKEN);  	ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; -	omap2_mcspi_set_master_mode(master); +	omap2_mcspi_set_mode(master);  	pm_runtime_mark_last_busy(mcspi->dev);  	pm_runtime_put_autosuspend(mcspi->dev);  	return 0; @@ -1350,11 +1417,12 @@ static int omap2_mcspi_probe(struct platform_device *pdev)  	struct device_node	*node = pdev->dev.of_node;  	const struct of_device_id *match; -	master = spi_alloc_master(&pdev->dev, sizeof *mcspi); -	if (master == NULL) { -		dev_dbg(&pdev->dev, "master allocation failed\n"); +	if (of_property_read_bool(node, "spi-slave")) +		master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi)); +	else +		master = spi_alloc_master(&pdev->dev, sizeof(*mcspi)); +	if (!master)  		return -ENOMEM; -	}  	/* the spi->mode bits understood by this driver: */  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; @@ -1366,6 +1434,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)  	master->transfer_one = omap2_mcspi_transfer_one;  	master->set_cs = omap2_mcspi_set_cs;  	master->cleanup = omap2_mcspi_cleanup; +	master->slave_abort = omap2_mcspi_slave_abort;  	master->dev.of_node = node;  	master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;  	master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; @@ -1417,15 +1486,31 @@ static int omap2_mcspi_probe(struct platform_device *pdev)  		sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);  	} +	status = platform_get_irq(pdev, 0); +	if (status == -EPROBE_DEFER) +		goto free_master; +	if (status < 0) { +		dev_err(&pdev->dev, "no irq resource found\n"); +		goto free_master; +	} +	init_completion(&mcspi->txdone); +	status = devm_request_irq(&pdev->dev, status, +				  omap2_mcspi_irq_handler, 0, pdev->name, +				  mcspi); +	if (status) { +		dev_err(&pdev->dev, "Cannot request IRQ"); +		goto free_master; +	} +  	pm_runtime_use_autosuspend(&pdev->dev);  	pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);  	pm_runtime_enable(&pdev->dev); -	status = omap2_mcspi_master_setup(mcspi); +	status = omap2_mcspi_controller_setup(mcspi);  	if (status < 0)  		goto disable_pm; -	status = devm_spi_register_master(&pdev->dev, master); +	status = devm_spi_register_controller(&pdev->dev, master);  	if (status < 0)  		goto disable_pm; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 47ef6b1a2e76..7f280567093e 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -431,6 +431,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)  	int word_len;  	struct orion_spi *orion_spi;  	int cs = spi->chip_select; +	void __iomem *vaddr;  	word_len = spi->bits_per_word;  	count = xfer->len; @@ -441,8 +442,9 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)  	 * Use SPI direct write mode if base address is available. Otherwise  	 * fall back to PIO mode for this transfer.  	 */ -	if ((orion_spi->child[cs].direct_access.vaddr) && (xfer->tx_buf) && -	    (word_len == 8)) { +	vaddr = orion_spi->child[cs].direct_access.vaddr; + +	if (vaddr && xfer->tx_buf && word_len == 8) {  		unsigned int cnt = count / 4;  		unsigned int rem = count % 4; @@ -450,13 +452,11 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)  		 * Send the TX-data to the SPI device via the direct  		 * mapped address window  		 */ -		iowrite32_rep(orion_spi->child[cs].direct_access.vaddr, -			      xfer->tx_buf, cnt); +		iowrite32_rep(vaddr, xfer->tx_buf, cnt);  		if (rem) {  			u32 *buf = (u32 *)xfer->tx_buf; -			iowrite8_rep(orion_spi->child[cs].direct_access.vaddr, -				     &buf[cnt], rem); +			iowrite8_rep(vaddr, &buf[cnt], rem);  		}  		return count; @@ -683,6 +683,7 @@ static int orion_spi_probe(struct platform_device *pdev)  	}  	for_each_available_child_of_node(pdev->dev.of_node, np) { +		struct orion_direct_acc *dir_acc;  		u32 cs;  		int cs_gpio; @@ -750,14 +751,13 @@ static int orion_spi_probe(struct platform_device *pdev)  		 * This needs to get extended for the direct SPI-NOR / SPI-NAND  		 * support, once this gets implemented.  		 */ -		spi->child[cs].direct_access.vaddr = devm_ioremap(&pdev->dev, -							    r->start, -							    PAGE_SIZE); -		if (!spi->child[cs].direct_access.vaddr) { +		dir_acc = &spi->child[cs].direct_access; +		dir_acc->vaddr = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); +		if (!dir_acc->vaddr) {  			status = -ENOMEM;  			goto out_rel_axi_clk;  		} -		spi->child[cs].direct_access.size = PAGE_SIZE; +		dir_acc->size = PAGE_SIZE;  		dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);  	} diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index bd1c6b53283f..d7e4e18ec3df 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -468,7 +468,7 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi)  	/* allocate coherent DMAable memory for hardware buffer descriptors. */  	sqi->bd = dma_zalloc_coherent(&sqi->master->dev,  				      sizeof(*bd) * PESQI_BD_COUNT, -				      &sqi->bd_dma, GFP_DMA32); +				      &sqi->bd_dma, GFP_KERNEL);  	if (!sqi->bd) {  		dev_err(&sqi->master->dev, "failed allocating dma buffer\n");  		return -ENOMEM; @@ -656,7 +656,7 @@ static int pic32_sqi_probe(struct platform_device *pdev)  	master->max_speed_hz	= clk_get_rate(sqi->base_clk);  	master->dma_alignment	= 32;  	master->max_dma_len	= PESQI_BD_BUF_LEN_MAX; -	master->dev.of_node	= of_node_get(pdev->dev.of_node); +	master->dev.of_node	= pdev->dev.of_node;  	master->mode_bits	= SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |  				  SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;  	master->flags		= SPI_MASTER_HALF_DUPLEX; diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index f8a45af1fa9f..131849adc570 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -320,7 +320,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,  	desc_rx = dmaengine_prep_slave_sg(master->dma_rx,  					  xfer->rx_sg.sgl,  					  xfer->rx_sg.nents, -					  DMA_FROM_DEVICE, +					  DMA_DEV_TO_MEM,  					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);  	if (!desc_rx) {  		ret = -EINVAL; @@ -330,7 +330,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,  	desc_tx = dmaengine_prep_slave_sg(master->dma_tx,  					  xfer->tx_sg.sgl,  					  xfer->tx_sg.nents, -					  DMA_TO_DEVICE, +					  DMA_MEM_TO_DEV,  					  DMA_PREP_INTERRUPT | DMA_CTRL_ACK);  	if (!desc_tx) {  		ret = -EINVAL; @@ -774,7 +774,7 @@ static int pic32_spi_probe(struct platform_device *pdev)  	if (ret)  		goto err_master; -	master->dev.of_node	= of_node_get(pdev->dev.of_node); +	master->dev.of_node	= pdev->dev.of_node;  	master->mode_bits	= SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH;  	master->num_chipselect	= 1; /* single chip-select */  	master->max_speed_hz	= clk_get_rate(pic32s->clk); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 1af8c96b940e..6120e6abcd96 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1490,10 +1490,8 @@ static void do_polling_transfer(struct pl022 *pl022)  	struct spi_message *message = NULL;  	struct spi_transfer *transfer = NULL;  	struct spi_transfer *previous = NULL; -	struct chip_data *chip;  	unsigned long time, timeout; -	chip = pl022->cur_chip;  	message = pl022->cur_msg;  	while (message->state != STATE_DONE) { @@ -2325,10 +2323,8 @@ static int pl022_suspend(struct device *dev)  	int ret;  	ret = spi_master_suspend(pl022->master); -	if (ret) { -		dev_warn(dev, "cannot suspend master\n"); +	if (ret)  		return ret; -	}  	ret = pm_runtime_force_suspend(dev);  	if (ret) { @@ -2353,9 +2349,7 @@ static int pl022_resume(struct device *dev)  	/* Start the queue running */  	ret = spi_master_resume(pl022->master); -	if (ret) -		dev_err(dev, "problem starting queue (%d)\n", ret); -	else +	if (!ret)  		dev_dbg(dev, "resumed\n");  	return ret; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 14f4ea59caff..612cc49db28f 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -33,6 +33,7 @@  #include <linux/clk.h>  #include <linux/pm_runtime.h>  #include <linux/acpi.h> +#include <linux/of_device.h>  #include "spi-pxa2xx.h" @@ -665,9 +666,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)  			bytes_left = drv_data->rx_end - drv_data->rx;  			switch (drv_data->n_bytes) {  			case 4: -				bytes_left >>= 1; +				bytes_left >>= 2; +				break;  			case 2:  				bytes_left >>= 1; +				break;  			}  			rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data); @@ -1333,9 +1336,6 @@ static void cleanup(struct spi_device *spi)  	kfree(chip);  } -#ifdef CONFIG_PCI -#ifdef CONFIG_ACPI -  static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {  	{ "INT33C0", LPSS_LPT_SSP },  	{ "INT33C1", LPSS_LPT_SSP }, @@ -1347,23 +1347,6 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {  };  MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); -static int pxa2xx_spi_get_port_id(struct acpi_device *adev) -{ -	unsigned int devid; -	int port_id = -1; - -	if (adev && adev->pnp.unique_id && -	    !kstrtouint(adev->pnp.unique_id, 0, &devid)) -		port_id = devid; -	return port_id; -} -#else /* !CONFIG_ACPI */ -static int pxa2xx_spi_get_port_id(struct acpi_device *adev) -{ -	return -1; -} -#endif -  /*   * PCI IDs of compound devices that integrate both host controller and private   * integrated DMA engine. Please note these are not used in module @@ -1410,6 +1393,37 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {  	{ },  }; +static const struct of_device_id pxa2xx_spi_of_match[] = { +	{ .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP }, +	{}, +}; +MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match); + +#ifdef CONFIG_ACPI + +static int pxa2xx_spi_get_port_id(struct acpi_device *adev) +{ +	unsigned int devid; +	int port_id = -1; + +	if (adev && adev->pnp.unique_id && +	    !kstrtouint(adev->pnp.unique_id, 0, &devid)) +		port_id = devid; +	return port_id; +} + +#else /* !CONFIG_ACPI */ + +static int pxa2xx_spi_get_port_id(struct acpi_device *adev) +{ +	return -1; +} + +#endif /* CONFIG_ACPI */ + + +#ifdef CONFIG_PCI +  static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)  {  	struct device *dev = param; @@ -1420,6 +1434,8 @@ static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)  	return true;  } +#endif /* CONFIG_PCI */ +  static struct pxa2xx_spi_master *  pxa2xx_spi_init_pdata(struct platform_device *pdev)  { @@ -1429,11 +1445,15 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)  	struct resource *res;  	const struct acpi_device_id *adev_id = NULL;  	const struct pci_device_id *pcidev_id = NULL; -	int type; +	const struct of_device_id *of_id = NULL; +	enum pxa_ssp_type type;  	adev = ACPI_COMPANION(&pdev->dev); -	if (dev_is_pci(pdev->dev.parent)) +	if (pdev->dev.of_node) +		of_id = of_match_device(pdev->dev.driver->of_match_table, +					&pdev->dev); +	else if (dev_is_pci(pdev->dev.parent))  		pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,  					 to_pci_dev(pdev->dev.parent));  	else if (adev) @@ -1443,9 +1463,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)  		return NULL;  	if (adev_id) -		type = (int)adev_id->driver_data; +		type = (enum pxa_ssp_type)adev_id->driver_data;  	else if (pcidev_id) -		type = (int)pcidev_id->driver_data; +		type = (enum pxa_ssp_type)pcidev_id->driver_data; +	else if (of_id) +		type = (enum pxa_ssp_type)of_id->data;  	else  		return NULL; @@ -1464,11 +1486,13 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)  	if (IS_ERR(ssp->mmio_base))  		return NULL; +#ifdef CONFIG_PCI  	if (pcidev_id) {  		pdata->tx_param = pdev->dev.parent;  		pdata->rx_param = pdev->dev.parent;  		pdata->dma_filter = pxa2xx_spi_idma_filter;  	} +#endif  	ssp->clk = devm_clk_get(&pdev->dev, NULL);  	ssp->irq = platform_get_irq(pdev, 0); @@ -1482,14 +1506,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)  	return pdata;  } -#else /* !CONFIG_PCI */ -static inline struct pxa2xx_spi_master * -pxa2xx_spi_init_pdata(struct platform_device *pdev) -{ -	return NULL; -} -#endif -  static int pxa2xx_spi_fw_translate_cs(struct spi_controller *master,  				      unsigned int cs)  { @@ -1764,14 +1780,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)  	return 0;  } -static void pxa2xx_spi_shutdown(struct platform_device *pdev) -{ -	int status = 0; - -	if ((status = pxa2xx_spi_remove(pdev)) != 0) -		dev_err(&pdev->dev, "shutdown failed with %d\n", status); -} -  #ifdef CONFIG_PM_SLEEP  static int pxa2xx_spi_suspend(struct device *dev)  { @@ -1808,13 +1816,7 @@ static int pxa2xx_spi_resume(struct device *dev)  		lpss_ssp_setup(drv_data);  	/* Start the queue running */ -	status = spi_controller_resume(drv_data->master); -	if (status != 0) { -		dev_err(dev, "problem starting queue (%d)\n", status); -		return status; -	} - -	return 0; +	return spi_controller_resume(drv_data->master);  }  #endif @@ -1848,10 +1850,10 @@ static struct platform_driver driver = {  		.name	= "pxa2xx-spi",  		.pm	= &pxa2xx_spi_pm_ops,  		.acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match), +		.of_match_table = of_match_ptr(pxa2xx_spi_of_match),  	},  	.probe = pxa2xx_spi_probe,  	.remove = pxa2xx_spi_remove, -	.shutdown = pxa2xx_spi_shutdown,  };  static int __init pxa2xx_spi_init(void) diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c new file mode 100644 index 000000000000..b8163b40bb92 --- /dev/null +++ b/drivers/spi/spi-qcom-qspi.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi-mem.h> + + +#define QSPI_NUM_CS		2 +#define QSPI_BYTES_PER_WORD	4 + +#define MSTR_CONFIG		0x0000 +#define FULL_CYCLE_MODE		BIT(3) +#define FB_CLK_EN		BIT(4) +#define PIN_HOLDN		BIT(6) +#define PIN_WPN			BIT(7) +#define DMA_ENABLE		BIT(8) +#define BIG_ENDIAN_MODE		BIT(9) +#define SPI_MODE_MSK		0xc00 +#define SPI_MODE_SHFT		10 +#define CHIP_SELECT_NUM		BIT(12) +#define SBL_EN			BIT(13) +#define LPA_BASE_MSK		0x3c000 +#define LPA_BASE_SHFT		14 +#define TX_DATA_DELAY_MSK	0xc0000 +#define TX_DATA_DELAY_SHFT	18 +#define TX_CLK_DELAY_MSK	0x300000 +#define TX_CLK_DELAY_SHFT	20 +#define TX_CS_N_DELAY_MSK	0xc00000 +#define TX_CS_N_DELAY_SHFT	22 +#define TX_DATA_OE_DELAY_MSK	0x3000000 +#define TX_DATA_OE_DELAY_SHFT	24 + +#define AHB_MASTER_CFG				0x0004 +#define HMEM_TYPE_START_MID_TRANS_MSK		0x7 +#define HMEM_TYPE_START_MID_TRANS_SHFT		0 +#define HMEM_TYPE_LAST_TRANS_MSK		0x38 +#define HMEM_TYPE_LAST_TRANS_SHFT		3 +#define USE_HMEMTYPE_LAST_ON_DESC_OR_CHAIN_MSK	0xc0 +#define USE_HMEMTYPE_LAST_ON_DESC_OR_CHAIN_SHFT	6 +#define HMEMTYPE_READ_TRANS_MSK			0x700 +#define HMEMTYPE_READ_TRANS_SHFT		8 +#define HSHARED					BIT(11) +#define HINNERSHARED				BIT(12) + +#define MSTR_INT_EN		0x000C +#define MSTR_INT_STATUS		0x0010 +#define RESP_FIFO_UNDERRUN	BIT(0) +#define RESP_FIFO_NOT_EMPTY	BIT(1) +#define RESP_FIFO_RDY		BIT(2) +#define HRESP_FROM_NOC_ERR	BIT(3) +#define WR_FIFO_EMPTY		BIT(9) +#define WR_FIFO_FULL		BIT(10) +#define WR_FIFO_OVERRUN		BIT(11) +#define TRANSACTION_DONE	BIT(16) +#define QSPI_ERR_IRQS		(RESP_FIFO_UNDERRUN | HRESP_FROM_NOC_ERR | \ +				 WR_FIFO_OVERRUN) +#define QSPI_ALL_IRQS		(QSPI_ERR_IRQS | RESP_FIFO_RDY | \ +				 WR_FIFO_EMPTY | WR_FIFO_FULL | \ +				 TRANSACTION_DONE) + +#define PIO_XFER_CTRL		0x0014 +#define REQUEST_COUNT_MSK	0xffff + +#define PIO_XFER_CFG		0x0018 +#define TRANSFER_DIRECTION	BIT(0) +#define MULTI_IO_MODE_MSK	0xe +#define MULTI_IO_MODE_SHFT	1 +#define TRANSFER_FRAGMENT	BIT(8) +#define SDR_1BIT		1 +#define SDR_2BIT		2 +#define SDR_4BIT		3 +#define DDR_1BIT		5 +#define DDR_2BIT		6 +#define DDR_4BIT		7 +#define DMA_DESC_SINGLE_SPI	1 +#define DMA_DESC_DUAL_SPI	2 +#define DMA_DESC_QUAD_SPI	3 + +#define PIO_XFER_STATUS		0x001c +#define WR_FIFO_BYTES_MSK	0xffff0000 +#define WR_FIFO_BYTES_SHFT	16 + +#define PIO_DATAOUT_1B		0x0020 +#define PIO_DATAOUT_4B		0x0024 + +#define RD_FIFO_STATUS	0x002c +#define FIFO_EMPTY	BIT(11) +#define WR_CNTS_MSK	0x7f0 +#define WR_CNTS_SHFT	4 +#define RDY_64BYTE	BIT(3) +#define RDY_32BYTE	BIT(2) +#define RDY_16BYTE	BIT(1) +#define FIFO_RDY	BIT(0) + +#define RD_FIFO_CFG		0x0028 +#define CONTINUOUS_MODE		BIT(0) + +#define RD_FIFO_RESET		0x0030 +#define RESET_FIFO		BIT(0) + +#define CUR_MEM_ADDR		0x0048 +#define HW_VERSION		0x004c +#define RD_FIFO			0x0050 +#define SAMPLING_CLK_CFG	0x0090 +#define SAMPLING_CLK_STATUS	0x0094 + + +enum qspi_dir { +	QSPI_READ, +	QSPI_WRITE, +}; + +struct qspi_xfer { +	union { +		const void *tx_buf; +		void *rx_buf; +	}; +	unsigned int rem_bytes; +	unsigned int buswidth; +	enum qspi_dir dir; +	bool is_last; +}; + +enum qspi_clocks { +	QSPI_CLK_CORE, +	QSPI_CLK_IFACE, +	QSPI_NUM_CLKS +}; + +struct qcom_qspi { +	void __iomem *base; +	struct device *dev; +	struct clk_bulk_data clks[QSPI_NUM_CLKS]; +	struct qspi_xfer xfer; +	/* Lock to protect data accessed by IRQs */ +	spinlock_t lock; +}; + +static u32 qspi_buswidth_to_iomode(struct qcom_qspi *ctrl, +				   unsigned int buswidth) +{ +	switch (buswidth) { +	case 1: +		return SDR_1BIT << MULTI_IO_MODE_SHFT; +	case 2: +		return SDR_2BIT << MULTI_IO_MODE_SHFT; +	case 4: +		return SDR_4BIT << MULTI_IO_MODE_SHFT; +	default: +		dev_warn_once(ctrl->dev, +				"Unexpected bus width: %u\n", buswidth); +		return SDR_1BIT << MULTI_IO_MODE_SHFT; +	} +} + +static void qcom_qspi_pio_xfer_cfg(struct qcom_qspi *ctrl) +{ +	u32 pio_xfer_cfg; +	const struct qspi_xfer *xfer; + +	xfer = &ctrl->xfer; +	pio_xfer_cfg = readl(ctrl->base + PIO_XFER_CFG); +	pio_xfer_cfg &= ~TRANSFER_DIRECTION; +	pio_xfer_cfg |= xfer->dir; +	if (xfer->is_last) +		pio_xfer_cfg &= ~TRANSFER_FRAGMENT; +	else +		pio_xfer_cfg |= TRANSFER_FRAGMENT; +	pio_xfer_cfg &= ~MULTI_IO_MODE_MSK; +	pio_xfer_cfg |= qspi_buswidth_to_iomode(ctrl, xfer->buswidth); + +	writel(pio_xfer_cfg, ctrl->base + PIO_XFER_CFG); +} + +static void qcom_qspi_pio_xfer_ctrl(struct qcom_qspi *ctrl) +{ +	u32 pio_xfer_ctrl; + +	pio_xfer_ctrl = readl(ctrl->base + PIO_XFER_CTRL); +	pio_xfer_ctrl &= ~REQUEST_COUNT_MSK; +	pio_xfer_ctrl |= ctrl->xfer.rem_bytes; +	writel(pio_xfer_ctrl, ctrl->base + PIO_XFER_CTRL); +} + +static void qcom_qspi_pio_xfer(struct qcom_qspi *ctrl) +{ +	u32 ints; + +	qcom_qspi_pio_xfer_cfg(ctrl); + +	/* Ack any previous interrupts that might be hanging around */ +	writel(QSPI_ALL_IRQS, ctrl->base + MSTR_INT_STATUS); + +	/* Setup new interrupts */ +	if (ctrl->xfer.dir == QSPI_WRITE) +		ints = QSPI_ERR_IRQS | WR_FIFO_EMPTY; +	else +		ints = QSPI_ERR_IRQS | RESP_FIFO_RDY; +	writel(ints, ctrl->base + MSTR_INT_EN); + +	/* Kick off the transfer */ +	qcom_qspi_pio_xfer_ctrl(ctrl); +} + +static void qcom_qspi_handle_err(struct spi_master *master, +				 struct spi_message *msg) +{ +	struct qcom_qspi *ctrl = spi_master_get_devdata(master); +	unsigned long flags; + +	spin_lock_irqsave(&ctrl->lock, flags); +	writel(0, ctrl->base + MSTR_INT_EN); +	ctrl->xfer.rem_bytes = 0; +	spin_unlock_irqrestore(&ctrl->lock, flags); +} + +static int qcom_qspi_transfer_one(struct spi_master *master, +				  struct spi_device *slv, +				  struct spi_transfer *xfer) +{ +	struct qcom_qspi *ctrl = spi_master_get_devdata(master); +	int ret; +	unsigned long speed_hz; +	unsigned long flags; + +	speed_hz = slv->max_speed_hz; +	if (xfer->speed_hz) +		speed_hz = xfer->speed_hz; + +	/* In regular operation (SBL_EN=1) core must be 4x transfer clock */ +	ret = clk_set_rate(ctrl->clks[QSPI_CLK_CORE].clk, speed_hz * 4); +	if (ret) { +		dev_err(ctrl->dev, "Failed to set core clk %d\n", ret); +		return ret; +	} + +	spin_lock_irqsave(&ctrl->lock, flags); + +	/* We are half duplex, so either rx or tx will be set */ +	if (xfer->rx_buf) { +		ctrl->xfer.dir = QSPI_READ; +		ctrl->xfer.buswidth = xfer->rx_nbits; +		ctrl->xfer.rx_buf = xfer->rx_buf; +	} else { +		ctrl->xfer.dir = QSPI_WRITE; +		ctrl->xfer.buswidth = xfer->tx_nbits; +		ctrl->xfer.tx_buf = xfer->tx_buf; +	} +	ctrl->xfer.is_last = list_is_last(&xfer->transfer_list, +					  &master->cur_msg->transfers); +	ctrl->xfer.rem_bytes = xfer->len; +	qcom_qspi_pio_xfer(ctrl); + +	spin_unlock_irqrestore(&ctrl->lock, flags); + +	/* We'll call spi_finalize_current_transfer() when done */ +	return 1; +} + +static int qcom_qspi_prepare_message(struct spi_master *master, +				     struct spi_message *message) +{ +	u32 mstr_cfg; +	struct qcom_qspi *ctrl; +	int tx_data_oe_delay = 1; +	int tx_data_delay = 1; +	unsigned long flags; + +	ctrl = spi_master_get_devdata(master); +	spin_lock_irqsave(&ctrl->lock, flags); + +	mstr_cfg = readl(ctrl->base + MSTR_CONFIG); +	mstr_cfg &= ~CHIP_SELECT_NUM; +	if (message->spi->chip_select) +		mstr_cfg |= CHIP_SELECT_NUM; + +	mstr_cfg |= FB_CLK_EN | PIN_WPN | PIN_HOLDN | SBL_EN | FULL_CYCLE_MODE; +	mstr_cfg &= ~(SPI_MODE_MSK | TX_DATA_OE_DELAY_MSK | TX_DATA_DELAY_MSK); +	mstr_cfg |= message->spi->mode << SPI_MODE_SHFT; +	mstr_cfg |= tx_data_oe_delay << TX_DATA_OE_DELAY_SHFT; +	mstr_cfg |= tx_data_delay << TX_DATA_DELAY_SHFT; +	mstr_cfg &= ~DMA_ENABLE; + +	writel(mstr_cfg, ctrl->base + MSTR_CONFIG); +	spin_unlock_irqrestore(&ctrl->lock, flags); + +	return 0; +} + +static irqreturn_t pio_read(struct qcom_qspi *ctrl) +{ +	u32 rd_fifo_status; +	u32 rd_fifo; +	unsigned int wr_cnts; +	unsigned int bytes_to_read; +	unsigned int words_to_read; +	u32 *word_buf; +	u8 *byte_buf; +	int i; + +	rd_fifo_status = readl(ctrl->base + RD_FIFO_STATUS); + +	if (!(rd_fifo_status & FIFO_RDY)) { +		dev_dbg(ctrl->dev, "Spurious IRQ %#x\n", rd_fifo_status); +		return IRQ_NONE; +	} + +	wr_cnts = (rd_fifo_status & WR_CNTS_MSK) >> WR_CNTS_SHFT; +	wr_cnts = min(wr_cnts, ctrl->xfer.rem_bytes); + +	words_to_read = wr_cnts / QSPI_BYTES_PER_WORD; +	bytes_to_read = wr_cnts % QSPI_BYTES_PER_WORD; + +	if (words_to_read) { +		word_buf = ctrl->xfer.rx_buf; +		ctrl->xfer.rem_bytes -= words_to_read * QSPI_BYTES_PER_WORD; +		ioread32_rep(ctrl->base + RD_FIFO, word_buf, words_to_read); +		ctrl->xfer.rx_buf = word_buf + words_to_read; +	} + +	if (bytes_to_read) { +		byte_buf = ctrl->xfer.rx_buf; +		rd_fifo = readl(ctrl->base + RD_FIFO); +		ctrl->xfer.rem_bytes -= bytes_to_read; +		for (i = 0; i < bytes_to_read; i++) +			*byte_buf++ = rd_fifo >> (i * BITS_PER_BYTE); +		ctrl->xfer.rx_buf = byte_buf; +	} + +	return IRQ_HANDLED; +} + +static irqreturn_t pio_write(struct qcom_qspi *ctrl) +{ +	const void *xfer_buf = ctrl->xfer.tx_buf; +	const int *word_buf; +	const char *byte_buf; +	unsigned int wr_fifo_bytes; +	unsigned int wr_fifo_words; +	unsigned int wr_size; +	unsigned int rem_words; + +	wr_fifo_bytes = readl(ctrl->base + PIO_XFER_STATUS); +	wr_fifo_bytes >>= WR_FIFO_BYTES_SHFT; + +	if (ctrl->xfer.rem_bytes < QSPI_BYTES_PER_WORD) { +		/* Process the last 1-3 bytes */ +		wr_size = min(wr_fifo_bytes, ctrl->xfer.rem_bytes); +		ctrl->xfer.rem_bytes -= wr_size; + +		byte_buf = xfer_buf; +		while (wr_size--) +			writel(*byte_buf++, +			       ctrl->base + PIO_DATAOUT_1B); +		ctrl->xfer.tx_buf = byte_buf; +	} else { +		/* +		 * Process all the whole words; to keep things simple we'll +		 * just wait for the next interrupt to handle the last 1-3 +		 * bytes if we don't have an even number of words. +		 */ +		rem_words = ctrl->xfer.rem_bytes / QSPI_BYTES_PER_WORD; +		wr_fifo_words = wr_fifo_bytes / QSPI_BYTES_PER_WORD; + +		wr_size = min(rem_words, wr_fifo_words); +		ctrl->xfer.rem_bytes -= wr_size * QSPI_BYTES_PER_WORD; + +		word_buf = xfer_buf; +		iowrite32_rep(ctrl->base + PIO_DATAOUT_4B, word_buf, wr_size); +		ctrl->xfer.tx_buf = word_buf + wr_size; + +	} + +	return IRQ_HANDLED; +} + +static irqreturn_t qcom_qspi_irq(int irq, void *dev_id) +{ +	u32 int_status; +	struct qcom_qspi *ctrl = dev_id; +	irqreturn_t ret = IRQ_NONE; +	unsigned long flags; + +	spin_lock_irqsave(&ctrl->lock, flags); + +	int_status = readl(ctrl->base + MSTR_INT_STATUS); +	writel(int_status, ctrl->base + MSTR_INT_STATUS); + +	if (ctrl->xfer.dir == QSPI_WRITE) { +		if (int_status & WR_FIFO_EMPTY) +			ret = pio_write(ctrl); +	} else { +		if (int_status & RESP_FIFO_RDY) +			ret = pio_read(ctrl); +	} + +	if (int_status & QSPI_ERR_IRQS) { +		if (int_status & RESP_FIFO_UNDERRUN) +			dev_err(ctrl->dev, "IRQ error: FIFO underrun\n"); +		if (int_status & WR_FIFO_OVERRUN) +			dev_err(ctrl->dev, "IRQ error: FIFO overrun\n"); +		if (int_status & HRESP_FROM_NOC_ERR) +			dev_err(ctrl->dev, "IRQ error: NOC response error\n"); +		ret = IRQ_HANDLED; +	} + +	if (!ctrl->xfer.rem_bytes) { +		writel(0, ctrl->base + MSTR_INT_EN); +		spi_finalize_current_transfer(dev_get_drvdata(ctrl->dev)); +	} + +	spin_unlock_irqrestore(&ctrl->lock, flags); +	return ret; +} + +static int qcom_qspi_probe(struct platform_device *pdev) +{ +	int ret; +	struct device *dev; +	struct resource *res; +	struct spi_master *master; +	struct qcom_qspi *ctrl; + +	dev = &pdev->dev; + +	master = spi_alloc_master(dev, sizeof(*ctrl)); +	if (!master) +		return -ENOMEM; + +	platform_set_drvdata(pdev, master); + +	ctrl = spi_master_get_devdata(master); + +	spin_lock_init(&ctrl->lock); +	ctrl->dev = dev; +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	ctrl->base = devm_ioremap_resource(dev, res); +	if (IS_ERR(ctrl->base)) { +		ret = PTR_ERR(ctrl->base); +		goto exit_probe_master_put; +	} + +	ctrl->clks[QSPI_CLK_CORE].id = "core"; +	ctrl->clks[QSPI_CLK_IFACE].id = "iface"; +	ret = devm_clk_bulk_get(dev, QSPI_NUM_CLKS, ctrl->clks); +	if (ret) +		goto exit_probe_master_put; + +	ret = platform_get_irq(pdev, 0); +	if (ret < 0) { +		dev_err(dev, "Failed to get irq %d\n", ret); +		goto exit_probe_master_put; +	} +	ret = devm_request_irq(dev, ret, qcom_qspi_irq, +			IRQF_TRIGGER_HIGH, dev_name(dev), ctrl); +	if (ret) { +		dev_err(dev, "Failed to request irq %d\n", ret); +		goto exit_probe_master_put; +	} + +	master->max_speed_hz = 300000000; +	master->num_chipselect = QSPI_NUM_CS; +	master->bus_num = -1; +	master->dev.of_node = pdev->dev.of_node; +	master->mode_bits = SPI_MODE_0 | +			    SPI_TX_DUAL | SPI_RX_DUAL | +			    SPI_TX_QUAD | SPI_RX_QUAD; +	master->flags = SPI_MASTER_HALF_DUPLEX; +	master->prepare_message = qcom_qspi_prepare_message; +	master->transfer_one = qcom_qspi_transfer_one; +	master->handle_err = qcom_qspi_handle_err; +	master->auto_runtime_pm = true; + +	pm_runtime_enable(dev); + +	ret = spi_register_master(master); +	if (!ret) +		return 0; + +	pm_runtime_disable(dev); + +exit_probe_master_put: +	spi_master_put(master); + +	return ret; +} + +static int qcom_qspi_remove(struct platform_device *pdev) +{ +	struct spi_master *master = platform_get_drvdata(pdev); + +	/* Unregister _before_ disabling pm_runtime() so we stop transfers */ +	spi_unregister_master(master); + +	pm_runtime_disable(&pdev->dev); + +	return 0; +} + +static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev) +{ +	struct spi_master *master = dev_get_drvdata(dev); +	struct qcom_qspi *ctrl = spi_master_get_devdata(master); + +	clk_bulk_disable_unprepare(QSPI_NUM_CLKS, ctrl->clks); + +	return 0; +} + +static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev) +{ +	struct spi_master *master = dev_get_drvdata(dev); +	struct qcom_qspi *ctrl = spi_master_get_devdata(master); + +	return clk_bulk_prepare_enable(QSPI_NUM_CLKS, ctrl->clks); +} + +static int __maybe_unused qcom_qspi_suspend(struct device *dev) +{ +	struct spi_master *master = dev_get_drvdata(dev); +	int ret; + +	ret = spi_master_suspend(master); +	if (ret) +		return ret; + +	ret = pm_runtime_force_suspend(dev); +	if (ret) +		spi_master_resume(master); + +	return ret; +} + +static int __maybe_unused qcom_qspi_resume(struct device *dev) +{ +	struct spi_master *master = dev_get_drvdata(dev); +	int ret; + +	ret = pm_runtime_force_resume(dev); +	if (ret) +		return ret; + +	ret = spi_master_resume(master); +	if (ret) +		pm_runtime_force_suspend(dev); + +	return ret; +} + +static const struct dev_pm_ops qcom_qspi_dev_pm_ops = { +	SET_RUNTIME_PM_OPS(qcom_qspi_runtime_suspend, +			   qcom_qspi_runtime_resume, NULL) +	SET_SYSTEM_SLEEP_PM_OPS(qcom_qspi_suspend, qcom_qspi_resume) +}; + +static const struct of_device_id qcom_qspi_dt_match[] = { +	{ .compatible = "qcom,qspi-v1", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, qcom_qspi_dt_match); + +static struct platform_driver qcom_qspi_driver = { +	.driver = { +		.name		= "qcom_qspi", +		.pm		= &qcom_qspi_dev_pm_ops, +		.of_match_table = qcom_qspi_dt_match, +	}, +	.probe = qcom_qspi_probe, +	.remove = qcom_qspi_remove, +}; +module_platform_driver(qcom_qspi_driver); + +MODULE_DESCRIPTION("SPI driver for QSPI cores"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c index 3641d0e20135..fbbf9a188247 100644 --- a/drivers/spi/spi-rb4xx.c +++ b/drivers/spi/spi-rb4xx.c @@ -159,7 +159,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev)  	master->bus_num = 0;  	master->num_chipselect = 3;  	master->mode_bits = SPI_TX_DUAL; -	master->bits_per_word_mask = BIT(7); +	master->bits_per_word_mask = SPI_BPW_MASK(8);  	master->flags = SPI_MASTER_MUST_TX;  	master->transfer_one = rb4xx_transfer_one;  	master->set_cs = rb4xx_set_cs; diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index fdcf3076681b..51ef632bca52 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -164,7 +164,6 @@ enum rockchip_ssi_type {  struct rockchip_spi_dma_data {  	struct dma_chan *ch; -	enum dma_transfer_direction direction;  	dma_addr_t addr;  }; @@ -202,12 +201,11 @@ struct rockchip_spi {  	bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM]; -	u32 use_dma; +	bool use_dma;  	struct sg_table tx_sg;  	struct sg_table rx_sg;  	struct rockchip_spi_dma_data dma_rx;  	struct rockchip_spi_dma_data dma_tx; -	struct dma_slave_caps dma_caps;  };  static inline void spi_enable_chip(struct rockchip_spi *rs, int enable) @@ -381,6 +379,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)  {  	int remain = 0; +	spi_enable_chip(rs, 1); +  	do {  		if (rs->tx) {  			remain = rs->tx_end - rs->tx; @@ -445,6 +445,9 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)  	struct dma_slave_config rxconf, txconf;  	struct dma_async_tx_descriptor *rxdesc, *txdesc; +	memset(&rxconf, 0, sizeof(rxconf)); +	memset(&txconf, 0, sizeof(txconf)); +  	spin_lock_irqsave(&rs->lock, flags);  	rs->state &= ~RXBUSY;  	rs->state &= ~TXBUSY; @@ -452,19 +455,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)  	rxdesc = NULL;  	if (rs->rx) { -		rxconf.direction = rs->dma_rx.direction; +		rxconf.direction = DMA_DEV_TO_MEM;  		rxconf.src_addr = rs->dma_rx.addr;  		rxconf.src_addr_width = rs->n_bytes; -		if (rs->dma_caps.max_burst > 4) -			rxconf.src_maxburst = 4; -		else -			rxconf.src_maxburst = 1; +		rxconf.src_maxburst = 1;  		dmaengine_slave_config(rs->dma_rx.ch, &rxconf);  		rxdesc = dmaengine_prep_slave_sg(  				rs->dma_rx.ch,  				rs->rx_sg.sgl, rs->rx_sg.nents, -				rs->dma_rx.direction, DMA_PREP_INTERRUPT); +				DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);  		if (!rxdesc)  			return -EINVAL; @@ -474,19 +474,16 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)  	txdesc = NULL;  	if (rs->tx) { -		txconf.direction = rs->dma_tx.direction; +		txconf.direction = DMA_MEM_TO_DEV;  		txconf.dst_addr = rs->dma_tx.addr;  		txconf.dst_addr_width = rs->n_bytes; -		if (rs->dma_caps.max_burst > 4) -			txconf.dst_maxburst = 4; -		else -			txconf.dst_maxburst = 1; +		txconf.dst_maxburst = rs->fifo_len / 2;  		dmaengine_slave_config(rs->dma_tx.ch, &txconf);  		txdesc = dmaengine_prep_slave_sg(  				rs->dma_tx.ch,  				rs->tx_sg.sgl, rs->tx_sg.nents, -				rs->dma_tx.direction, DMA_PREP_INTERRUPT); +				DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);  		if (!txdesc) {  			if (rxdesc)  				dmaengine_terminate_sync(rs->dma_rx.ch); @@ -506,6 +503,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)  		dma_async_issue_pending(rs->dma_rx.ch);  	} +	spi_enable_chip(rs, 1); +  	if (txdesc) {  		spin_lock_irqsave(&rs->lock, flags);  		rs->state |= TXBUSY; @@ -514,7 +513,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)  		dma_async_issue_pending(rs->dma_tx.ch);  	} -	return 0; +	/* 1 means the transfer is in progress */ +	return 1;  }  static void rockchip_spi_config(struct rockchip_spi *rs) @@ -578,7 +578,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)  	writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);  	writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); -	writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMATDLR); +	writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);  	writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);  	writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); @@ -597,7 +597,6 @@ static int rockchip_spi_transfer_one(  		struct spi_device *spi,  		struct spi_transfer *xfer)  { -	int ret = 0;  	struct rockchip_spi *rs = spi_master_get_devdata(master);  	WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && @@ -635,30 +634,16 @@ static int rockchip_spi_transfer_one(  	/* we need prepare dma before spi was enabled */  	if (master->can_dma && master->can_dma(master, spi, xfer)) -		rs->use_dma = 1; +		rs->use_dma = true;  	else -		rs->use_dma = 0; +		rs->use_dma = false;  	rockchip_spi_config(rs); -	if (rs->use_dma) { -		if (rs->tmode == CR0_XFM_RO) { -			/* rx: dma must be prepared first */ -			ret = rockchip_spi_prepare_dma(rs); -			spi_enable_chip(rs, 1); -		} else { -			/* tx or tr: spi must be enabled first */ -			spi_enable_chip(rs, 1); -			ret = rockchip_spi_prepare_dma(rs); -		} -		/* successful DMA prepare means the transfer is in progress */ -		ret = ret ? ret : 1; -	} else { -		spi_enable_chip(rs, 1); -		ret = rockchip_spi_pio_transfer(rs); -	} +	if (rs->use_dma) +		return rockchip_spi_prepare_dma(rs); -	return ret; +	return rockchip_spi_pio_transfer(rs);  }  static bool rockchip_spi_can_dma(struct spi_master *master, @@ -780,11 +765,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)  	}  	if (rs->dma_tx.ch && rs->dma_rx.ch) { -		dma_get_slave_caps(rs->dma_rx.ch, &(rs->dma_caps));  		rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);  		rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR); -		rs->dma_tx.direction = DMA_MEM_TO_DEV; -		rs->dma_rx.direction = DMA_DEV_TO_MEM;  		master->can_dma = rockchip_spi_can_dma;  		master->dma_tx = rs->dma_tx.ch; diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index b37de1d991d6..55f8e55327b3 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * SH RSPI driver   * @@ -6,15 +7,6 @@   *   * Based on spi-sh.c:   * Copyright (C) 2011 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details.   */  #include <linux/module.h> diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 20e800e70442..dc0926e43665 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * SuperH HSPI bus driver   * @@ -7,15 +8,6 @@   * Based on pxa2xx_spi.c:   * Copyright (C) 2011 Renesas Solutions Corp.   * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details.   */  #include <linux/clk.h> @@ -316,6 +308,6 @@ static struct platform_driver hspi_driver = {  module_platform_driver(hspi_driver);  MODULE_DESCRIPTION("SuperH HSPI bus driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2");  MODULE_AUTHOR("Kuninori Morimoto <[email protected]>");  MODULE_ALIAS("platform:sh-hspi"); diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 101cd6aae2ea..adf384323934 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * SuperH MSIOF SPI Master Interface   *   * Copyright (c) 2009 Magnus Damm   * Copyright (C) 2014 Renesas Electronics Corporation   * Copyright (C) 2014-2017 Glider bvba - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - *   */  #include <linux/bitmap.h> @@ -1343,8 +1339,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)  	i = platform_get_irq(pdev, 0);  	if (i < 0) { -		dev_err(&pdev->dev, "cannot get platform IRQ\n"); -		ret = -ENOENT; +		dev_err(&pdev->dev, "cannot get IRQ\n"); +		ret = i;  		goto err1;  	} diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 50e0ea9acf8b..f1ee58208216 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * SH SPI bus driver   * @@ -5,15 +6,6 @@   *   * Based on pxa2xx_spi.c:   * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details.   */  #include <linux/module.h> @@ -522,6 +514,6 @@ static struct platform_driver spi_sh_driver = {  module_platform_driver(spi_sh_driver);  MODULE_DESCRIPTION("SH SPI bus driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2");  MODULE_AUTHOR("Yoshihiro Shimoda");  MODULE_ALIAS("platform:sh_spi"); diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c new file mode 100644 index 000000000000..d1075433f6a6 --- /dev/null +++ b/drivers/spi/spi-slave-mt27xx.c @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2018 MediaTek Inc. + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> + +#define SPIS_IRQ_EN_REG		0x0 +#define SPIS_IRQ_CLR_REG	0x4 +#define SPIS_IRQ_ST_REG		0x8 +#define SPIS_IRQ_MASK_REG	0xc +#define SPIS_CFG_REG		0x10 +#define SPIS_RX_DATA_REG	0x14 +#define SPIS_TX_DATA_REG	0x18 +#define SPIS_RX_DST_REG		0x1c +#define SPIS_TX_SRC_REG		0x20 +#define SPIS_DMA_CFG_REG	0x30 +#define SPIS_SOFT_RST_REG	0x40 + +/* SPIS_IRQ_EN_REG */ +#define DMA_DONE_EN		BIT(7) +#define DATA_DONE_EN		BIT(2) +#define RSTA_DONE_EN		BIT(1) +#define CMD_INVALID_EN		BIT(0) + +/* SPIS_IRQ_ST_REG */ +#define DMA_DONE_ST		BIT(7) +#define DATA_DONE_ST		BIT(2) +#define RSTA_DONE_ST		BIT(1) +#define CMD_INVALID_ST		BIT(0) + +/* SPIS_IRQ_MASK_REG */ +#define DMA_DONE_MASK		BIT(7) +#define DATA_DONE_MASK		BIT(2) +#define RSTA_DONE_MASK		BIT(1) +#define CMD_INVALID_MASK	BIT(0) + +/* SPIS_CFG_REG */ +#define SPIS_TX_ENDIAN		BIT(7) +#define SPIS_RX_ENDIAN		BIT(6) +#define SPIS_TXMSBF		BIT(5) +#define SPIS_RXMSBF		BIT(4) +#define SPIS_CPHA		BIT(3) +#define SPIS_CPOL		BIT(2) +#define SPIS_TX_EN		BIT(1) +#define SPIS_RX_EN		BIT(0) + +/* SPIS_DMA_CFG_REG */ +#define TX_DMA_TRIG_EN		BIT(31) +#define TX_DMA_EN		BIT(30) +#define RX_DMA_EN		BIT(29) +#define TX_DMA_LEN		0xfffff + +/* SPIS_SOFT_RST_REG */ +#define SPIS_DMA_ADDR_EN	BIT(1) +#define SPIS_SOFT_RST		BIT(0) + +#define MTK_SPI_SLAVE_MAX_FIFO_SIZE 512U + +struct mtk_spi_slave { +	struct device *dev; +	void __iomem *base; +	struct clk *spi_clk; +	struct completion xfer_done; +	struct spi_transfer *cur_transfer; +	bool slave_aborted; +}; + +static const struct of_device_id mtk_spi_slave_of_match[] = { +	{ .compatible = "mediatek,mt2712-spi-slave", }, +	{} +}; +MODULE_DEVICE_TABLE(of, mtk_spi_slave_of_match); + +static void mtk_spi_slave_disable_dma(struct mtk_spi_slave *mdata) +{ +	u32 reg_val; + +	reg_val = readl(mdata->base + SPIS_DMA_CFG_REG); +	reg_val &= ~RX_DMA_EN; +	reg_val &= ~TX_DMA_EN; +	writel(reg_val, mdata->base + SPIS_DMA_CFG_REG); +} + +static void mtk_spi_slave_disable_xfer(struct mtk_spi_slave *mdata) +{ +	u32 reg_val; + +	reg_val = readl(mdata->base + SPIS_CFG_REG); +	reg_val &= ~SPIS_TX_EN; +	reg_val &= ~SPIS_RX_EN; +	writel(reg_val, mdata->base + SPIS_CFG_REG); +} + +static int mtk_spi_slave_wait_for_completion(struct mtk_spi_slave *mdata) +{ +	if (wait_for_completion_interruptible(&mdata->xfer_done) || +	    mdata->slave_aborted) { +		dev_err(mdata->dev, "interrupted\n"); +		return -EINTR; +	} + +	return 0; +} + +static int mtk_spi_slave_prepare_message(struct spi_controller *ctlr, +					 struct spi_message *msg) +{ +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); +	struct spi_device *spi = msg->spi; +	bool cpha, cpol; +	u32 reg_val; + +	cpha = spi->mode & SPI_CPHA ? 1 : 0; +	cpol = spi->mode & SPI_CPOL ? 1 : 0; + +	reg_val = readl(mdata->base + SPIS_CFG_REG); +	if (cpha) +		reg_val |= SPIS_CPHA; +	else +		reg_val &= ~SPIS_CPHA; +	if (cpol) +		reg_val |= SPIS_CPOL; +	else +		reg_val &= ~SPIS_CPOL; + +	if (spi->mode & SPI_LSB_FIRST) +		reg_val &= ~(SPIS_TXMSBF | SPIS_RXMSBF); +	else +		reg_val |= SPIS_TXMSBF | SPIS_RXMSBF; + +	reg_val &= ~SPIS_TX_ENDIAN; +	reg_val &= ~SPIS_RX_ENDIAN; +	writel(reg_val, mdata->base + SPIS_CFG_REG); + +	return 0; +} + +static int mtk_spi_slave_fifo_transfer(struct spi_controller *ctlr, +				       struct spi_device *spi, +				       struct spi_transfer *xfer) +{ +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); +	int reg_val, cnt, remainder, ret; + +	writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + +	reg_val = readl(mdata->base + SPIS_CFG_REG); +	if (xfer->rx_buf) +		reg_val |= SPIS_RX_EN; +	if (xfer->tx_buf) +		reg_val |= SPIS_TX_EN; +	writel(reg_val, mdata->base + SPIS_CFG_REG); + +	cnt = xfer->len / 4; +	if (xfer->tx_buf) +		iowrite32_rep(mdata->base + SPIS_TX_DATA_REG, +			      xfer->tx_buf, cnt); + +	remainder = xfer->len % 4; +	if (xfer->tx_buf && remainder > 0) { +		reg_val = 0; +		memcpy(®_val, xfer->tx_buf + cnt * 4, remainder); +		writel(reg_val, mdata->base + SPIS_TX_DATA_REG); +	} + +	ret = mtk_spi_slave_wait_for_completion(mdata); +	if (ret) { +		mtk_spi_slave_disable_xfer(mdata); +		writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); +	} + +	return ret; +} + +static int mtk_spi_slave_dma_transfer(struct spi_controller *ctlr, +				      struct spi_device *spi, +				      struct spi_transfer *xfer) +{ +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); +	struct device *dev = mdata->dev; +	int reg_val, ret; + +	writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + +	if (xfer->tx_buf) { +		/* tx_buf is a const void* where we need a void * for +		 * the dma mapping +		 */ +		void *nonconst_tx = (void *)xfer->tx_buf; + +		xfer->tx_dma = dma_map_single(dev, nonconst_tx, +					      xfer->len, DMA_TO_DEVICE); +		if (dma_mapping_error(dev, xfer->tx_dma)) { +			ret = -ENOMEM; +			goto disable_transfer; +		} +	} + +	if (xfer->rx_buf) { +		xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, +					      xfer->len, DMA_FROM_DEVICE); +		if (dma_mapping_error(dev, xfer->rx_dma)) { +			ret = -ENOMEM; +			goto unmap_txdma; +		} +	} + +	writel(xfer->tx_dma, mdata->base + SPIS_TX_SRC_REG); +	writel(xfer->rx_dma, mdata->base + SPIS_RX_DST_REG); + +	writel(SPIS_DMA_ADDR_EN, mdata->base + SPIS_SOFT_RST_REG); + +	/* enable config reg tx rx_enable */ +	reg_val = readl(mdata->base + SPIS_CFG_REG); +	if (xfer->tx_buf) +		reg_val |= SPIS_TX_EN; +	if (xfer->rx_buf) +		reg_val |= SPIS_RX_EN; +	writel(reg_val, mdata->base + SPIS_CFG_REG); + +	/* config dma */ +	reg_val = 0; +	reg_val |= (xfer->len - 1) & TX_DMA_LEN; +	writel(reg_val, mdata->base + SPIS_DMA_CFG_REG); + +	reg_val = readl(mdata->base + SPIS_DMA_CFG_REG); +	if (xfer->tx_buf) +		reg_val |= TX_DMA_EN; +	if (xfer->rx_buf) +		reg_val |= RX_DMA_EN; +	reg_val |= TX_DMA_TRIG_EN; +	writel(reg_val, mdata->base + SPIS_DMA_CFG_REG); + +	ret = mtk_spi_slave_wait_for_completion(mdata); +	if (ret) +		goto unmap_rxdma; + +	return 0; + +unmap_rxdma: +	if (xfer->rx_buf) +		dma_unmap_single(dev, xfer->rx_dma, +				 xfer->len, DMA_FROM_DEVICE); + +unmap_txdma: +	if (xfer->tx_buf) +		dma_unmap_single(dev, xfer->tx_dma, +				 xfer->len, DMA_TO_DEVICE); + +disable_transfer: +	mtk_spi_slave_disable_dma(mdata); +	mtk_spi_slave_disable_xfer(mdata); +	writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + +	return ret; +} + +static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr, +				      struct spi_device *spi, +				      struct spi_transfer *xfer) +{ +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + +	reinit_completion(&mdata->xfer_done); +	mdata->slave_aborted = false; +	mdata->cur_transfer = xfer; + +	if (xfer->len > MTK_SPI_SLAVE_MAX_FIFO_SIZE) +		return mtk_spi_slave_dma_transfer(ctlr, spi, xfer); +	else +		return mtk_spi_slave_fifo_transfer(ctlr, spi, xfer); +} + +static int mtk_spi_slave_setup(struct spi_device *spi) +{ +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(spi->master); +	u32 reg_val; + +	reg_val = DMA_DONE_EN | DATA_DONE_EN | +		  RSTA_DONE_EN | CMD_INVALID_EN; +	writel(reg_val, mdata->base + SPIS_IRQ_EN_REG); + +	reg_val = DMA_DONE_MASK | DATA_DONE_MASK | +		  RSTA_DONE_MASK | CMD_INVALID_MASK; +	writel(reg_val, mdata->base + SPIS_IRQ_MASK_REG); + +	mtk_spi_slave_disable_dma(mdata); +	mtk_spi_slave_disable_xfer(mdata); + +	return 0; +} + +static int mtk_slave_abort(struct spi_controller *ctlr) +{ +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + +	mdata->slave_aborted = true; +	complete(&mdata->xfer_done); + +	return 0; +} + +static irqreturn_t mtk_spi_slave_interrupt(int irq, void *dev_id) +{ +	struct spi_controller *ctlr = dev_id; +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); +	struct spi_transfer *trans = mdata->cur_transfer; +	u32 int_status, reg_val, cnt, remainder; + +	int_status = readl(mdata->base + SPIS_IRQ_ST_REG); +	writel(int_status, mdata->base + SPIS_IRQ_CLR_REG); + +	if (!trans) +		return IRQ_NONE; + +	if ((int_status & DMA_DONE_ST) && +	    ((int_status & DATA_DONE_ST) || +	    (int_status & RSTA_DONE_ST))) { +		writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG); + +		if (trans->tx_buf) +			dma_unmap_single(mdata->dev, trans->tx_dma, +					 trans->len, DMA_TO_DEVICE); +		if (trans->rx_buf) +			dma_unmap_single(mdata->dev, trans->rx_dma, +					 trans->len, DMA_FROM_DEVICE); + +		mtk_spi_slave_disable_dma(mdata); +		mtk_spi_slave_disable_xfer(mdata); +	} + +	if ((!(int_status & DMA_DONE_ST)) && +	    ((int_status & DATA_DONE_ST) || +	    (int_status & RSTA_DONE_ST))) { +		cnt = trans->len / 4; +		if (trans->rx_buf) +			ioread32_rep(mdata->base + SPIS_RX_DATA_REG, +				     trans->rx_buf, cnt); +		remainder = trans->len % 4; +		if (trans->rx_buf && remainder > 0) { +			reg_val = readl(mdata->base + SPIS_RX_DATA_REG); +			memcpy(trans->rx_buf + (cnt * 4), +			       ®_val, remainder); +		} + +		mtk_spi_slave_disable_xfer(mdata); +	} + +	if (int_status & CMD_INVALID_ST) { +		dev_warn(&ctlr->dev, "cmd invalid\n"); +		return IRQ_NONE; +	} + +	mdata->cur_transfer = NULL; +	complete(&mdata->xfer_done); + +	return IRQ_HANDLED; +} + +static int mtk_spi_slave_probe(struct platform_device *pdev) +{ +	struct spi_controller *ctlr; +	struct mtk_spi_slave *mdata; +	struct resource *res; +	int irq, ret; + +	ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata)); +	if (!ctlr) { +		dev_err(&pdev->dev, "failed to alloc spi slave\n"); +		return -ENOMEM; +	} + +	ctlr->auto_runtime_pm = true; +	ctlr->dev.of_node = pdev->dev.of_node; +	ctlr->mode_bits = SPI_CPOL | SPI_CPHA; +	ctlr->mode_bits |= SPI_LSB_FIRST; + +	ctlr->prepare_message = mtk_spi_slave_prepare_message; +	ctlr->transfer_one = mtk_spi_slave_transfer_one; +	ctlr->setup = mtk_spi_slave_setup; +	ctlr->slave_abort = mtk_slave_abort; + +	mdata = spi_controller_get_devdata(ctlr); + +	platform_set_drvdata(pdev, ctlr); + +	init_completion(&mdata->xfer_done); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!res) { +		ret = -ENODEV; +		dev_err(&pdev->dev, "failed to determine base address\n"); +		goto err_put_ctlr; +	} + +	mdata->dev = &pdev->dev; + +	mdata->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(mdata->base)) { +		ret = PTR_ERR(mdata->base); +		goto err_put_ctlr; +	} + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "failed to get irq (%d)\n", irq); +		ret = irq; +		goto err_put_ctlr; +	} + +	ret = devm_request_irq(&pdev->dev, irq, mtk_spi_slave_interrupt, +			       IRQF_TRIGGER_NONE, dev_name(&pdev->dev), ctlr); +	if (ret) { +		dev_err(&pdev->dev, "failed to register irq (%d)\n", ret); +		goto err_put_ctlr; +	} + +	mdata->spi_clk = devm_clk_get(&pdev->dev, "spi"); +	if (IS_ERR(mdata->spi_clk)) { +		ret = PTR_ERR(mdata->spi_clk); +		dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret); +		goto err_put_ctlr; +	} + +	ret = clk_prepare_enable(mdata->spi_clk); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret); +		goto err_put_ctlr; +	} + +	pm_runtime_enable(&pdev->dev); + +	ret = devm_spi_register_controller(&pdev->dev, ctlr); +	if (ret) { +		dev_err(&pdev->dev, +			"failed to register slave controller(%d)\n", ret); +		clk_disable_unprepare(mdata->spi_clk); +		goto err_disable_runtime_pm; +	} + +	clk_disable_unprepare(mdata->spi_clk); + +	return 0; + +err_disable_runtime_pm: +	pm_runtime_disable(&pdev->dev); +err_put_ctlr: +	spi_controller_put(ctlr); + +	return ret; +} + +static int mtk_spi_slave_remove(struct platform_device *pdev) +{ +	pm_runtime_disable(&pdev->dev); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mtk_spi_slave_suspend(struct device *dev) +{ +	struct spi_controller *ctlr = dev_get_drvdata(dev); +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); +	int ret; + +	ret = spi_controller_suspend(ctlr); +	if (ret) +		return ret; + +	if (!pm_runtime_suspended(dev)) +		clk_disable_unprepare(mdata->spi_clk); + +	return ret; +} + +static int mtk_spi_slave_resume(struct device *dev) +{ +	struct spi_controller *ctlr = dev_get_drvdata(dev); +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); +	int ret; + +	if (!pm_runtime_suspended(dev)) { +		ret = clk_prepare_enable(mdata->spi_clk); +		if (ret < 0) { +			dev_err(dev, "failed to enable spi_clk (%d)\n", ret); +			return ret; +		} +	} + +	ret = spi_controller_resume(ctlr); +	if (ret < 0) +		clk_disable_unprepare(mdata->spi_clk); + +	return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int mtk_spi_slave_runtime_suspend(struct device *dev) +{ +	struct spi_controller *ctlr = dev_get_drvdata(dev); +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); + +	clk_disable_unprepare(mdata->spi_clk); + +	return 0; +} + +static int mtk_spi_slave_runtime_resume(struct device *dev) +{ +	struct spi_controller *ctlr = dev_get_drvdata(dev); +	struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr); +	int ret; + +	ret = clk_prepare_enable(mdata->spi_clk); +	if (ret < 0) { +		dev_err(dev, "failed to enable spi_clk (%d)\n", ret); +		return ret; +	} + +	return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops mtk_spi_slave_pm = { +	SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_slave_suspend, mtk_spi_slave_resume) +	SET_RUNTIME_PM_OPS(mtk_spi_slave_runtime_suspend, +			   mtk_spi_slave_runtime_resume, NULL) +}; + +static struct platform_driver mtk_spi_slave_driver = { +	.driver = { +		.name = "mtk-spi-slave", +		.pm	= &mtk_spi_slave_pm, +		.of_match_table = mtk_spi_slave_of_match, +	}, +	.probe = mtk_spi_slave_probe, +	.remove = mtk_spi_slave_remove, +}; + +module_platform_driver(mtk_spi_slave_driver); + +MODULE_DESCRIPTION("MTK SPI Slave Controller driver"); +MODULE_AUTHOR("Leilk Liu <[email protected]>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mtk-spi-slave"); diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c index c0257e937995..169f3d595f60 100644 --- a/drivers/spi/spi-slave-system-control.c +++ b/drivers/spi/spi-slave-system-control.c @@ -60,6 +60,7 @@ static void spi_slave_system_control_complete(void *arg)  	case CMD_REBOOT:  		dev_info(&priv->spi->dev, "Rebooting system...\n");  		kernel_restart(NULL); +		break;  	case CMD_POWEROFF:  		dev_info(&priv->spi->dev, "Powering off system...\n"); diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c new file mode 100644 index 000000000000..8daa24eec624 --- /dev/null +++ b/drivers/spi/spi-sprd.c @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2018 Spreadtrum Communications Inc. + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> + +#define SPRD_SPI_TXD			0x0 +#define SPRD_SPI_CLKD			0x4 +#define SPRD_SPI_CTL0			0x8 +#define SPRD_SPI_CTL1			0xc +#define SPRD_SPI_CTL2			0x10 +#define SPRD_SPI_CTL3			0x14 +#define SPRD_SPI_CTL4			0x18 +#define SPRD_SPI_CTL5			0x1c +#define SPRD_SPI_INT_EN			0x20 +#define SPRD_SPI_INT_CLR		0x24 +#define SPRD_SPI_INT_RAW_STS		0x28 +#define SPRD_SPI_INT_MASK_STS		0x2c +#define SPRD_SPI_STS1			0x30 +#define SPRD_SPI_STS2			0x34 +#define SPRD_SPI_DSP_WAIT		0x38 +#define SPRD_SPI_STS3			0x3c +#define SPRD_SPI_CTL6			0x40 +#define SPRD_SPI_STS4			0x44 +#define SPRD_SPI_FIFO_RST		0x48 +#define SPRD_SPI_CTL7			0x4c +#define SPRD_SPI_STS5			0x50 +#define SPRD_SPI_CTL8			0x54 +#define SPRD_SPI_CTL9			0x58 +#define SPRD_SPI_CTL10			0x5c +#define SPRD_SPI_CTL11			0x60 +#define SPRD_SPI_CTL12			0x64 +#define SPRD_SPI_STS6			0x68 +#define SPRD_SPI_STS7			0x6c +#define SPRD_SPI_STS8			0x70 +#define SPRD_SPI_STS9			0x74 + +/* Bits & mask definition for register CTL0 */ +#define SPRD_SPI_SCK_REV		BIT(13) +#define SPRD_SPI_NG_TX			BIT(1) +#define SPRD_SPI_NG_RX			BIT(0) +#define SPRD_SPI_CHNL_LEN_MASK		GENMASK(4, 0) +#define SPRD_SPI_CSN_MASK		GENMASK(11, 8) +#define SPRD_SPI_CS0_VALID		BIT(8) + +/* Bits & mask definition for register SPI_INT_EN */ +#define SPRD_SPI_TX_END_INT_EN		BIT(8) +#define SPRD_SPI_RX_END_INT_EN		BIT(9) + +/* Bits & mask definition for register SPI_INT_RAW_STS */ +#define SPRD_SPI_TX_END_RAW		BIT(8) +#define SPRD_SPI_RX_END_RAW		BIT(9) + +/* Bits & mask definition for register SPI_INT_CLR */ +#define SPRD_SPI_TX_END_CLR		BIT(8) +#define SPRD_SPI_RX_END_CLR		BIT(9) + +/* Bits & mask definition for register INT_MASK_STS */ +#define SPRD_SPI_MASK_RX_END		BIT(9) +#define SPRD_SPI_MASK_TX_END		BIT(8) + +/* Bits & mask definition for register STS2 */ +#define SPRD_SPI_TX_BUSY		BIT(8) + +/* Bits & mask definition for register CTL1 */ +#define SPRD_SPI_RX_MODE		BIT(12) +#define SPRD_SPI_TX_MODE		BIT(13) +#define SPRD_SPI_RTX_MD_MASK		GENMASK(13, 12) + +/* Bits & mask definition for register CTL2 */ +#define SPRD_SPI_DMA_EN			BIT(6) + +/* Bits & mask definition for register CTL4 */ +#define SPRD_SPI_START_RX		BIT(9) +#define SPRD_SPI_ONLY_RECV_MASK		GENMASK(8, 0) + +/* Bits & mask definition for register SPI_INT_CLR */ +#define SPRD_SPI_RX_END_INT_CLR		BIT(9) +#define SPRD_SPI_TX_END_INT_CLR		BIT(8) + +/* Bits & mask definition for register SPI_INT_RAW */ +#define SPRD_SPI_RX_END_IRQ		BIT(9) +#define SPRD_SPI_TX_END_IRQ		BIT(8) + +/* Bits & mask definition for register CTL12 */ +#define SPRD_SPI_SW_RX_REQ		BIT(0) +#define SPRD_SPI_SW_TX_REQ		BIT(1) + +/* Bits & mask definition for register CTL7 */ +#define SPRD_SPI_DATA_LINE2_EN		BIT(15) +#define SPRD_SPI_MODE_MASK		GENMASK(5, 3) +#define SPRD_SPI_MODE_OFFSET		3 +#define SPRD_SPI_3WIRE_MODE		4 +#define SPRD_SPI_4WIRE_MODE		0 + +/* Bits & mask definition for register CTL8 */ +#define SPRD_SPI_TX_MAX_LEN_MASK	GENMASK(19, 0) +#define SPRD_SPI_TX_LEN_H_MASK		GENMASK(3, 0) +#define SPRD_SPI_TX_LEN_H_OFFSET	16 + +/* Bits & mask definition for register CTL9 */ +#define SPRD_SPI_TX_LEN_L_MASK		GENMASK(15, 0) + +/* Bits & mask definition for register CTL10 */ +#define SPRD_SPI_RX_MAX_LEN_MASK	GENMASK(19, 0) +#define SPRD_SPI_RX_LEN_H_MASK		GENMASK(3, 0) +#define SPRD_SPI_RX_LEN_H_OFFSET	16 + +/* Bits & mask definition for register CTL11 */ +#define SPRD_SPI_RX_LEN_L_MASK		GENMASK(15, 0) + +/* Default & maximum word delay cycles */ +#define SPRD_SPI_MIN_DELAY_CYCLE	14 +#define SPRD_SPI_MAX_DELAY_CYCLE	130 + +#define SPRD_SPI_FIFO_SIZE		32 +#define SPRD_SPI_CHIP_CS_NUM		0x4 +#define SPRD_SPI_CHNL_LEN		2 +#define SPRD_SPI_DEFAULT_SOURCE		26000000 +#define SPRD_SPI_MAX_SPEED_HZ		48000000 +#define SPRD_SPI_AUTOSUSPEND_DELAY	100 + +struct sprd_spi { +	void __iomem *base; +	struct device *dev; +	struct clk *clk; +	u32 src_clk; +	u32 hw_mode; +	u32 trans_len; +	u32 trans_mode; +	u32 word_delay; +	u32 hw_speed_hz; +	u32 len; +	int status; +	const void *tx_buf; +	void *rx_buf; +	int (*read_bufs)(struct sprd_spi *ss, u32 len); +	int (*write_bufs)(struct sprd_spi *ss, u32 len); +}; + +static u32 sprd_spi_transfer_max_timeout(struct sprd_spi *ss, +					 struct spi_transfer *t) +{ +	/* +	 * The time spent on transmission of the full FIFO data is the maximum +	 * SPI transmission time. +	 */ +	u32 size = t->bits_per_word * SPRD_SPI_FIFO_SIZE; +	u32 bit_time_us = DIV_ROUND_UP(USEC_PER_SEC, ss->hw_speed_hz); +	u32 total_time_us = size * bit_time_us; +	/* +	 * There is an interval between data and the data in our SPI hardware, +	 * so the total transmission time need add the interval time. +	 */ +	u32 interval_cycle = SPRD_SPI_FIFO_SIZE * ss->word_delay; +	u32 interval_time_us = DIV_ROUND_UP(interval_cycle * USEC_PER_SEC, +					    ss->src_clk); + +	return total_time_us + interval_time_us; +} + +static int sprd_spi_wait_for_tx_end(struct sprd_spi *ss, struct spi_transfer *t) +{ +	u32 val, us; +	int ret; + +	us = sprd_spi_transfer_max_timeout(ss, t); +	ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val, +					 val & SPRD_SPI_TX_END_IRQ, 0, us); +	if (ret) { +		dev_err(ss->dev, "SPI error, spi send timeout!\n"); +		return ret; +	} + +	ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_STS2, val, +					 !(val & SPRD_SPI_TX_BUSY), 0, us); +	if (ret) { +		dev_err(ss->dev, "SPI error, spi busy timeout!\n"); +		return ret; +	} + +	writel_relaxed(SPRD_SPI_TX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR); + +	return 0; +} + +static int sprd_spi_wait_for_rx_end(struct sprd_spi *ss, struct spi_transfer *t) +{ +	u32 val, us; +	int ret; + +	us = sprd_spi_transfer_max_timeout(ss, t); +	ret = readl_relaxed_poll_timeout(ss->base + SPRD_SPI_INT_RAW_STS, val, +					 val & SPRD_SPI_RX_END_IRQ, 0, us); +	if (ret) { +		dev_err(ss->dev, "SPI error, spi rx timeout!\n"); +		return ret; +	} + +	writel_relaxed(SPRD_SPI_RX_END_INT_CLR, ss->base + SPRD_SPI_INT_CLR); + +	return 0; +} + +static void sprd_spi_tx_req(struct sprd_spi *ss) +{ +	writel_relaxed(SPRD_SPI_SW_TX_REQ, ss->base + SPRD_SPI_CTL12); +} + +static void sprd_spi_rx_req(struct sprd_spi *ss) +{ +	writel_relaxed(SPRD_SPI_SW_RX_REQ, ss->base + SPRD_SPI_CTL12); +} + +static void sprd_spi_enter_idle(struct sprd_spi *ss) +{ +	u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL1); + +	val &= ~SPRD_SPI_RTX_MD_MASK; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL1); +} + +static void sprd_spi_set_transfer_bits(struct sprd_spi *ss, u32 bits) +{ +	u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL0); + +	/* Set the valid bits for every transaction */ +	val &= ~(SPRD_SPI_CHNL_LEN_MASK << SPRD_SPI_CHNL_LEN); +	val |= bits << SPRD_SPI_CHNL_LEN; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL0); +} + +static void sprd_spi_set_tx_length(struct sprd_spi *ss, u32 length) +{ +	u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL8); + +	length &= SPRD_SPI_TX_MAX_LEN_MASK; +	val &= ~SPRD_SPI_TX_LEN_H_MASK; +	val |= length >> SPRD_SPI_TX_LEN_H_OFFSET; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL8); + +	val = length & SPRD_SPI_TX_LEN_L_MASK; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL9); +} + +static void sprd_spi_set_rx_length(struct sprd_spi *ss, u32 length) +{ +	u32 val = readl_relaxed(ss->base + SPRD_SPI_CTL10); + +	length &= SPRD_SPI_RX_MAX_LEN_MASK; +	val &= ~SPRD_SPI_RX_LEN_H_MASK; +	val |= length >> SPRD_SPI_RX_LEN_H_OFFSET; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL10); + +	val = length & SPRD_SPI_RX_LEN_L_MASK; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL11); +} + +static void sprd_spi_chipselect(struct spi_device *sdev, bool cs) +{ +	struct spi_controller *sctlr = sdev->controller; +	struct sprd_spi *ss = spi_controller_get_devdata(sctlr); +	u32 val; + +	val = readl_relaxed(ss->base + SPRD_SPI_CTL0); +	/*  The SPI controller will pull down CS pin if cs is 0 */ +	if (!cs) { +		val &= ~SPRD_SPI_CS0_VALID; +		writel_relaxed(val, ss->base + SPRD_SPI_CTL0); +	} else { +		val |= SPRD_SPI_CSN_MASK; +		writel_relaxed(val, ss->base + SPRD_SPI_CTL0); +	} +} + +static int sprd_spi_write_only_receive(struct sprd_spi *ss, u32 len) +{ +	u32 val; + +	/* Clear the start receive bit and reset receive data number */ +	val = readl_relaxed(ss->base + SPRD_SPI_CTL4); +	val &= ~(SPRD_SPI_START_RX | SPRD_SPI_ONLY_RECV_MASK); +	writel_relaxed(val, ss->base + SPRD_SPI_CTL4); + +	/* Set the receive data length */ +	val = readl_relaxed(ss->base + SPRD_SPI_CTL4); +	val |= len & SPRD_SPI_ONLY_RECV_MASK; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL4); + +	/* Trigger to receive data */ +	val = readl_relaxed(ss->base + SPRD_SPI_CTL4); +	val |= SPRD_SPI_START_RX; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL4); + +	return len; +} + +static int sprd_spi_write_bufs_u8(struct sprd_spi *ss, u32 len) +{ +	u8 *tx_p = (u8 *)ss->tx_buf; +	int i; + +	for (i = 0; i < len; i++) +		writeb_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); + +	ss->tx_buf += i; +	return i; +} + +static int sprd_spi_write_bufs_u16(struct sprd_spi *ss, u32 len) +{ +	u16 *tx_p = (u16 *)ss->tx_buf; +	int i; + +	for (i = 0; i < len; i++) +		writew_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); + +	ss->tx_buf += i << 1; +	return i << 1; +} + +static int sprd_spi_write_bufs_u32(struct sprd_spi *ss, u32 len) +{ +	u32 *tx_p = (u32 *)ss->tx_buf; +	int i; + +	for (i = 0; i < len; i++) +		writel_relaxed(tx_p[i], ss->base + SPRD_SPI_TXD); + +	ss->tx_buf += i << 2; +	return i << 2; +} + +static int sprd_spi_read_bufs_u8(struct sprd_spi *ss, u32 len) +{ +	u8 *rx_p = (u8 *)ss->rx_buf; +	int i; + +	for (i = 0; i < len; i++) +		rx_p[i] = readb_relaxed(ss->base + SPRD_SPI_TXD); + +	ss->rx_buf += i; +	return i; +} + +static int sprd_spi_read_bufs_u16(struct sprd_spi *ss, u32 len) +{ +	u16 *rx_p = (u16 *)ss->rx_buf; +	int i; + +	for (i = 0; i < len; i++) +		rx_p[i] = readw_relaxed(ss->base + SPRD_SPI_TXD); + +	ss->rx_buf += i << 1; +	return i << 1; +} + +static int sprd_spi_read_bufs_u32(struct sprd_spi *ss, u32 len) +{ +	u32 *rx_p = (u32 *)ss->rx_buf; +	int i; + +	for (i = 0; i < len; i++) +		rx_p[i] = readl_relaxed(ss->base + SPRD_SPI_TXD); + +	ss->rx_buf += i << 2; +	return i << 2; +} + +static int sprd_spi_txrx_bufs(struct spi_device *sdev, struct spi_transfer *t) +{ +	struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); +	u32 trans_len = ss->trans_len, len; +	int ret, write_size = 0; + +	while (trans_len) { +		len = trans_len > SPRD_SPI_FIFO_SIZE ? SPRD_SPI_FIFO_SIZE : +			trans_len; +		if (ss->trans_mode & SPRD_SPI_TX_MODE) { +			sprd_spi_set_tx_length(ss, len); +			write_size += ss->write_bufs(ss, len); + +			/* +			 * For our 3 wires mode or dual TX line mode, we need +			 * to request the controller to transfer. +			 */ +			if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) +				sprd_spi_tx_req(ss); + +			ret = sprd_spi_wait_for_tx_end(ss, t); +		} else { +			sprd_spi_set_rx_length(ss, len); + +			/* +			 * For our 3 wires mode or dual TX line mode, we need +			 * to request the controller to read. +			 */ +			if (ss->hw_mode & SPI_3WIRE || ss->hw_mode & SPI_TX_DUAL) +				sprd_spi_rx_req(ss); +			else +				write_size += ss->write_bufs(ss, len); + +			ret = sprd_spi_wait_for_rx_end(ss, t); +		} + +		if (ret) +			goto complete; + +		if (ss->trans_mode & SPRD_SPI_RX_MODE) +			ss->read_bufs(ss, len); + +		trans_len -= len; +	} + +	ret = write_size; + +complete: +	sprd_spi_enter_idle(ss); + +	return ret; +} + +static void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz) +{ +	/* +	 * From SPI datasheet, the prescale calculation formula: +	 * prescale = SPI source clock / (2 * SPI_freq) - 1; +	 */ +	u32 clk_div = DIV_ROUND_UP(ss->src_clk, speed_hz << 1) - 1; + +	/* Save the real hardware speed */ +	ss->hw_speed_hz = (ss->src_clk >> 1) / (clk_div + 1); +	writel_relaxed(clk_div, ss->base + SPRD_SPI_CLKD); +} + +static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t) +{ +	u16 word_delay, interval; +	u32 val; + +	val = readl_relaxed(ss->base + SPRD_SPI_CTL7); +	val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX); +	/* Set default chip selection, clock phase and clock polarity */ +	val |= ss->hw_mode & SPI_CPHA ? SPRD_SPI_NG_RX : SPRD_SPI_NG_TX; +	val |= ss->hw_mode & SPI_CPOL ? SPRD_SPI_SCK_REV : 0; +	writel_relaxed(val, ss->base + SPRD_SPI_CTL0); + +	/* +	 * Set the intervals of two SPI frames, and the inteval calculation +	 * formula as below per datasheet: +	 * interval time (source clock cycles) = interval * 4 + 10. +	 */ +	word_delay = clamp_t(u16, t->word_delay, SPRD_SPI_MIN_DELAY_CYCLE, +			     SPRD_SPI_MAX_DELAY_CYCLE); +	interval = DIV_ROUND_UP(word_delay - 10, 4); +	ss->word_delay = interval * 4 + 10; +	writel_relaxed(interval, ss->base + SPRD_SPI_CTL5); + +	/* Reset SPI fifo */ +	writel_relaxed(1, ss->base + SPRD_SPI_FIFO_RST); +	writel_relaxed(0, ss->base + SPRD_SPI_FIFO_RST); + +	/* Set SPI work mode */ +	val = readl_relaxed(ss->base + SPRD_SPI_CTL7); +	val &= ~SPRD_SPI_MODE_MASK; + +	if (ss->hw_mode & SPI_3WIRE) +		val |= SPRD_SPI_3WIRE_MODE << SPRD_SPI_MODE_OFFSET; +	else +		val |= SPRD_SPI_4WIRE_MODE << SPRD_SPI_MODE_OFFSET; + +	if (ss->hw_mode & SPI_TX_DUAL) +		val |= SPRD_SPI_DATA_LINE2_EN; +	else +		val &= ~SPRD_SPI_DATA_LINE2_EN; + +	writel_relaxed(val, ss->base + SPRD_SPI_CTL7); +} + +static int sprd_spi_setup_transfer(struct spi_device *sdev, +				   struct spi_transfer *t) +{ +	struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller); +	u8 bits_per_word = t->bits_per_word; +	u32 val, mode = 0; + +	ss->len = t->len; +	ss->tx_buf = t->tx_buf; +	ss->rx_buf = t->rx_buf; + +	ss->hw_mode = sdev->mode; +	sprd_spi_init_hw(ss, t); + +	/* Set tansfer speed and valid bits */ +	sprd_spi_set_speed(ss, t->speed_hz); +	sprd_spi_set_transfer_bits(ss, bits_per_word); + +	if (bits_per_word > 16) +		bits_per_word = round_up(bits_per_word, 16); +	else +		bits_per_word = round_up(bits_per_word, 8); + +	switch (bits_per_word) { +	case 8: +		ss->trans_len = t->len; +		ss->read_bufs = sprd_spi_read_bufs_u8; +		ss->write_bufs = sprd_spi_write_bufs_u8; +		break; +	case 16: +		ss->trans_len = t->len >> 1; +		ss->read_bufs = sprd_spi_read_bufs_u16; +		ss->write_bufs = sprd_spi_write_bufs_u16; +		break; +	case 32: +		ss->trans_len = t->len >> 2; +		ss->read_bufs = sprd_spi_read_bufs_u32; +		ss->write_bufs = sprd_spi_write_bufs_u32; +		break; +	default: +		return -EINVAL; +	} + +	/* Set transfer read or write mode */ +	val = readl_relaxed(ss->base + SPRD_SPI_CTL1); +	val &= ~SPRD_SPI_RTX_MD_MASK; +	if (t->tx_buf) +		mode |= SPRD_SPI_TX_MODE; +	if (t->rx_buf) +		mode |= SPRD_SPI_RX_MODE; + +	writel_relaxed(val | mode, ss->base + SPRD_SPI_CTL1); + +	ss->trans_mode = mode; + +	/* +	 * If in only receive mode, we need to trigger the SPI controller to +	 * receive data automatically. +	 */ +	if (ss->trans_mode == SPRD_SPI_RX_MODE) +		ss->write_bufs = sprd_spi_write_only_receive; + +	return 0; +} + +static int sprd_spi_transfer_one(struct spi_controller *sctlr, +				 struct spi_device *sdev, +				 struct spi_transfer *t) +{ +	int ret; + +	ret = sprd_spi_setup_transfer(sdev, t); +	if (ret) +		goto setup_err; + +	ret = sprd_spi_txrx_bufs(sdev, t); +	if (ret == t->len) +		ret = 0; +	else if (ret >= 0) +		ret = -EREMOTEIO; + +setup_err: +	spi_finalize_current_transfer(sctlr); + +	return ret; +} + +static int sprd_spi_clk_init(struct platform_device *pdev, struct sprd_spi *ss) +{ +	struct clk *clk_spi, *clk_parent; + +	clk_spi = devm_clk_get(&pdev->dev, "spi"); +	if (IS_ERR(clk_spi)) { +		dev_warn(&pdev->dev, "can't get the spi clock\n"); +		clk_spi = NULL; +	} + +	clk_parent = devm_clk_get(&pdev->dev, "source"); +	if (IS_ERR(clk_parent)) { +		dev_warn(&pdev->dev, "can't get the source clock\n"); +		clk_parent = NULL; +	} + +	ss->clk = devm_clk_get(&pdev->dev, "enable"); +	if (IS_ERR(ss->clk)) { +		dev_err(&pdev->dev, "can't get the enable clock\n"); +		return PTR_ERR(ss->clk); +	} + +	if (!clk_set_parent(clk_spi, clk_parent)) +		ss->src_clk = clk_get_rate(clk_spi); +	else +		ss->src_clk = SPRD_SPI_DEFAULT_SOURCE; + +	return 0; +} + +static int sprd_spi_probe(struct platform_device *pdev) +{ +	struct spi_controller *sctlr; +	struct resource *res; +	struct sprd_spi *ss; +	int ret; + +	pdev->id = of_alias_get_id(pdev->dev.of_node, "spi"); +	sctlr = spi_alloc_master(&pdev->dev, sizeof(*ss)); +	if (!sctlr) +		return -ENOMEM; + +	ss = spi_controller_get_devdata(sctlr); +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	ss->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(ss->base)) { +		ret = PTR_ERR(ss->base); +		goto free_controller; +	} + +	ss->dev = &pdev->dev; +	sctlr->dev.of_node = pdev->dev.of_node; +	sctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE | SPI_TX_DUAL; +	sctlr->bus_num = pdev->id; +	sctlr->set_cs = sprd_spi_chipselect; +	sctlr->transfer_one = sprd_spi_transfer_one; +	sctlr->auto_runtime_pm = true; +	sctlr->max_speed_hz = min_t(u32, ss->src_clk >> 1, +				    SPRD_SPI_MAX_SPEED_HZ); + +	platform_set_drvdata(pdev, sctlr); +	ret = sprd_spi_clk_init(pdev, ss); +	if (ret) +		goto free_controller; + +	ret = clk_prepare_enable(ss->clk); +	if (ret) +		goto free_controller; + +	ret = pm_runtime_set_active(&pdev->dev); +	if (ret < 0) +		goto disable_clk; + +	pm_runtime_set_autosuspend_delay(&pdev->dev, +					 SPRD_SPI_AUTOSUSPEND_DELAY); +	pm_runtime_use_autosuspend(&pdev->dev); +	pm_runtime_enable(&pdev->dev); +	ret = pm_runtime_get_sync(&pdev->dev); +	if (ret < 0) { +		dev_err(&pdev->dev, "failed to resume SPI controller\n"); +		goto err_rpm_put; +	} + +	ret = devm_spi_register_controller(&pdev->dev, sctlr); +	if (ret) +		goto err_rpm_put; + +	pm_runtime_mark_last_busy(&pdev->dev); +	pm_runtime_put_autosuspend(&pdev->dev); + +	return 0; + +err_rpm_put: +	pm_runtime_put_noidle(&pdev->dev); +	pm_runtime_disable(&pdev->dev); +disable_clk: +	clk_disable_unprepare(ss->clk); +free_controller: +	spi_controller_put(sctlr); + +	return ret; +} + +static int sprd_spi_remove(struct platform_device *pdev) +{ +	struct spi_controller *sctlr = platform_get_drvdata(pdev); +	struct sprd_spi *ss = spi_controller_get_devdata(sctlr); +	int ret; + +	ret = pm_runtime_get_sync(ss->dev); +	if (ret < 0) { +		dev_err(ss->dev, "failed to resume SPI controller\n"); +		return ret; +	} + +	clk_disable_unprepare(ss->clk); +	pm_runtime_put_noidle(&pdev->dev); +	pm_runtime_disable(&pdev->dev); + +	return 0; +} + +static int __maybe_unused sprd_spi_runtime_suspend(struct device *dev) +{ +	struct spi_controller *sctlr = dev_get_drvdata(dev); +	struct sprd_spi *ss = spi_controller_get_devdata(sctlr); + +	clk_disable_unprepare(ss->clk); + +	return 0; +} + +static int __maybe_unused sprd_spi_runtime_resume(struct device *dev) +{ +	struct spi_controller *sctlr = dev_get_drvdata(dev); +	struct sprd_spi *ss = spi_controller_get_devdata(sctlr); +	int ret; + +	ret = clk_prepare_enable(ss->clk); +	if (ret) +		return ret; + +	return 0; +} + +static const struct dev_pm_ops sprd_spi_pm_ops = { +	SET_RUNTIME_PM_OPS(sprd_spi_runtime_suspend, +			   sprd_spi_runtime_resume, NULL) +}; + +static const struct of_device_id sprd_spi_of_match[] = { +	{ .compatible = "sprd,sc9860-spi", }, +	{ /* sentinel */ } +}; + +static struct platform_driver sprd_spi_driver = { +	.driver = { +		.name = "sprd-spi", +		.of_match_table = sprd_spi_of_match, +		.pm = &sprd_spi_pm_ops, +	}, +	.probe = sprd_spi_probe, +	.remove  = sprd_spi_remove, +}; + +module_platform_driver(sprd_spi_driver); + +MODULE_DESCRIPTION("Spreadtrum SPI Controller driver"); +MODULE_AUTHOR("Lanqing Liu <[email protected]>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c new file mode 100644 index 000000000000..3b2a9a6b990d --- /dev/null +++ b/drivers/spi/spi-stm32-qspi.c @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Ludovic Barre <[email protected]> for STMicroelectronics. + */ +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/sizes.h> +#include <linux/spi/spi-mem.h> + +#define QSPI_CR			0x00 +#define CR_EN			BIT(0) +#define CR_ABORT		BIT(1) +#define CR_DMAEN		BIT(2) +#define CR_TCEN			BIT(3) +#define CR_SSHIFT		BIT(4) +#define CR_DFM			BIT(6) +#define CR_FSEL			BIT(7) +#define CR_FTHRES_MASK		GENMASK(12, 8) +#define CR_TEIE			BIT(16) +#define CR_TCIE			BIT(17) +#define CR_FTIE			BIT(18) +#define CR_SMIE			BIT(19) +#define CR_TOIE			BIT(20) +#define CR_PRESC_MASK		GENMASK(31, 24) + +#define QSPI_DCR		0x04 +#define DCR_FSIZE_MASK		GENMASK(20, 16) + +#define QSPI_SR			0x08 +#define SR_TEF			BIT(0) +#define SR_TCF			BIT(1) +#define SR_FTF			BIT(2) +#define SR_SMF			BIT(3) +#define SR_TOF			BIT(4) +#define SR_BUSY			BIT(5) +#define SR_FLEVEL_MASK		GENMASK(13, 8) + +#define QSPI_FCR		0x0c +#define FCR_CTEF		BIT(0) +#define FCR_CTCF		BIT(1) + +#define QSPI_DLR		0x10 + +#define QSPI_CCR		0x14 +#define CCR_INST_MASK		GENMASK(7, 0) +#define CCR_IMODE_MASK		GENMASK(9, 8) +#define CCR_ADMODE_MASK		GENMASK(11, 10) +#define CCR_ADSIZE_MASK		GENMASK(13, 12) +#define CCR_DCYC_MASK		GENMASK(22, 18) +#define CCR_DMODE_MASK		GENMASK(25, 24) +#define CCR_FMODE_MASK		GENMASK(27, 26) +#define CCR_FMODE_INDW		(0U << 26) +#define CCR_FMODE_INDR		(1U << 26) +#define CCR_FMODE_APM		(2U << 26) +#define CCR_FMODE_MM		(3U << 26) +#define CCR_BUSWIDTH_0		0x0 +#define CCR_BUSWIDTH_1		0x1 +#define CCR_BUSWIDTH_2		0x2 +#define CCR_BUSWIDTH_4		0x3 + +#define QSPI_AR			0x18 +#define QSPI_ABR		0x1c +#define QSPI_DR			0x20 +#define QSPI_PSMKR		0x24 +#define QSPI_PSMAR		0x28 +#define QSPI_PIR		0x2c +#define QSPI_LPTR		0x30 +#define LPTR_DFT_TIMEOUT	0x10 + +#define STM32_QSPI_MAX_MMAP_SZ	SZ_256M +#define STM32_QSPI_MAX_NORCHIP	2 + +#define STM32_FIFO_TIMEOUT_US 30000 +#define STM32_BUSY_TIMEOUT_US 100000 +#define STM32_ABT_TIMEOUT_US 100000 + +struct stm32_qspi_flash { +	struct stm32_qspi *qspi; +	u32 cs; +	u32 presc; +}; + +struct stm32_qspi { +	struct device *dev; +	void __iomem *io_base; +	void __iomem *mm_base; +	resource_size_t mm_size; +	struct clk *clk; +	u32 clk_rate; +	struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP]; +	struct completion data_completion; +	u32 fmode; + +	/* +	 * to protect device configuration, could be different between +	 * 2 flash access (bk1, bk2) +	 */ +	struct mutex lock; +}; + +static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) +{ +	struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; +	u32 cr, sr; + +	sr = readl_relaxed(qspi->io_base + QSPI_SR); + +	if (sr & (SR_TEF | SR_TCF)) { +		/* disable irq */ +		cr = readl_relaxed(qspi->io_base + QSPI_CR); +		cr &= ~CR_TCIE & ~CR_TEIE; +		writel_relaxed(cr, qspi->io_base + QSPI_CR); +		complete(&qspi->data_completion); +	} + +	return IRQ_HANDLED; +} + +static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr) +{ +	*val = readb_relaxed(addr); +} + +static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr) +{ +	writeb_relaxed(*val, addr); +} + +static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, +			      const struct spi_mem_op *op) +{ +	void (*tx_fifo)(u8 *val, void __iomem *addr); +	u32 len = op->data.nbytes, sr; +	u8 *buf; +	int ret; + +	if (op->data.dir == SPI_MEM_DATA_IN) { +		tx_fifo = stm32_qspi_read_fifo; +		buf = op->data.buf.in; + +	} else { +		tx_fifo = stm32_qspi_write_fifo; +		buf = (u8 *)op->data.buf.out; +	} + +	while (len--) { +		ret = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, +							sr, (sr & SR_FTF), 1, +							STM32_FIFO_TIMEOUT_US); +		if (ret) { +			dev_err(qspi->dev, "fifo timeout (len:%d stat:%#x)\n", +				len, sr); +			return ret; +		} +		tx_fifo(buf++, qspi->io_base + QSPI_DR); +	} + +	return 0; +} + +static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, +			    const struct spi_mem_op *op) +{ +	memcpy_fromio(op->data.buf.in, qspi->mm_base + op->addr.val, +		      op->data.nbytes); +	return 0; +} + +static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) +{ +	if (!op->data.nbytes) +		return 0; + +	if (qspi->fmode == CCR_FMODE_MM) +		return stm32_qspi_tx_mm(qspi, op); + +	return stm32_qspi_tx_poll(qspi, op); +} + +static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) +{ +	u32 sr; + +	return readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_SR, sr, +						 !(sr & SR_BUSY), 1, +						 STM32_BUSY_TIMEOUT_US); +} + +static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, +			       const struct spi_mem_op *op) +{ +	u32 cr, sr; +	int err = 0; + +	if (!op->data.nbytes) +		return stm32_qspi_wait_nobusy(qspi); + +	if (readl_relaxed(qspi->io_base + QSPI_SR) & SR_TCF) +		goto out; + +	reinit_completion(&qspi->data_completion); +	cr = readl_relaxed(qspi->io_base + QSPI_CR); +	writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); + +	if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, +						msecs_to_jiffies(1000))) { +		err = -ETIMEDOUT; +	} else { +		sr = readl_relaxed(qspi->io_base + QSPI_SR); +		if (sr & SR_TEF) +			err = -EIO; +	} + +out: +	/* clear flags */ +	writel_relaxed(FCR_CTCF | FCR_CTEF, qspi->io_base + QSPI_FCR); + +	return err; +} + +static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth) +{ +	if (buswidth == 4) +		return CCR_BUSWIDTH_4; + +	return buswidth; +} + +static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) +{ +	struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); +	struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; +	u32 ccr, cr, addr_max; +	int timeout, err = 0; + +	dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", +		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, +		op->dummy.buswidth, op->data.buswidth, +		op->addr.val, op->data.nbytes); + +	err = stm32_qspi_wait_nobusy(qspi); +	if (err) +		goto abort; + +	addr_max = op->addr.val + op->data.nbytes + 1; + +	if (op->data.dir == SPI_MEM_DATA_IN) { +		if (addr_max < qspi->mm_size && +		    op->addr.buswidth) +			qspi->fmode = CCR_FMODE_MM; +		else +			qspi->fmode = CCR_FMODE_INDR; +	} else { +		qspi->fmode = CCR_FMODE_INDW; +	} + +	cr = readl_relaxed(qspi->io_base + QSPI_CR); +	cr &= ~CR_PRESC_MASK & ~CR_FSEL; +	cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); +	cr |= FIELD_PREP(CR_FSEL, flash->cs); +	writel_relaxed(cr, qspi->io_base + QSPI_CR); + +	if (op->data.nbytes) +		writel_relaxed(op->data.nbytes - 1, +			       qspi->io_base + QSPI_DLR); +	else +		qspi->fmode = CCR_FMODE_INDW; + +	ccr = qspi->fmode; +	ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); +	ccr |= FIELD_PREP(CCR_IMODE_MASK, +			  stm32_qspi_get_mode(qspi, op->cmd.buswidth)); + +	if (op->addr.nbytes) { +		ccr |= FIELD_PREP(CCR_ADMODE_MASK, +				  stm32_qspi_get_mode(qspi, op->addr.buswidth)); +		ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1); +	} + +	if (op->dummy.buswidth && op->dummy.nbytes) +		ccr |= FIELD_PREP(CCR_DCYC_MASK, +				  op->dummy.nbytes * 8 / op->dummy.buswidth); + +	if (op->data.nbytes) { +		ccr |= FIELD_PREP(CCR_DMODE_MASK, +				  stm32_qspi_get_mode(qspi, op->data.buswidth)); +	} + +	writel_relaxed(ccr, qspi->io_base + QSPI_CCR); + +	if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM) +		writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); + +	err = stm32_qspi_tx(qspi, op); + +	/* +	 * Abort in: +	 * -error case +	 * -read memory map: prefetching must be stopped if we read the last +	 *  byte of device (device size - fifo size). like device size is not +	 *  knows, the prefetching is always stop. +	 */ +	if (err || qspi->fmode == CCR_FMODE_MM) +		goto abort; + +	/* wait end of tx in indirect mode */ +	err = stm32_qspi_wait_cmd(qspi, op); +	if (err) +		goto abort; + +	return 0; + +abort: +	cr = readl_relaxed(qspi->io_base + QSPI_CR) | CR_ABORT; +	writel_relaxed(cr, qspi->io_base + QSPI_CR); + +	/* wait clear of abort bit by hw */ +	timeout = readl_relaxed_poll_timeout_atomic(qspi->io_base + QSPI_CR, +						    cr, !(cr & CR_ABORT), 1, +						    STM32_ABT_TIMEOUT_US); + +	writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR); + +	if (err || timeout) +		dev_err(qspi->dev, "%s err:%d abort timeout:%d\n", +			__func__, err, timeout); + +	return err; +} + +static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ +	struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); +	int ret; + +	mutex_lock(&qspi->lock); +	ret = stm32_qspi_send(mem, op); +	mutex_unlock(&qspi->lock); + +	return ret; +} + +static int stm32_qspi_setup(struct spi_device *spi) +{ +	struct spi_controller *ctrl = spi->master; +	struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); +	struct stm32_qspi_flash *flash; +	u32 cr, presc; + +	if (ctrl->busy) +		return -EBUSY; + +	if (!spi->max_speed_hz) +		return -EINVAL; + +	presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; + +	flash = &qspi->flash[spi->chip_select]; +	flash->qspi = qspi; +	flash->cs = spi->chip_select; +	flash->presc = presc; + +	mutex_lock(&qspi->lock); +	writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QSPI_LPTR); +	cr = FIELD_PREP(CR_FTHRES_MASK, 3) | CR_TCEN | CR_SSHIFT | CR_EN; +	writel_relaxed(cr, qspi->io_base + QSPI_CR); + +	/* set dcr fsize to max address */ +	writel_relaxed(DCR_FSIZE_MASK, qspi->io_base + QSPI_DCR); +	mutex_unlock(&qspi->lock); + +	return 0; +} + +/* + * no special host constraint, so use default spi_mem_default_supports_op + * to check supported mode. + */ +static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { +	.exec_op = stm32_qspi_exec_op, +}; + +static void stm32_qspi_release(struct stm32_qspi *qspi) +{ +	/* disable qspi */ +	writel_relaxed(0, qspi->io_base + QSPI_CR); +	mutex_destroy(&qspi->lock); +	clk_disable_unprepare(qspi->clk); +} + +static int stm32_qspi_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct spi_controller *ctrl; +	struct reset_control *rstc; +	struct stm32_qspi *qspi; +	struct resource *res; +	int ret, irq; + +	ctrl = spi_alloc_master(dev, sizeof(*qspi)); +	if (!ctrl) +		return -ENOMEM; + +	qspi = spi_controller_get_devdata(ctrl); + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi"); +	qspi->io_base = devm_ioremap_resource(dev, res); +	if (IS_ERR(qspi->io_base)) +		return PTR_ERR(qspi->io_base); + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm"); +	qspi->mm_base = devm_ioremap_resource(dev, res); +	if (IS_ERR(qspi->mm_base)) +		return PTR_ERR(qspi->mm_base); + +	qspi->mm_size = resource_size(res); +	if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) +		return -EINVAL; + +	irq = platform_get_irq(pdev, 0); +	ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0, +			       dev_name(dev), qspi); +	if (ret) { +		dev_err(dev, "failed to request irq\n"); +		return ret; +	} + +	init_completion(&qspi->data_completion); + +	qspi->clk = devm_clk_get(dev, NULL); +	if (IS_ERR(qspi->clk)) +		return PTR_ERR(qspi->clk); + +	qspi->clk_rate = clk_get_rate(qspi->clk); +	if (!qspi->clk_rate) +		return -EINVAL; + +	ret = clk_prepare_enable(qspi->clk); +	if (ret) { +		dev_err(dev, "can not enable the clock\n"); +		return ret; +	} + +	rstc = devm_reset_control_get_exclusive(dev, NULL); +	if (!IS_ERR(rstc)) { +		reset_control_assert(rstc); +		udelay(2); +		reset_control_deassert(rstc); +	} + +	qspi->dev = dev; +	platform_set_drvdata(pdev, qspi); +	mutex_init(&qspi->lock); + +	ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD +		| SPI_TX_DUAL | SPI_TX_QUAD; +	ctrl->setup = stm32_qspi_setup; +	ctrl->bus_num = -1; +	ctrl->mem_ops = &stm32_qspi_mem_ops; +	ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; +	ctrl->dev.of_node = dev->of_node; + +	ret = devm_spi_register_master(dev, ctrl); +	if (ret) +		goto err_spi_register; + +	return 0; + +err_spi_register: +	stm32_qspi_release(qspi); + +	return ret; +} + +static int stm32_qspi_remove(struct platform_device *pdev) +{ +	struct stm32_qspi *qspi = platform_get_drvdata(pdev); + +	stm32_qspi_release(qspi); +	return 0; +} + +static const struct of_device_id stm32_qspi_match[] = { +	{.compatible = "st,stm32f469-qspi"}, +	{} +}; +MODULE_DEVICE_TABLE(of, stm32_qspi_match); + +static struct platform_driver stm32_qspi_driver = { +	.probe	= stm32_qspi_probe, +	.remove	= stm32_qspi_remove, +	.driver	= { +		.name = "stm32-qspi", +		.of_match_table = stm32_qspi_match, +	}, +}; +module_platform_driver(stm32_qspi_driver); + +MODULE_AUTHOR("Ludovic Barre <[email protected]>"); +MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9da0bc5a036c..6ca59406b0b7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later  /*   * SPI init/core code   *   * Copyright (C) 2005 David Brownell   * Copyright (C) 2008 Secret Lab Technologies Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details.   */  #include <linux/kernel.h> @@ -60,6 +51,7 @@ static void spidev_release(struct device *dev)  		spi->controller->cleanup(spi);  	spi_controller_put(spi->controller); +	kfree(spi->driver_override);  	kfree(spi);  } @@ -77,6 +69,51 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)  }  static DEVICE_ATTR_RO(modalias); +static ssize_t driver_override_store(struct device *dev, +				     struct device_attribute *a, +				     const char *buf, size_t count) +{ +	struct spi_device *spi = to_spi_device(dev); +	const char *end = memchr(buf, '\n', count); +	const size_t len = end ? end - buf : count; +	const char *driver_override, *old; + +	/* We need to keep extra room for a newline when displaying value */ +	if (len >= (PAGE_SIZE - 1)) +		return -EINVAL; + +	driver_override = kstrndup(buf, len, GFP_KERNEL); +	if (!driver_override) +		return -ENOMEM; + +	device_lock(dev); +	old = spi->driver_override; +	if (len) { +		spi->driver_override = driver_override; +	} else { +		/* Emptry string, disable driver override */ +		spi->driver_override = NULL; +		kfree(driver_override); +	} +	device_unlock(dev); +	kfree(old); + +	return count; +} + +static ssize_t driver_override_show(struct device *dev, +				    struct device_attribute *a, char *buf) +{ +	const struct spi_device *spi = to_spi_device(dev); +	ssize_t len; + +	device_lock(dev); +	len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : ""); +	device_unlock(dev); +	return len; +} +static DEVICE_ATTR_RW(driver_override); +  #define SPI_STATISTICS_ATTRS(field, file)				\  static ssize_t spi_controller_##field##_show(struct device *dev,	\  					     struct device_attribute *attr, \ @@ -158,6 +195,7 @@ SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");  static struct attribute *spi_dev_attrs[] = {  	&dev_attr_modalias.attr, +	&dev_attr_driver_override.attr,  	NULL,  }; @@ -305,6 +343,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)  	const struct spi_device	*spi = to_spi_device(dev);  	const struct spi_driver	*sdrv = to_spi_driver(drv); +	/* Check override first, and if set, only use the named driver */ +	if (spi->driver_override) +		return strcmp(spi->driver_override, drv->name) == 0; +  	/* Attempt an OF style match */  	if (of_driver_match_device(dev, drv))  		return 1; @@ -733,7 +775,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable)  		enable = !enable;  	if (gpio_is_valid(spi->cs_gpio)) { -		gpio_set_value(spi->cs_gpio, !enable); +		/* Honour the SPI_NO_CS flag */ +		if (!(spi->mode & SPI_NO_CS)) +			gpio_set_value(spi->cs_gpio, !enable);  		/* Some SPI masters need both GPIO CS & slave_select */  		if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&  		    spi->controller->set_cs) @@ -2783,8 +2827,10 @@ int spi_setup(struct spi_device *spi)  		return -EINVAL;  	/* help drivers fail *cleanly* when they need options  	 * that aren't supported with their current controller +	 * SPI_CS_WORD has a fallback software implementation, +	 * so it is ignored here.  	 */ -	bad_bits = spi->mode & ~spi->controller->mode_bits; +	bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD);  	ugly_bits = bad_bits &  		    (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);  	if (ugly_bits) { @@ -2838,6 +2884,35 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)  	if (list_empty(&message->transfers))  		return -EINVAL; +	/* If an SPI controller does not support toggling the CS line on each +	 * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO +	 * for the CS line, we can emulate the CS-per-word hardware function by +	 * splitting transfers into one-word transfers and ensuring that +	 * cs_change is set for each transfer. +	 */ +	if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) || +					  gpio_is_valid(spi->cs_gpio))) { +		size_t maxsize; +		int ret; + +		maxsize = (spi->bits_per_word + 7) / 8; + +		/* spi_split_transfers_maxsize() requires message->spi */ +		message->spi = spi; + +		ret = spi_split_transfers_maxsize(ctlr, message, maxsize, +						  GFP_KERNEL); +		if (ret) +			return ret; + +		list_for_each_entry(xfer, &message->transfers, transfer_list) { +			/* don't change cs_change on the last entry in the list */ +			if (list_is_last(&xfer->transfer_list, &message->transfers)) +				break; +			xfer->cs_change = 1; +		} +	} +  	/* Half-duplex links include original MicroWire, and ones with  	 * only one data pin like SPI_3WIRE (switches direction) or where  	 * either MOSI or MISO is missing.  They can also be caused by @@ -3323,20 +3398,23 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);  /*-------------------------------------------------------------------------*/ -#if IS_ENABLED(CONFIG_OF_DYNAMIC) +#if IS_ENABLED(CONFIG_OF)  static int __spi_of_device_match(struct device *dev, void *data)  {  	return dev->of_node == data;  }  /* must call put_device() when done with returned spi_device device */ -static struct spi_device *of_find_spi_device_by_node(struct device_node *node) +struct spi_device *of_find_spi_device_by_node(struct device_node *node)  {  	struct device *dev = bus_find_device(&spi_bus_type, NULL, node,  						__spi_of_device_match);  	return dev ? to_spi_device(dev) : NULL;  } +EXPORT_SYMBOL_GPL(of_find_spi_device_by_node); +#endif /* IS_ENABLED(CONFIG_OF) */ +#if IS_ENABLED(CONFIG_OF_DYNAMIC)  static int __spi_of_controller_match(struct device *dev, const void *data)  {  	return dev->of_node == data; diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index cda10719d1d1..b0c76e2626ce 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -669,6 +669,7 @@ static const struct of_device_id spidev_dt_ids[] = {  	{ .compatible = "lineartechnology,ltc2488" },  	{ .compatible = "ge,achc" },  	{ .compatible = "semtech,sx1301" }, +	{ .compatible = "lwn,bk4" },  	{},  };  MODULE_DEVICE_TABLE(of, spidev_dt_ids); @@ -724,11 +725,9 @@ static int spidev_probe(struct spi_device *spi)  	 * compatible string, it is a Linux implementation thing  	 * rather than a description of the hardware.  	 */ -	if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { -		dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n"); -		WARN_ON(spi->dev.of_node && -			!of_match_device(spidev_dt_ids, &spi->dev)); -	} +	WARN(spi->dev.of_node && +	     of_device_is_compatible(spi->dev.of_node, "spidev"), +	     "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);  	spidev_probe_acpi(spi); |