Allow the use of another DMA controller driver in atmel-mci sd/mmc driver. This
adds a generic dma_slave pointer to the mci platform structure where we can
store DMA controller information. In atmel-mci we use information provided by
this structure to initialize the driver (with new helper functions that are
architecture dependant).
This also adds at32/avr32 chip modifications to cope with this new access
method.

Signed-off-by: Nicolas Ferre <[email protected]>
---
 arch/avr32/mach-at32ap/at32ap700x.c |    6 ++-
 drivers/mmc/host/atmel-mci.c        |   82 ++++++++++++++++++++++++++---------
 include/linux/atmel-mci.h           |    3 +-
 3 files changed, 68 insertions(+), 23 deletions(-)

diff --git a/arch/avr32/mach-at32ap/at32ap700x.c 
b/arch/avr32/mach-at32ap/at32ap700x.c
index eb9d4dc..d1fe145 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -1320,7 +1320,7 @@ struct platform_device *__init
 at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 {
        struct platform_device          *pdev;
-       struct dw_dma_slave             *dws = &data->dma_slave;
+       struct dw_dma_slave             *dws;
        u32                             pioa_mask;
        u32                             piob_mask;
 
@@ -1339,6 +1339,8 @@ at32_add_device_mci(unsigned int id, struct 
mci_platform_data *data)
                                ARRAY_SIZE(atmel_mci0_resource)))
                goto fail;
 
+       dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
+
        dws->dma_dev = &dw_dmac0_device.dev;
        dws->reg_width = DW_DMA_SLAVE_WIDTH_32BIT;
        dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
@@ -1346,6 +1348,8 @@ at32_add_device_mci(unsigned int id, struct 
mci_platform_data *data)
        dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
                                | DWC_CFGL_HS_SRC_POL);
 
+       data->dma_slave = dws;
+
        if (platform_device_add_data(pdev, data,
                                sizeof(struct mci_platform_data)))
                goto fail;
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 065fa81..1689396 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1575,16 +1575,71 @@ static void __exit atmci_cleanup_slot(struct 
atmel_mci_slot *slot,
 }
 
 #ifdef CONFIG_MMC_ATMELMCI_DMA
-static bool filter(struct dma_chan *chan, void *slave)
+static struct device *find_slave_dev(void *slave)
+{
+       if (!slave)
+               return NULL;
+
+       if (cpu_is_at32ap7000())
+               return ((struct dw_dma_slave *)slave)->dma_dev;
+       else
+               return ((struct at_dma_slave *)slave)->dma_dev;
+}
+
+static void setup_dma_addr(struct mci_platform_data *pdata,
+                       dma_addr_t tx_addr, dma_addr_t rx_addr)
 {
-       struct dw_dma_slave *dws = slave;
+       if (!pdata)
+               return;
+
+       if (cpu_is_at32ap7000()) {
+               struct dw_dma_slave *dws = pdata->dma_slave;
+
+               dws->tx_reg = tx_addr;
+               dws->rx_reg = rx_addr;
+       } else {
+               struct at_dma_slave *ats = pdata->dma_slave;
 
-       if (dws->dma_dev == chan->device->dev) {
-               chan->private = dws;
+               ats->tx_reg = tx_addr;
+               ats->rx_reg = rx_addr;
+       }
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       if (find_slave_dev(slave) == chan->device->dev) {
+               chan->private = slave;
                return true;
-       } else
+       } else {
                return false;
+       }
+}
+
+static void atmci_configure_dma(struct atmel_mci *host)
+{
+       struct mci_platform_data        *pdata;
+
+       if (host == NULL)
+               return;
+
+       pdata = host->pdev->dev.platform_data;
+
+       if (pdata && find_slave_dev(pdata->dma_slave)) {
+               dma_cap_mask_t mask;
+
+               setup_dma_addr(pdata, host->mapbase + MCI_TDR,
+                                     host->mapbase + MCI_RDR);
+
+               /* Try to grab a DMA channel */
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+               host->dma.chan = dma_request_channel(mask, filter, 
pdata->dma_slave);
+       }
+       if (!host->dma.chan)
+               dev_notice(&host->pdev->dev, "DMA not available, using PIO\n");
 }
+#else
+static void atmci_configure_dma(struct atmel_mci *host) {}
 #endif
 
 static int __init atmci_probe(struct platform_device *pdev)
@@ -1638,22 +1693,7 @@ static int __init atmci_probe(struct platform_device 
*pdev)
        if (ret)
                goto err_request_irq;
 
-#ifdef CONFIG_MMC_ATMELMCI_DMA
-       if (pdata->dma_slave.dma_dev) {
-               struct dw_dma_slave *dws = &pdata->dma_slave;
-               dma_cap_mask_t mask;
-
-               dws->tx_reg = regs->start + MCI_TDR;
-               dws->rx_reg = regs->start + MCI_RDR;
-
-               /* Try to grab a DMA channel */
-               dma_cap_zero(mask);
-               dma_cap_set(DMA_SLAVE, mask);
-               host->dma.chan = dma_request_channel(mask, filter, dws);
-       }
-       if (!host->dma.chan)
-               dev_notice(&pdev->dev, "DMA not available, using PIO\n");
-#endif /* CONFIG_MMC_ATMELMCI_DMA */
+       atmci_configure_dma(host);
 
        platform_set_drvdata(pdev, host);
 
diff --git a/include/linux/atmel-mci.h b/include/linux/atmel-mci.h
index 57b1846..e26b7de 100644
--- a/include/linux/atmel-mci.h
+++ b/include/linux/atmel-mci.h
@@ -4,6 +4,7 @@
 #define ATMEL_MCI_MAX_NR_SLOTS 2
 
 #include <linux/dw_dmac.h>
+#include <mach/at_hdmac.h>
 
 /**
  * struct mci_slot_pdata - board-specific per-slot configuration
@@ -34,7 +35,7 @@ struct mci_slot_pdata {
  * @slot: Per-slot configuration data.
  */
 struct mci_platform_data {
-       struct dw_dma_slave     dma_slave;
+       void                    *dma_slave;
        struct mci_slot_pdata   slot[ATMEL_MCI_MAX_NR_SLOTS];
 };
 
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to