diff options
Diffstat (limited to 'drivers/spi')
| -rw-r--r-- | drivers/spi/atmel-quadspi.c | 11 | ||||
| -rw-r--r-- | drivers/spi/spi-bcm63xx-hsspi.c | 1 | ||||
| -rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 103 | ||||
| -rw-r--r-- | drivers/spi/spi-pxa2xx.c | 23 | ||||
| -rw-r--r-- | drivers/spi/spi-qup.c | 11 | ||||
| -rw-r--r-- | drivers/spi/spi-zynqmp-gqspi.c | 3 | ||||
| -rw-r--r-- | drivers/spi/spi.c | 32 | ||||
| -rw-r--r-- | drivers/spi/spidev.c | 5 | 
8 files changed, 125 insertions, 64 deletions
| diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index fd8007ebb145..13def7f78b9e 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -149,6 +149,7 @@ struct atmel_qspi {  	struct clk		*qspick;  	struct platform_device	*pdev;  	const struct atmel_qspi_caps *caps; +	resource_size_t		mmap_size;  	u32			pending;  	u32			mr;  	u32			scr; @@ -329,6 +330,14 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)  	u32 sr, offset;  	int err; +	/* +	 * Check if the address exceeds the MMIO window size. An improvement +	 * would be to add support for regular SPI mode and fall back to it +	 * when the flash memories overrun the controller's memory space. +	 */ +	if (op->addr.val + op->data.nbytes > aq->mmap_size) +		return -ENOTSUPP; +  	err = atmel_qspi_set_cfg(aq, op, &offset);  	if (err)  		return err; @@ -480,6 +489,8 @@ static int atmel_qspi_probe(struct platform_device *pdev)  		goto exit;  	} +	aq->mmap_size = resource_size(res); +  	/* Get the peripheral clock */  	aq->pclk = devm_clk_get(&pdev->dev, "pclk");  	if (IS_ERR(aq->pclk)) diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 7327309ea3d5..6c235306c0e4 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -366,7 +366,6 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)  			goto out_disable_clk;  		rate = clk_get_rate(pll_clk); -		clk_disable_unprepare(pll_clk);  		if (!rate) {  			ret = -EINVAL;  			goto out_disable_pll_clk; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 7e2292c11d12..e9e256718ef4 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -130,6 +130,7 @@ struct omap2_mcspi {  	int			fifo_depth;  	bool			slave_aborted;  	unsigned int		pin_dir:1; +	size_t			max_xfer_len;  };  struct omap2_mcspi_cs { @@ -974,20 +975,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,   * Note that we currently allow DMA only if we get a channel   * for both rx and tx. Otherwise we'll do PIO for both rx and tx.   */ -static int omap2_mcspi_request_dma(struct spi_device *spi) +static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi, +				   struct omap2_mcspi_dma *mcspi_dma)  { -	struct spi_master	*master = spi->master; -	struct omap2_mcspi	*mcspi; -	struct omap2_mcspi_dma	*mcspi_dma;  	int ret = 0; -	mcspi = spi_master_get_devdata(master); -	mcspi_dma = mcspi->dma_channels + spi->chip_select; - -	init_completion(&mcspi_dma->dma_rx_completion); -	init_completion(&mcspi_dma->dma_tx_completion); - -	mcspi_dma->dma_rx = dma_request_chan(&master->dev, +	mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,  					     mcspi_dma->dma_rx_ch_name);  	if (IS_ERR(mcspi_dma->dma_rx)) {  		ret = PTR_ERR(mcspi_dma->dma_rx); @@ -995,7 +988,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)  		goto no_dma;  	} -	mcspi_dma->dma_tx = dma_request_chan(&master->dev, +	mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,  					     mcspi_dma->dma_tx_ch_name);  	if (IS_ERR(mcspi_dma->dma_tx)) {  		ret = PTR_ERR(mcspi_dma->dma_tx); @@ -1004,20 +997,40 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)  		mcspi_dma->dma_rx = NULL;  	} +	init_completion(&mcspi_dma->dma_rx_completion); +	init_completion(&mcspi_dma->dma_tx_completion); +  no_dma:  	return ret;  } +static void omap2_mcspi_release_dma(struct spi_master *master) +{ +	struct omap2_mcspi *mcspi = spi_master_get_devdata(master); +	struct omap2_mcspi_dma	*mcspi_dma; +	int i; + +	for (i = 0; i < master->num_chipselect; i++) { +		mcspi_dma = &mcspi->dma_channels[i]; + +		if (mcspi_dma->dma_rx) { +			dma_release_channel(mcspi_dma->dma_rx); +			mcspi_dma->dma_rx = NULL; +		} +		if (mcspi_dma->dma_tx) { +			dma_release_channel(mcspi_dma->dma_tx); +			mcspi_dma->dma_tx = NULL; +		} +	} +} +  static int omap2_mcspi_setup(struct spi_device *spi)  {  	int			ret;  	struct omap2_mcspi	*mcspi = spi_master_get_devdata(spi->master);  	struct omap2_mcspi_regs	*ctx = &mcspi->ctx; -	struct omap2_mcspi_dma	*mcspi_dma;  	struct omap2_mcspi_cs	*cs = spi->controller_state; -	mcspi_dma = &mcspi->dma_channels[spi->chip_select]; -  	if (!cs) {  		cs = kzalloc(sizeof *cs, GFP_KERNEL);  		if (!cs) @@ -1042,13 +1055,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)  		}  	} -	if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) { -		ret = omap2_mcspi_request_dma(spi); -		if (ret) -			dev_warn(&spi->dev, "not using DMA for McSPI (%d)\n", -				 ret); -	} -  	ret = pm_runtime_get_sync(mcspi->dev);  	if (ret < 0) {  		pm_runtime_put_noidle(mcspi->dev); @@ -1065,12 +1071,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)  static void omap2_mcspi_cleanup(struct spi_device *spi)  { -	struct omap2_mcspi	*mcspi; -	struct omap2_mcspi_dma	*mcspi_dma;  	struct omap2_mcspi_cs	*cs; -	mcspi = spi_master_get_devdata(spi->master); -  	if (spi->controller_state) {  		/* Unlink controller state from context save list */  		cs = spi->controller_state; @@ -1079,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)  		kfree(cs);  	} -	if (spi->chip_select < spi->master->num_chipselect) { -		mcspi_dma = &mcspi->dma_channels[spi->chip_select]; - -		if (mcspi_dma->dma_rx) { -			dma_release_channel(mcspi_dma->dma_rx); -			mcspi_dma->dma_rx = NULL; -		} -		if (mcspi_dma->dma_tx) { -			dma_release_channel(mcspi_dma->dma_tx); -			mcspi_dma->dma_tx = NULL; -		} -	} -  	if (gpio_is_valid(spi->cs_gpio))  		gpio_free(spi->cs_gpio);  } @@ -1302,9 +1291,24 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,  	if (spi_controller_is_slave(master))  		return true; +	master->dma_rx = mcspi_dma->dma_rx; +	master->dma_tx = mcspi_dma->dma_tx; +  	return (xfer->len >= DMA_MIN_BYTES);  } +static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi) +{ +	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); +	struct omap2_mcspi_dma *mcspi_dma = +		&mcspi->dma_channels[spi->chip_select]; + +	if (mcspi->max_xfer_len && mcspi_dma->dma_rx) +		return mcspi->max_xfer_len; + +	return SIZE_MAX; +} +  static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)  {  	struct spi_master	*master = mcspi->master; @@ -1373,6 +1377,11 @@ static struct omap2_mcspi_platform_config omap4_pdata = {  	.regs_offset = OMAP4_MCSPI_REG_OFFSET,  }; +static struct omap2_mcspi_platform_config am654_pdata = { +	.regs_offset = OMAP4_MCSPI_REG_OFFSET, +	.max_xfer_len = SZ_4K - 1, +}; +  static const struct of_device_id omap_mcspi_of_match[] = {  	{  		.compatible = "ti,omap2-mcspi", @@ -1382,6 +1391,10 @@ static const struct of_device_id omap_mcspi_of_match[] = {  		.compatible = "ti,omap4-mcspi",  		.data = &omap4_pdata,  	}, +	{ +		.compatible = "ti,am654-mcspi", +		.data = &am654_pdata, +	},  	{ },  };  MODULE_DEVICE_TABLE(of, omap_mcspi_of_match); @@ -1439,6 +1452,10 @@ static int omap2_mcspi_probe(struct platform_device *pdev)  		mcspi->pin_dir = pdata->pin_dir;  	}  	regs_offset = pdata->regs_offset; +	if (pdata->max_xfer_len) { +		mcspi->max_xfer_len = pdata->max_xfer_len; +		master->max_transfer_size = omap2_mcspi_max_xfer_size; +	}  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	mcspi->base = devm_ioremap_resource(&pdev->dev, r); @@ -1464,6 +1481,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev)  	for (i = 0; i < master->num_chipselect; i++) {  		sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);  		sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i); + +		status = omap2_mcspi_request_dma(mcspi, +						 &mcspi->dma_channels[i]); +		if (status == -EPROBE_DEFER) +			goto free_master;  	}  	status = platform_get_irq(pdev, 0); @@ -1501,6 +1523,7 @@ disable_pm:  	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev);  free_master: +	omap2_mcspi_release_dma(master);  	spi_master_put(master);  	return status;  } @@ -1510,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev)  	struct spi_master *master = platform_get_drvdata(pdev);  	struct omap2_mcspi *mcspi = spi_master_get_devdata(master); +	omap2_mcspi_release_dma(master); +  	pm_runtime_dont_use_autosuspend(mcspi->dev);  	pm_runtime_put_sync(mcspi->dev);  	pm_runtime_disable(&pdev->dev); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 4c7a71f0fb3e..2e318158fca9 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -70,6 +70,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");  #define LPSS_CAPS_CS_EN_SHIFT			9  #define LPSS_CAPS_CS_EN_MASK			(0xf << LPSS_CAPS_CS_EN_SHIFT) +#define LPSS_PRIV_CLOCK_GATE 0x38 +#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3 +#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3 +  struct lpss_config {  	/* LPSS offset from drv_data->ioaddr */  	unsigned offset; @@ -86,6 +90,8 @@ struct lpss_config {  	unsigned cs_sel_shift;  	unsigned cs_sel_mask;  	unsigned cs_num; +	/* Quirks */ +	unsigned cs_clk_stays_gated : 1;  };  /* Keep these sorted with enum pxa_ssp_type */ @@ -156,6 +162,7 @@ static const struct lpss_config lpss_platforms[] = {  		.tx_threshold_hi = 56,  		.cs_sel_shift = 8,  		.cs_sel_mask = 3 << 8, +		.cs_clk_stays_gated = true,  	},  }; @@ -383,6 +390,22 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)  	else  		value |= LPSS_CS_CONTROL_CS_HIGH;  	__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); +	if (config->cs_clk_stays_gated) { +		u32 clkgate; + +		/* +		 * Changing CS alone when dynamic clock gating is on won't +		 * actually flip CS at that time. This ruins SPI transfers +		 * that specify delays, or have no data. Toggle the clock mode +		 * to force on briefly to poke the CS pin to move. +		 */ +		clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE); +		value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) | +			LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON; + +		__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value); +		__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate); +	}  }  static void cs_assert(struct spi_device *spi) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index dd3434a407ea..a364b99497e2 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1217,6 +1217,11 @@ static int spi_qup_suspend(struct device *device)  	struct spi_qup *controller = spi_master_get_devdata(master);  	int ret; +	if (pm_runtime_suspended(device)) { +		ret = spi_qup_pm_resume_runtime(device); +		if (ret) +			return ret; +	}  	ret = spi_master_suspend(master);  	if (ret)  		return ret; @@ -1225,10 +1230,8 @@ static int spi_qup_suspend(struct device *device)  	if (ret)  		return ret; -	if (!pm_runtime_suspended(device)) { -		clk_disable_unprepare(controller->cclk); -		clk_disable_unprepare(controller->iclk); -	} +	clk_disable_unprepare(controller->cclk); +	clk_disable_unprepare(controller->iclk);  	return 0;  } diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 60c4de4e4485..7412a3042a8d 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -401,9 +401,6 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)  	zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry); -	/* Dummy generic FIFO entry */ -	zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0); -  	/* Manually start the generic FIFO command */  	zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,  			zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 38b4c78df506..755221bc3745 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2639,7 +2639,7 @@ int spi_register_controller(struct spi_controller *ctlr)  		if (ctlr->use_gpio_descriptors) {  			status = spi_get_gpio_descs(ctlr);  			if (status) -				return status; +				goto free_bus_id;  			/*  			 * A controller using GPIO descriptors always  			 * supports SPI_CS_HIGH if need be. @@ -2649,7 +2649,7 @@ int spi_register_controller(struct spi_controller *ctlr)  			/* Legacy code path for GPIOs from DT */  			status = of_spi_get_gpio_numbers(ctlr);  			if (status) -				return status; +				goto free_bus_id;  		}  	} @@ -2657,17 +2657,14 @@ int spi_register_controller(struct spi_controller *ctlr)  	 * Even if it's just one always-selected device, there must  	 * be at least one chipselect.  	 */ -	if (!ctlr->num_chipselect) -		return -EINVAL; +	if (!ctlr->num_chipselect) { +		status = -EINVAL; +		goto free_bus_id; +	}  	status = device_add(&ctlr->dev); -	if (status < 0) { -		/* free bus id */ -		mutex_lock(&board_lock); -		idr_remove(&spi_master_idr, ctlr->bus_num); -		mutex_unlock(&board_lock); -		goto done; -	} +	if (status < 0) +		goto free_bus_id;  	dev_dbg(dev, "registered %s %s\n",  			spi_controller_is_slave(ctlr) ? "slave" : "master",  			dev_name(&ctlr->dev)); @@ -2683,11 +2680,7 @@ int spi_register_controller(struct spi_controller *ctlr)  		status = spi_controller_initialize_queue(ctlr);  		if (status) {  			device_del(&ctlr->dev); -			/* free bus id */ -			mutex_lock(&board_lock); -			idr_remove(&spi_master_idr, ctlr->bus_num); -			mutex_unlock(&board_lock); -			goto done; +			goto free_bus_id;  		}  	}  	/* add statistics */ @@ -2702,7 +2695,12 @@ int spi_register_controller(struct spi_controller *ctlr)  	/* Register devices from the device tree and ACPI */  	of_register_spi_devices(ctlr);  	acpi_register_spi_devices(ctlr); -done: +	return status; + +free_bus_id: +	mutex_lock(&board_lock); +	idr_remove(&spi_master_idr, ctlr->bus_num); +	mutex_unlock(&board_lock);  	return status;  }  EXPORT_SYMBOL_GPL(spi_register_controller); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 1e217e3e9486..2ab6e782f14c 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -396,6 +396,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  		else  			retval = get_user(tmp, (u32 __user *)arg);  		if (retval == 0) { +			struct spi_controller *ctlr = spi->controller;  			u32	save = spi->mode;  			if (tmp & ~SPI_MODE_MASK) { @@ -403,6 +404,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  				break;  			} +			if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods && +			    ctlr->cs_gpiods[spi->chip_select]) +				tmp |= SPI_CS_HIGH; +  			tmp |= spi->mode & ~SPI_MODE_MASK;  			spi->mode = (u16)tmp;  			retval = spi_setup(spi); |