spi: davinci: do not allocate DMA channels during SPI device setup
Do not allocate (and de-allocate) SPI DMA channels during setup
(and cleanup) for each SPI device. Instead, allocate the DMA
channels once duing probe and use them for the life time of
the driver.
This makes sense since there are dedicated DMA channels meant
for SPI use.
This also helps remove the unnecessary DMA "sync_dev" variables
being used to store DMA channel information.
Also, the "use_dma" platform variable is now eliminated since
it is possible to check if the platform supports DMA or not
based upon whether DMA resources can be found or not.
Tested-By: Michael Williamson <michael.williamson@criticallink.com>
Tested-By: Brian Niebuhr <bniebuhr@efjohnson.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
diff --git a/arch/arm/mach-davinci/include/mach/spi.h b/arch/arm/mach-davinci/include/mach/spi.h
index 68db6d5..f7586a0 100644
--- a/arch/arm/mach-davinci/include/mach/spi.h
+++ b/arch/arm/mach-davinci/include/mach/spi.h
@@ -31,7 +31,6 @@
u8 num_chipselect;
u8 clk_internal;
u8 intr_line;
- u8 use_dma;
u8 *chip_sel;
bool cshold_bug;
};
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 9695f98..6db4786 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -116,8 +116,6 @@
struct davinci_spi_dma {
int dma_tx_channel;
int dma_rx_channel;
- int dma_tx_sync_dev;
- int dma_rx_sync_dev;
enum dma_event_q eventq;
struct completion dma_tx_completion;
@@ -153,8 +151,6 @@
static struct davinci_spi_config davinci_spi_default_cfg;
-static unsigned use_dma;
-
static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi)
{
if (davinci_spi->rx) {
@@ -391,12 +387,7 @@
static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data)
{
- struct spi_device *spi = (struct spi_device *)data;
- struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
-
- davinci_spi = spi_master_get_devdata(spi->master);
- davinci_spi_dma = &davinci_spi->dma_channels;
+ struct davinci_spi_dma *davinci_spi_dma = data;
if (ch_status == DMA_COMPLETE)
edma_stop(davinci_spi_dma->dma_rx_channel);
@@ -408,12 +399,7 @@
static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data)
{
- struct spi_device *spi = (struct spi_device *)data;
- struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
-
- davinci_spi = spi_master_get_devdata(spi->master);
- davinci_spi_dma = &davinci_spi->dma_channels;
+ struct davinci_spi_dma *davinci_spi_dma = data;
if (ch_status == DMA_COMPLETE)
edma_stop(davinci_spi_dma->dma_tx_channel);
@@ -423,39 +409,6 @@
complete(&davinci_spi_dma->dma_tx_completion);
}
-static int davinci_spi_request_dma(struct spi_device *spi)
-{
- struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
- struct device *sdev;
- int r;
-
- davinci_spi = spi_master_get_devdata(spi->master);
- davinci_spi_dma = &davinci_spi->dma_channels;
- sdev = davinci_spi->bitbang.master->dev.parent;
-
- r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev,
- davinci_spi_dma_rx_callback, spi,
- davinci_spi_dma->eventq);
- if (r < 0) {
- dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n");
- return -EAGAIN;
- }
- davinci_spi_dma->dma_rx_channel = r;
- r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev,
- davinci_spi_dma_tx_callback, spi,
- davinci_spi_dma->eventq);
- if (r < 0) {
- edma_free_channel(davinci_spi_dma->dma_rx_channel);
- davinci_spi_dma->dma_rx_channel = -1;
- dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n");
- return -EAGAIN;
- }
- davinci_spi_dma->dma_tx_channel = r;
-
- return 0;
-}
-
/**
* davinci_spi_setup - This functions will set default transfer method
* @spi: spi device on which data transfer to be done
@@ -466,7 +419,6 @@
{
int retval = 0;
struct davinci_spi *davinci_spi;
- struct davinci_spi_dma *davinci_spi_dma;
struct davinci_spi_platform_data *pdata;
davinci_spi = spi_master_get_devdata(spi->master);
@@ -494,33 +446,9 @@
clear_io_bits(davinci_spi->base + SPIGCR1,
SPIGCR1_LOOPBACK_MASK);
- if (use_dma) {
- davinci_spi_dma = &davinci_spi->dma_channels;
-
- if ((davinci_spi_dma->dma_rx_channel == -1) ||
- (davinci_spi_dma->dma_tx_channel == -1))
- retval = davinci_spi_request_dma(spi);
- }
-
return retval;
}
-static void davinci_spi_cleanup(struct spi_device *spi)
-{
- if (use_dma) {
- struct davinci_spi *davinci_spi =
- spi_master_get_devdata(spi->master);
- struct davinci_spi_dma *davinci_spi_dma =
- &davinci_spi->dma_channels;
-
- if ((davinci_spi_dma->dma_rx_channel != -1)
- && (davinci_spi_dma->dma_tx_channel != -1)) {
- edma_free_channel(davinci_spi_dma->dma_tx_channel);
- edma_free_channel(davinci_spi_dma->dma_rx_channel);
- }
- }
-}
-
static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
int int_status)
{
@@ -842,6 +770,30 @@
return t->len;
}
+static int davinci_spi_request_dma(struct davinci_spi_dma *davinci_spi_dma)
+{
+ int r;
+
+ r = edma_alloc_channel(davinci_spi_dma->dma_rx_channel,
+ davinci_spi_dma_rx_callback, davinci_spi_dma,
+ davinci_spi_dma->eventq);
+ if (r < 0) {
+ pr_err("Unable to request DMA channel for SPI RX\n");
+ return -EAGAIN;
+ }
+
+ r = edma_alloc_channel(davinci_spi_dma->dma_tx_channel,
+ davinci_spi_dma_tx_callback, davinci_spi_dma,
+ davinci_spi_dma->eventq);
+ if (r < 0) {
+ edma_free_channel(davinci_spi_dma->dma_rx_channel);
+ pr_err("Unable to request DMA channel for SPI TX\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
/**
* davinci_spi_probe - probe function for SPI Master Controller
* @pdev: platform_device structure which contains plateform specific data
@@ -928,45 +880,39 @@
master->bus_num = pdev->id;
master->num_chipselect = pdata->num_chipselect;
master->setup = davinci_spi_setup;
- master->cleanup = davinci_spi_cleanup;
davinci_spi->bitbang.chipselect = davinci_spi_chipselect;
davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer;
davinci_spi->version = pdata->version;
- use_dma = pdata->use_dma;
davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
if (davinci_spi->version == SPI_VERSION_2)
davinci_spi->bitbang.flags |= SPI_READY;
- if (use_dma) {
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (r)
- dma_rx_chan = r->start;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (r)
- dma_tx_chan = r->start;
- r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
- if (r)
- dma_eventq = r->start;
- }
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (r)
+ dma_rx_chan = r->start;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (r)
+ dma_tx_chan = r->start;
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+ if (r)
+ dma_eventq = r->start;
- if (!use_dma ||
- dma_rx_chan == SPI_NO_RESOURCE ||
- dma_tx_chan == SPI_NO_RESOURCE ||
- dma_eventq == SPI_NO_RESOURCE) {
- davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio;
- use_dma = 0;
- } else {
- davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
-
- davinci_spi->dma_channels.dma_rx_channel = -1;
- davinci_spi->dma_channels.dma_rx_sync_dev = dma_rx_chan;
- davinci_spi->dma_channels.dma_tx_channel = -1;
- davinci_spi->dma_channels.dma_tx_sync_dev = dma_tx_chan;
+ davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio;
+ if (dma_rx_chan != SPI_NO_RESOURCE &&
+ dma_tx_chan != SPI_NO_RESOURCE &&
+ dma_eventq != SPI_NO_RESOURCE) {
+ davinci_spi->dma_channels.dma_rx_channel = dma_rx_chan;
+ davinci_spi->dma_channels.dma_tx_channel = dma_tx_chan;
davinci_spi->dma_channels.eventq = dma_eventq;
+ ret = davinci_spi_request_dma(&davinci_spi->dma_channels);
+ if (ret)
+ goto free_clk;
+
+ davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n"
"Using RX channel = %d , TX channel = %d and "
"event queue = %d", dma_rx_chan, dma_tx_chan,
@@ -1015,12 +961,15 @@
ret = spi_bitbang_start(&davinci_spi->bitbang);
if (ret)
- goto free_clk;
+ goto free_dma;
dev_info(&pdev->dev, "Controller at 0x%p\n", davinci_spi->base);
return ret;
+free_dma:
+ edma_free_channel(davinci_spi->dma_channels.dma_tx_channel);
+ edma_free_channel(davinci_spi->dma_channels.dma_rx_channel);
free_clk:
clk_disable(davinci_spi->clk);
clk_put(davinci_spi->clk);