|
|
@@ -995,19 +995,11 @@ 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 spi_master *master,
|
|
|
+ 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_ch_name);
|
|
|
if (IS_ERR(mcspi_dma->dma_rx)) {
|
|
|
@@ -1025,20 +1017,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)
|
|
|
@@ -1063,13 +1075,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);
|
|
|
@@ -1086,12 +1091,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;
|
|
|
@@ -1100,19 +1101,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);
|
|
|
}
|
|
|
@@ -1323,6 +1311,9 @@ 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);
|
|
|
}
|
|
|
|
|
|
@@ -1510,6 +1501,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(master,
|
|
|
+ &mcspi->dma_channels[i]);
|
|
|
+ if (status == -EPROBE_DEFER)
|
|
|
+ goto free_master;
|
|
|
}
|
|
|
|
|
|
status = platform_get_irq(pdev, 0);
|
|
|
@@ -1547,6 +1543,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;
|
|
|
}
|
|
|
@@ -1556,6 +1553,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);
|