at91/atmel-mci: inclusion of sd/mmc driver in at91sam9g45 chip and board
authorNicolas Ferre <nicolas.ferre@atmel.com>
Fri, 22 Oct 2010 16:27:48 +0000 (18:27 +0200)
committerNicolas Ferre <nicolas.ferre@atmel.com>
Tue, 26 Oct 2010 09:32:49 +0000 (11:32 +0200)
This adds the support of atmel-mci sd/mmc driver in at91sam9g45 devices and
board files. This also configures the DMA controller slave interface for
at_hdmac dmaengine driver.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/board-sam9m10g45ek.c
drivers/mmc/host/Kconfig

index 1276bab..1e8f275 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
+#include <linux/atmel-mci.h>
 
 #include <linux/fb.h>
 #include <video/atmel_lcdc.h>
@@ -25,6 +26,7 @@
 #include <mach/at91sam9g45_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
+#include <mach/atmel-mci.h>
 
 #include "generic.h"
 
@@ -349,6 +351,169 @@ void __init at91_add_device_eth(struct at91_eth_data *data) {}
 #endif
 
 
+/* --------------------------------------------------------------------
+ *  MMC / SD
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct mci_platform_data mmc0_data, mmc1_data;
+
+static struct resource mmc0_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_BASE_MCI0,
+               .end    = AT91SAM9G45_BASE_MCI0 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9G45_ID_MCI0,
+               .end    = AT91SAM9G45_ID_MCI0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at91sam9g45_mmc0_device = {
+       .name           = "atmel_mci",
+       .id             = 0,
+       .dev            = {
+                               .dma_mask               = &mmc_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &mmc0_data,
+       },
+       .resource       = mmc0_resources,
+       .num_resources  = ARRAY_SIZE(mmc0_resources),
+};
+
+static struct resource mmc1_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_BASE_MCI1,
+               .end    = AT91SAM9G45_BASE_MCI1 + SZ_16K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9G45_ID_MCI1,
+               .end    = AT91SAM9G45_ID_MCI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device at91sam9g45_mmc1_device = {
+       .name           = "atmel_mci",
+       .id             = 1,
+       .dev            = {
+                               .dma_mask               = &mmc_dmamask,
+                               .coherent_dma_mask      = DMA_BIT_MASK(32),
+                               .platform_data          = &mmc1_data,
+       },
+       .resource       = mmc1_resources,
+       .num_resources  = ARRAY_SIZE(mmc1_resources),
+};
+
+/* Consider only one slot : slot 0 */
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+{
+
+       if (!data)
+               return;
+
+       /* Must have at least one usable slot */
+       if (!data->slot[0].bus_width)
+               return;
+
+#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
+       {
+       struct at_dma_slave     *atslave;
+       struct mci_dma_data     *alt_atslave;
+
+       alt_atslave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL);
+       atslave = &alt_atslave->sdata;
+
+       /* DMA slave channel configuration */
+       atslave->dma_dev = &at_hdmac_device.dev;
+       atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT;
+       atslave->cfg = ATC_FIFOCFG_HALFFIFO
+                       | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
+       atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
+       if (mmc_id == 0)        /* MCI0 */
+               atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
+                             | ATC_DST_PER(AT_DMA_ID_MCI0);
+
+       else                    /* MCI1 */
+               atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI1)
+                             | ATC_DST_PER(AT_DMA_ID_MCI1);
+
+       data->dma_slave = alt_atslave;
+       }
+#endif
+
+
+       /* input/irq */
+       if (data->slot[0].detect_pin) {
+               at91_set_gpio_input(data->slot[0].detect_pin, 1);
+               at91_set_deglitch(data->slot[0].detect_pin, 1);
+       }
+       if (data->slot[0].wp_pin)
+               at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+       if (mmc_id == 0) {              /* MCI0 */
+
+               /* CLK */
+               at91_set_A_periph(AT91_PIN_PA0, 0);
+
+               /* CMD */
+               at91_set_A_periph(AT91_PIN_PA1, 1);
+
+               /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+               at91_set_A_periph(AT91_PIN_PA2, 1);
+               if (data->slot[0].bus_width == 4) {
+                       at91_set_A_periph(AT91_PIN_PA3, 1);
+                       at91_set_A_periph(AT91_PIN_PA4, 1);
+                       at91_set_A_periph(AT91_PIN_PA5, 1);
+                       if (data->slot[0].bus_width == 8) {
+                               at91_set_A_periph(AT91_PIN_PA6, 1);
+                               at91_set_A_periph(AT91_PIN_PA7, 1);
+                               at91_set_A_periph(AT91_PIN_PA8, 1);
+                               at91_set_A_periph(AT91_PIN_PA9, 1);
+                       }
+               }
+
+               mmc0_data = *data;
+               at91_clock_associate("mci0_clk", &at91sam9g45_mmc0_device.dev, "mci_clk");
+               platform_device_register(&at91sam9g45_mmc0_device);
+
+       } else {                        /* MCI1 */
+
+               /* CLK */
+               at91_set_A_periph(AT91_PIN_PA31, 0);
+
+               /* CMD */
+               at91_set_A_periph(AT91_PIN_PA22, 1);
+
+               /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+               at91_set_A_periph(AT91_PIN_PA23, 1);
+               if (data->slot[0].bus_width == 4) {
+                       at91_set_A_periph(AT91_PIN_PA24, 1);
+                       at91_set_A_periph(AT91_PIN_PA25, 1);
+                       at91_set_A_periph(AT91_PIN_PA26, 1);
+                       if (data->slot[0].bus_width == 8) {
+                               at91_set_A_periph(AT91_PIN_PA27, 1);
+                               at91_set_A_periph(AT91_PIN_PA28, 1);
+                               at91_set_A_periph(AT91_PIN_PA29, 1);
+                               at91_set_A_periph(AT91_PIN_PA30, 1);
+                       }
+               }
+
+               mmc1_data = *data;
+               at91_clock_associate("mci1_clk", &at91sam9g45_mmc1_device.dev, "mci_clk");
+               platform_device_register(&at91sam9g45_mmc1_device);
+
+       }
+}
+#else
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+#endif
+
+
 /* --------------------------------------------------------------------
  *  NAND / SmartMedia
  * -------------------------------------------------------------------- */
index 7913984..86ff4b5 100644 (file)
@@ -24,7 +24,9 @@
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/clk.h>
+#include <linux/atmel-mci.h>
 
+#include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
@@ -97,6 +99,25 @@ static struct spi_board_info ek_spi_devices[] = {
 };
 
 
+/*
+ * MCI (SD/MMC)
+ */
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PD10,
+       },
+};
+
+static struct mci_platform_data __initdata mci1_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PD11,
+               .wp_pin         = AT91_PIN_PD29,
+       },
+};
+
+
 /*
  * MACB Ethernet device
  */
@@ -380,6 +401,9 @@ static void __init ek_board_init(void)
        at91_add_device_usba(&ek_usba_udc_data);
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+       /* MMC */
+       at91_add_device_mci(0, &mci0_data);
+       at91_add_device_mci(1, &mci1_data);
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* NAND */
index 68d1279..1a02611 100644 (file)
@@ -237,7 +237,7 @@ endchoice
 
 config MMC_ATMELMCI_DMA
        bool "Atmel MCI DMA support (EXPERIMENTAL)"
-       depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
+       depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE && EXPERIMENTAL
        help
          Say Y here to have the Atmel MCI driver use a DMA engine to
          do data transfers and thus increase the throughput and