aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-06-30 12:35:03 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-07-15 08:14:49 -0400
commit7d2be0749a59096a334c94dc48f43294193cb8ed (patch)
treea14faa58c61071fb548c223268650153b5aa865a /arch
parent6d37333163025b46afbcad434ec9a5f2e88e7254 (diff)
atmel-mci: Driver for Atmel on-chip MMC controllers
This is a driver for the MMC controller on the AP7000 chips from Atmel. It should in theory work on AT91 systems too with some tweaking, but since the DMA interface is quite different, it's not entirely clear if it's worth merging this with the at91_mci driver. This driver has been around for a while in BSPs and kernel sources provided by Atmel, but this particular version uses the generic DMA Engine framework (with the slave extensions) instead of an avr32-only DMA controller framework. This driver can also use PIO transfers when no DMA channels are available, and for transfers where using DMA may be difficult or impractical for some reason (e.g. the DMA setup overhead is usually not worth it for very short transfers, and badly aligned buffers or lengths are difficult to handle.) Currently, the driver only support PIO transfers. DMA support has been split out to a separate patch to hopefully make it easier to review. The driver has been tested using mmc-block and ext3fs on several SD, SDHC and MMC+ cards. Reads and writes work fine, with read transfer rates up to 3.5 MiB/s on fast cards with debugging disabled. The driver has also been tested using the mmc_test module on the same cards. All tests except 7, 9, 15 and 17 succeed. The first two are unsupported by all the cards I have, so I don't know if the driver handles this correctly. The last two fail because the hardware flags a Data CRC Error instead of a Data Timeout error. I'm not sure how to deal with that. Documentation for this controller can be found in many data sheets from Atmel, including the AT32AP7000 data sheet which can be found here: http://www.atmel.com/dyn/products/datasheets.asp?family_id=682 Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'arch')
-rw-r--r--arch/avr32/boards/atngw100/setup.c7
-rw-r--r--arch/avr32/boards/atstk1000/atstk1002.c3
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c30
3 files changed, 35 insertions, 5 deletions
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index a51bb9fb3c89..c7fe94d03a1e 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -19,6 +19,7 @@
19#include <linux/leds.h> 19#include <linux/leds.h>
20#include <linux/spi/spi.h> 20#include <linux/spi/spi.h>
21 21
22#include <asm/atmel-mci.h>
22#include <asm/io.h> 23#include <asm/io.h>
23#include <asm/setup.h> 24#include <asm/setup.h>
24 25
@@ -51,6 +52,11 @@ static struct spi_board_info spi0_board_info[] __initdata = {
51 }, 52 },
52}; 53};
53 54
55static struct mci_platform_data __initdata mci0_data = {
56 .detect_pin = GPIO_PIN_PC(25),
57 .wp_pin = GPIO_PIN_PE(0),
58};
59
54/* 60/*
55 * The next two functions should go away as the boot loader is 61 * The next two functions should go away as the boot loader is
56 * supposed to initialize the macb address registers with a valid 62 * supposed to initialize the macb address registers with a valid
@@ -170,6 +176,7 @@ static int __init atngw100_init(void)
170 set_hw_addr(at32_add_device_eth(1, &eth_data[1])); 176 set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
171 177
172 at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); 178 at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
179 at32_add_device_mci(0, &mci0_data);
173 at32_add_device_usba(0, NULL); 180 at32_add_device_usba(0, NULL);
174 181
175 for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) { 182 for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 86b363c1c25b..e11659b732fa 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -234,6 +234,9 @@ static int __init atstk1002_init(void)
234#ifdef CONFIG_BOARD_ATSTK100X_SPI1 234#ifdef CONFIG_BOARD_ATSTK100X_SPI1
235 at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); 235 at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
236#endif 236#endif
237#ifndef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
238 at32_add_device_mci(0, NULL);
239#endif
237#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM 240#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
238 set_hw_addr(at32_add_device_eth(1, &eth_data[1])); 241 set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
239#else 242#else
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 07b21b121eef..021d51217184 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -14,6 +14,7 @@
14#include <linux/spi/spi.h> 14#include <linux/spi/spi.h>
15#include <linux/usb/atmel_usba_udc.h> 15#include <linux/usb/atmel_usba_udc.h>
16 16
17#include <asm/atmel-mci.h>
17#include <asm/io.h> 18#include <asm/io.h>
18#include <asm/irq.h> 19#include <asm/irq.h>
19 20
@@ -1278,20 +1279,32 @@ static struct clk atmel_mci0_pclk = {
1278 .index = 9, 1279 .index = 9,
1279}; 1280};
1280 1281
1281struct platform_device *__init at32_add_device_mci(unsigned int id) 1282struct platform_device *__init
1283at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
1282{ 1284{
1283 struct platform_device *pdev; 1285 struct mci_platform_data _data;
1286 struct platform_device *pdev;
1287 struct dw_dma_slave *dws;
1284 1288
1285 if (id != 0) 1289 if (id != 0)
1286 return NULL; 1290 return NULL;
1287 1291
1288 pdev = platform_device_alloc("atmel_mci", id); 1292 pdev = platform_device_alloc("atmel_mci", id);
1289 if (!pdev) 1293 if (!pdev)
1290 return NULL; 1294 goto fail;
1291 1295
1292 if (platform_device_add_resources(pdev, atmel_mci0_resource, 1296 if (platform_device_add_resources(pdev, atmel_mci0_resource,
1293 ARRAY_SIZE(atmel_mci0_resource))) 1297 ARRAY_SIZE(atmel_mci0_resource)))
1294 goto err_add_resources; 1298 goto fail;
1299
1300 if (!data) {
1301 data = &_data;
1302 memset(data, 0, sizeof(struct mci_platform_data));
1303 }
1304
1305 if (platform_device_add_data(pdev, data,
1306 sizeof(struct mci_platform_data)))
1307 goto fail;
1295 1308
1296 select_peripheral(PA(10), PERIPH_A, 0); /* CLK */ 1309 select_peripheral(PA(10), PERIPH_A, 0); /* CLK */
1297 select_peripheral(PA(11), PERIPH_A, 0); /* CMD */ 1310 select_peripheral(PA(11), PERIPH_A, 0); /* CMD */
@@ -1300,12 +1313,19 @@ struct platform_device *__init at32_add_device_mci(unsigned int id)
1300 select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */ 1313 select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
1301 select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */ 1314 select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
1302 1315
1316 if (data) {
1317 if (data->detect_pin != GPIO_PIN_NONE)
1318 at32_select_gpio(data->detect_pin, 0);
1319 if (data->wp_pin != GPIO_PIN_NONE)
1320 at32_select_gpio(data->wp_pin, 0);
1321 }
1322
1303 atmel_mci0_pclk.dev = &pdev->dev; 1323 atmel_mci0_pclk.dev = &pdev->dev;
1304 1324
1305 platform_device_add(pdev); 1325 platform_device_add(pdev);
1306 return pdev; 1326 return pdev;
1307 1327
1308err_add_resources: 1328fail:
1309 platform_device_put(pdev); 1329 platform_device_put(pdev);
1310 return NULL; 1330 return NULL;
1311} 1331}