diff options
author | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-08-07 08:08:49 -0400 |
---|---|---|
committer | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-10-05 14:39:21 -0400 |
commit | 6b918657b7431e4c5c953b8222ae2f4fc1b2576a (patch) | |
tree | bb3bb53d91501064821ea860a490dc1b3633df52 /arch/avr32/mach-at32ap | |
parent | 945533b538c6c6185afc77ba4a81eeba8f6ef8dd (diff) |
atmel-mci: Platform code for supporting multiple mmc slots
Add the necessary platform infrastructure to support multiple mmc/sdcard
slots all at once through a single controller. Currently, the driver
will use the first valid slot it finds and stick with that, but later
patches will add support for switching between several slots on the fly.
Extend the platform data structure with per-slot information: MMC/SDcard
bus width and card detect/write protect pins. This will affect the pin
muxing as well as the capabilities announced to the mmc core.
Note that board code is now required to supply a mci_platform_data
struct to at32_add_device_mci().
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/mach-at32ap')
-rw-r--r-- | arch/avr32/mach-at32ap/at32ap700x.c | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index e01dbe4ebb40..9967d5a3b6eb 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c | |||
@@ -1272,10 +1272,13 @@ static struct clk atmel_mci0_pclk = { | |||
1272 | struct platform_device *__init | 1272 | struct platform_device *__init |
1273 | at32_add_device_mci(unsigned int id, struct mci_platform_data *data) | 1273 | at32_add_device_mci(unsigned int id, struct mci_platform_data *data) |
1274 | { | 1274 | { |
1275 | struct mci_platform_data _data; | ||
1276 | struct platform_device *pdev; | 1275 | struct platform_device *pdev; |
1277 | 1276 | ||
1278 | if (id != 0) | 1277 | if (id != 0 || !data) |
1278 | return NULL; | ||
1279 | |||
1280 | /* Must have at least one usable slot */ | ||
1281 | if (!data->slot[0].bus_width && !data->slot[1].bus_width) | ||
1279 | return NULL; | 1282 | return NULL; |
1280 | 1283 | ||
1281 | pdev = platform_device_alloc("atmel_mci", id); | 1284 | pdev = platform_device_alloc("atmel_mci", id); |
@@ -1286,28 +1289,61 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data) | |||
1286 | ARRAY_SIZE(atmel_mci0_resource))) | 1289 | ARRAY_SIZE(atmel_mci0_resource))) |
1287 | goto fail; | 1290 | goto fail; |
1288 | 1291 | ||
1289 | if (!data) { | ||
1290 | data = &_data; | ||
1291 | memset(data, -1, sizeof(struct mci_platform_data)); | ||
1292 | data->detect_pin = GPIO_PIN_NONE; | ||
1293 | data->wp_pin = GPIO_PIN_NONE; | ||
1294 | } | ||
1295 | 1292 | ||
1296 | if (platform_device_add_data(pdev, data, | 1293 | if (platform_device_add_data(pdev, data, |
1297 | sizeof(struct mci_platform_data))) | 1294 | sizeof(struct mci_platform_data))) |
1298 | goto fail; | 1295 | goto fail; |
1299 | 1296 | ||
1300 | select_peripheral(PA(10), PERIPH_A, 0); /* CLK */ | 1297 | /* CLK line is common to both slots */ |
1301 | select_peripheral(PA(11), PERIPH_A, 0); /* CMD */ | 1298 | select_peripheral(PA(10), PERIPH_A, 0); |
1302 | select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */ | ||
1303 | select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */ | ||
1304 | select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */ | ||
1305 | select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */ | ||
1306 | 1299 | ||
1307 | if (gpio_is_valid(data->detect_pin)) | 1300 | switch (data->slot[0].bus_width) { |
1308 | at32_select_gpio(data->detect_pin, 0); | 1301 | case 4: |
1309 | if (gpio_is_valid(data->wp_pin)) | 1302 | select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */ |
1310 | at32_select_gpio(data->wp_pin, 0); | 1303 | select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */ |
1304 | select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */ | ||
1305 | /* fall through */ | ||
1306 | case 1: | ||
1307 | select_peripheral(PA(11), PERIPH_A, 0); /* CMD */ | ||
1308 | select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */ | ||
1309 | |||
1310 | if (gpio_is_valid(data->slot[0].detect_pin)) | ||
1311 | at32_select_gpio(data->slot[0].detect_pin, 0); | ||
1312 | if (gpio_is_valid(data->slot[0].wp_pin)) | ||
1313 | at32_select_gpio(data->slot[0].wp_pin, 0); | ||
1314 | break; | ||
1315 | case 0: | ||
1316 | /* Slot is unused */ | ||
1317 | break; | ||
1318 | default: | ||
1319 | goto fail; | ||
1320 | } | ||
1321 | |||
1322 | switch (data->slot[1].bus_width) { | ||
1323 | case 4: | ||
1324 | select_peripheral(PB(8), PERIPH_B, 0); /* DATA1 */ | ||
1325 | select_peripheral(PB(9), PERIPH_B, 0); /* DATA2 */ | ||
1326 | select_peripheral(PB(10), PERIPH_B, 0); /* DATA3 */ | ||
1327 | /* fall through */ | ||
1328 | case 1: | ||
1329 | select_peripheral(PB(6), PERIPH_B, 0); /* CMD */ | ||
1330 | select_peripheral(PB(7), PERIPH_B, 0); /* DATA0 */ | ||
1331 | |||
1332 | if (gpio_is_valid(data->slot[1].detect_pin)) | ||
1333 | at32_select_gpio(data->slot[1].detect_pin, 0); | ||
1334 | if (gpio_is_valid(data->slot[1].wp_pin)) | ||
1335 | at32_select_gpio(data->slot[1].wp_pin, 0); | ||
1336 | break; | ||
1337 | case 0: | ||
1338 | /* Slot is unused */ | ||
1339 | break; | ||
1340 | default: | ||
1341 | if (!data->slot[0].bus_width) | ||
1342 | goto fail; | ||
1343 | |||
1344 | data->slot[1].bus_width = 0; | ||
1345 | break; | ||
1346 | } | ||
1311 | 1347 | ||
1312 | atmel_mci0_pclk.dev = &pdev->dev; | 1348 | atmel_mci0_pclk.dev = &pdev->dev; |
1313 | 1349 | ||