diff options
Diffstat (limited to 'drivers/spi/spi-omap2-mcspi.c')
| -rw-r--r-- | drivers/spi/spi-omap2-mcspi.c | 103 | 
1 files changed, 64 insertions, 39 deletions
| 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); |