at91/atmel-mci: inclusion of sd/mmc driver in at91sam9g45 chip and board

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>
This commit is contained in:
Nicolas Ferre 2010-10-22 18:27:48 +02:00
parent a2a571b74a
commit 75305d768d
3 changed files with 190 additions and 1 deletions

View 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
* -------------------------------------------------------------------- */

View 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 */

View 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