blob: d8776d61b3cc5c83879f7c3d66fdba4c7fd1fb92 [file] [log] [blame]
Pete Popovba264b32005-09-21 06:18:27 +00001/*
Pierre Ossman70f10482007-07-11 20:04:50 +02002 * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
Pete Popovba264b32005-09-21 06:18:27 +00003 *
4 * Copyright (c) 2005, Advanced Micro Devices, Inc.
5 *
6 * Developed with help from the 2.4.30 MMC AU1XXX controller including
7 * the following copyright notices:
8 * Copyright (c) 2003-2004 Embedded Edge, LLC.
9 * Portions Copyright (C) 2002 Embedix, Inc
10 * Copyright 2002 Hewlett-Packard Company
11
12 * 2.6 version of this driver inspired by:
13 * (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
14 * All Rights Reserved.
15 * (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
16 * All Rights Reserved.
17 *
18
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License version 2 as
21 * published by the Free Software Foundation.
22 */
23
24/* Why is a timer used to detect insert events?
25 *
26 * From the AU1100 MMC application guide:
27 * If the Au1100-based design is intended to support both MultiMediaCards
28 * and 1- or 4-data bit SecureDigital cards, then the solution is to
29 * connect a weak (560KOhm) pull-up resistor to connector pin 1.
30 * In doing so, a MMC card never enters SPI-mode communications,
31 * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
32 * (the low to high transition will not occur).
33 *
34 * So we use the timer to check the status manually.
35 */
36
Pete Popovba264b32005-09-21 06:18:27 +000037#include <linux/module.h>
38#include <linux/init.h>
Martin Michlmayrb256f9d2006-03-04 23:01:13 +000039#include <linux/platform_device.h>
Pete Popovba264b32005-09-21 06:18:27 +000040#include <linux/mm.h>
41#include <linux/interrupt.h>
42#include <linux/dma-mapping.h>
Al Viro0ada7a02007-10-27 19:40:46 +010043#include <linux/scatterlist.h>
Manuel Laussc4223c22008-06-09 08:36:13 +020044#include <linux/leds.h>
Pete Popovba264b32005-09-21 06:18:27 +000045#include <linux/mmc/host.h>
Manuel Laussc4223c22008-06-09 08:36:13 +020046
Pete Popovba264b32005-09-21 06:18:27 +000047#include <asm/io.h>
48#include <asm/mach-au1x00/au1000.h>
49#include <asm/mach-au1x00/au1xxx_dbdma.h>
50#include <asm/mach-au1x00/au1100_mmc.h>
Pete Popovba264b32005-09-21 06:18:27 +000051
52#include <au1xxx.h>
53#include "au1xmmc.h"
54
55#define DRIVER_NAME "au1xxx-mmc"
56
57/* Set this to enable special debugging macros */
Manuel Laussc4223c22008-06-09 08:36:13 +020058/* #define DEBUG */
Pete Popovba264b32005-09-21 06:18:27 +000059
Russell Kingc6563172006-03-29 09:30:20 +010060#ifdef DEBUG
61#define DBG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args)
Pete Popovba264b32005-09-21 06:18:27 +000062#else
Russell Kingc6563172006-03-29 09:30:20 +010063#define DBG(fmt, idx, args...)
Pete Popovba264b32005-09-21 06:18:27 +000064#endif
65
Pete Popovba264b32005-09-21 06:18:27 +000066static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
67{
68 u32 val = au_readl(HOST_CONFIG(host));
69 val |= mask;
70 au_writel(val, HOST_CONFIG(host));
71 au_sync();
72}
73
74static inline void FLUSH_FIFO(struct au1xmmc_host *host)
75{
76 u32 val = au_readl(HOST_CONFIG2(host));
77
78 au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
79 au_sync_delay(1);
80
81 /* SEND_STOP will turn off clock control - this re-enables it */
82 val &= ~SD_CONFIG2_DF;
83
84 au_writel(val, HOST_CONFIG2(host));
85 au_sync();
86}
87
88static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
89{
90 u32 val = au_readl(HOST_CONFIG(host));
91 val &= ~mask;
92 au_writel(val, HOST_CONFIG(host));
93 au_sync();
94}
95
96static inline void SEND_STOP(struct au1xmmc_host *host)
97{
98
99 /* We know the value of CONFIG2, so avoid a read we don't need */
100 u32 mask = SD_CONFIG2_EN;
101
102 WARN_ON(host->status != HOST_S_DATA);
103 host->status = HOST_S_STOP;
104
105 au_writel(mask | SD_CONFIG2_DF, HOST_CONFIG2(host));
106 au_sync();
107
108 /* Send the stop commmand */
109 au_writel(STOP_CMD, HOST_CMD(host));
110}
111
112static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
113{
Manuel Laussc4223c22008-06-09 08:36:13 +0200114 if (host->platdata && host->platdata->set_power)
115 host->platdata->set_power(host->mmc, state);
Pete Popovba264b32005-09-21 06:18:27 +0000116}
117
Manuel Laussc4223c22008-06-09 08:36:13 +0200118static int au1xmmc_card_inserted(struct au1xmmc_host *host)
Pete Popovba264b32005-09-21 06:18:27 +0000119{
Manuel Laussc4223c22008-06-09 08:36:13 +0200120 int ret;
121
122 if (host->platdata && host->platdata->card_inserted)
123 ret = host->platdata->card_inserted(host->mmc);
124 else
125 ret = 1; /* assume there is a card */
126
127 return ret;
Pete Popovba264b32005-09-21 06:18:27 +0000128}
129
Manuel Lauss82999772007-01-25 10:29:24 +0100130static int au1xmmc_card_readonly(struct mmc_host *mmc)
Pete Popovba264b32005-09-21 06:18:27 +0000131{
Manuel Lauss82999772007-01-25 10:29:24 +0100132 struct au1xmmc_host *host = mmc_priv(mmc);
Manuel Laussc4223c22008-06-09 08:36:13 +0200133 int ret;
134
135 if (host->platdata && host->platdata->card_readonly)
136 ret = host->platdata->card_readonly(mmc);
137 else
138 ret = 0; /* assume card is read-write */
139
140 return ret;
Pete Popovba264b32005-09-21 06:18:27 +0000141}
142
143static void au1xmmc_finish_request(struct au1xmmc_host *host)
144{
145
146 struct mmc_request *mrq = host->mrq;
147
148 host->mrq = NULL;
Manuel Laussc4223c22008-06-09 08:36:13 +0200149 host->flags &= HOST_F_ACTIVE | HOST_F_DMA;
Pete Popovba264b32005-09-21 06:18:27 +0000150
151 host->dma.len = 0;
152 host->dma.dir = 0;
153
154 host->pio.index = 0;
155 host->pio.offset = 0;
156 host->pio.len = 0;
157
158 host->status = HOST_S_IDLE;
159
Pete Popovba264b32005-09-21 06:18:27 +0000160 mmc_request_done(host->mmc, mrq);
161}
162
163static void au1xmmc_tasklet_finish(unsigned long param)
164{
165 struct au1xmmc_host *host = (struct au1xmmc_host *) param;
166 au1xmmc_finish_request(host);
167}
168
169static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200170 struct mmc_command *cmd, struct mmc_data *data)
Pete Popovba264b32005-09-21 06:18:27 +0000171{
Pete Popovba264b32005-09-21 06:18:27 +0000172 u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
173
Martin Michlmayre142c242006-03-04 23:01:39 +0000174 switch (mmc_resp_type(cmd)) {
Manuel Lauss279bc442007-01-25 10:27:41 +0100175 case MMC_RSP_NONE:
176 break;
Pete Popovba264b32005-09-21 06:18:27 +0000177 case MMC_RSP_R1:
178 mmccmd |= SD_CMD_RT_1;
179 break;
180 case MMC_RSP_R1B:
181 mmccmd |= SD_CMD_RT_1B;
182 break;
183 case MMC_RSP_R2:
184 mmccmd |= SD_CMD_RT_2;
185 break;
186 case MMC_RSP_R3:
187 mmccmd |= SD_CMD_RT_3;
188 break;
Manuel Lauss279bc442007-01-25 10:27:41 +0100189 default:
190 printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
191 mmc_resp_type(cmd));
Pierre Ossman17b04292007-07-22 22:18:46 +0200192 return -EINVAL;
Pete Popovba264b32005-09-21 06:18:27 +0000193 }
194
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200195 if (data) {
Pierre Ossman6356a9d2007-10-22 18:16:16 +0200196 if (data->flags & MMC_DATA_READ) {
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200197 if (data->blocks > 1)
198 mmccmd |= SD_CMD_CT_4;
199 else
200 mmccmd |= SD_CMD_CT_2;
Pierre Ossman6356a9d2007-10-22 18:16:16 +0200201 } else if (data->flags & MMC_DATA_WRITE) {
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200202 if (data->blocks > 1)
203 mmccmd |= SD_CMD_CT_3;
204 else
205 mmccmd |= SD_CMD_CT_1;
206 }
Pete Popovba264b32005-09-21 06:18:27 +0000207 }
208
209 au_writel(cmd->arg, HOST_CMDARG(host));
210 au_sync();
211
212 if (wait)
213 IRQ_OFF(host, SD_CONFIG_CR);
214
215 au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
216 au_sync();
217
218 /* Wait for the command to go on the line */
219
220 while(1) {
221 if (!(au_readl(HOST_CMD(host)) & SD_CMD_GO))
222 break;
223 }
224
225 /* Wait for the command to come back */
226
227 if (wait) {
228 u32 status = au_readl(HOST_STATUS(host));
229
230 while(!(status & SD_STATUS_CR))
231 status = au_readl(HOST_STATUS(host));
232
233 /* Clear the CR status */
234 au_writel(SD_STATUS_CR, HOST_STATUS(host));
235
236 IRQ_ON(host, SD_CONFIG_CR);
237 }
238
Pierre Ossman17b04292007-07-22 22:18:46 +0200239 return 0;
Pete Popovba264b32005-09-21 06:18:27 +0000240}
241
242static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
243{
244
245 struct mmc_request *mrq = host->mrq;
246 struct mmc_data *data;
247 u32 crc;
248
249 WARN_ON(host->status != HOST_S_DATA && host->status != HOST_S_STOP);
250
251 if (host->mrq == NULL)
252 return;
253
254 data = mrq->cmd->data;
255
256 if (status == 0)
257 status = au_readl(HOST_STATUS(host));
258
259 /* The transaction is really over when the SD_STATUS_DB bit is clear */
260
261 while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
262 status = au_readl(HOST_STATUS(host));
263
Pierre Ossman17b04292007-07-22 22:18:46 +0200264 data->error = 0;
Pete Popovba264b32005-09-21 06:18:27 +0000265 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
266
267 /* Process any errors */
268
269 crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
270 if (host->flags & HOST_F_XMIT)
271 crc |= ((status & 0x07) == 0x02) ? 0 : 1;
272
273 if (crc)
Pierre Ossman17b04292007-07-22 22:18:46 +0200274 data->error = -EILSEQ;
Pete Popovba264b32005-09-21 06:18:27 +0000275
276 /* Clear the CRC bits */
277 au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
278
279 data->bytes_xfered = 0;
280
Pierre Ossman17b04292007-07-22 22:18:46 +0200281 if (!data->error) {
Pete Popovba264b32005-09-21 06:18:27 +0000282 if (host->flags & HOST_F_DMA) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200283#ifdef CONFIG_SOC_AU1200 /* DBDMA */
Pete Popovba264b32005-09-21 06:18:27 +0000284 u32 chan = DMA_CHANNEL(host);
285
286 chan_tab_t *c = *((chan_tab_t **) chan);
287 au1x_dma_chan_t *cp = c->chan_ptr;
288 data->bytes_xfered = cp->ddma_bytecnt;
Manuel Laussc4223c22008-06-09 08:36:13 +0200289#endif
Pete Popovba264b32005-09-21 06:18:27 +0000290 }
291 else
292 data->bytes_xfered =
Pavel Pisa2c171bf2006-05-19 21:48:03 +0100293 (data->blocks * data->blksz) -
Pete Popovba264b32005-09-21 06:18:27 +0000294 host->pio.len;
295 }
296
297 au1xmmc_finish_request(host);
298}
299
300static void au1xmmc_tasklet_data(unsigned long param)
301{
302 struct au1xmmc_host *host = (struct au1xmmc_host *) param;
303
304 u32 status = au_readl(HOST_STATUS(host));
305 au1xmmc_data_complete(host, status);
306}
307
308#define AU1XMMC_MAX_TRANSFER 8
309
310static void au1xmmc_send_pio(struct au1xmmc_host *host)
311{
312
313 struct mmc_data *data = 0;
314 int sg_len, max, count = 0;
315 unsigned char *sg_ptr;
316 u32 status = 0;
317 struct scatterlist *sg;
318
319 data = host->mrq->data;
320
321 if (!(host->flags & HOST_F_XMIT))
322 return;
323
324 /* This is the pointer to the data buffer */
325 sg = &data->sg[host->pio.index];
Jens Axboe45711f12007-10-22 21:19:53 +0200326 sg_ptr = sg_virt(sg) + host->pio.offset;
Pete Popovba264b32005-09-21 06:18:27 +0000327
328 /* This is the space left inside the buffer */
329 sg_len = data->sg[host->pio.index].length - host->pio.offset;
330
331 /* Check to if we need less then the size of the sg_buffer */
332
333 max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
334 if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER;
335
336 for(count = 0; count < max; count++ ) {
337 unsigned char val;
338
339 status = au_readl(HOST_STATUS(host));
340
341 if (!(status & SD_STATUS_TH))
342 break;
343
344 val = *sg_ptr++;
345
346 au_writel((unsigned long) val, HOST_TXPORT(host));
347 au_sync();
348 }
349
350 host->pio.len -= count;
351 host->pio.offset += count;
352
353 if (count == sg_len) {
354 host->pio.index++;
355 host->pio.offset = 0;
356 }
357
358 if (host->pio.len == 0) {
359 IRQ_OFF(host, SD_CONFIG_TH);
360
361 if (host->flags & HOST_F_STOP)
362 SEND_STOP(host);
363
364 tasklet_schedule(&host->data_task);
365 }
366}
367
368static void au1xmmc_receive_pio(struct au1xmmc_host *host)
369{
370
371 struct mmc_data *data = 0;
372 int sg_len = 0, max = 0, count = 0;
373 unsigned char *sg_ptr = 0;
374 u32 status = 0;
375 struct scatterlist *sg;
376
377 data = host->mrq->data;
378
379 if (!(host->flags & HOST_F_RECV))
380 return;
381
382 max = host->pio.len;
383
384 if (host->pio.index < host->dma.len) {
385 sg = &data->sg[host->pio.index];
Jens Axboe45711f12007-10-22 21:19:53 +0200386 sg_ptr = sg_virt(sg) + host->pio.offset;
Pete Popovba264b32005-09-21 06:18:27 +0000387
388 /* This is the space left inside the buffer */
389 sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
390
391 /* Check to if we need less then the size of the sg_buffer */
392 if (sg_len < max) max = sg_len;
393 }
394
395 if (max > AU1XMMC_MAX_TRANSFER)
396 max = AU1XMMC_MAX_TRANSFER;
397
398 for(count = 0; count < max; count++ ) {
399 u32 val;
400 status = au_readl(HOST_STATUS(host));
401
402 if (!(status & SD_STATUS_NE))
403 break;
404
405 if (status & SD_STATUS_RC) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200406 DBG("RX CRC Error [%d + %d].\n", host->pdev->id,
Pete Popovba264b32005-09-21 06:18:27 +0000407 host->pio.len, count);
408 break;
409 }
410
411 if (status & SD_STATUS_RO) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200412 DBG("RX Overrun [%d + %d]\n", host->pdev->id,
Pete Popovba264b32005-09-21 06:18:27 +0000413 host->pio.len, count);
414 break;
415 }
416 else if (status & SD_STATUS_RU) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200417 DBG("RX Underrun [%d + %d]\n", host->pdev->id,
Pete Popovba264b32005-09-21 06:18:27 +0000418 host->pio.len, count);
419 break;
420 }
421
422 val = au_readl(HOST_RXPORT(host));
423
424 if (sg_ptr)
425 *sg_ptr++ = (unsigned char) (val & 0xFF);
426 }
427
428 host->pio.len -= count;
429 host->pio.offset += count;
430
431 if (sg_len && count == sg_len) {
432 host->pio.index++;
433 host->pio.offset = 0;
434 }
435
436 if (host->pio.len == 0) {
437 //IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF);
438 IRQ_OFF(host, SD_CONFIG_NE);
439
440 if (host->flags & HOST_F_STOP)
441 SEND_STOP(host);
442
443 tasklet_schedule(&host->data_task);
444 }
445}
446
447/* static void au1xmmc_cmd_complete
448 This is called when a command has been completed - grab the response
449 and check for errors. Then start the data transfer if it is indicated.
450*/
451
452static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
453{
454
455 struct mmc_request *mrq = host->mrq;
456 struct mmc_command *cmd;
457 int trans;
458
459 if (!host->mrq)
460 return;
461
462 cmd = mrq->cmd;
Pierre Ossman17b04292007-07-22 22:18:46 +0200463 cmd->error = 0;
Pete Popovba264b32005-09-21 06:18:27 +0000464
Russell Kinge9225172006-02-02 12:23:12 +0000465 if (cmd->flags & MMC_RSP_PRESENT) {
466 if (cmd->flags & MMC_RSP_136) {
467 u32 r[4];
468 int i;
Pete Popovba264b32005-09-21 06:18:27 +0000469
Russell Kinge9225172006-02-02 12:23:12 +0000470 r[0] = au_readl(host->iobase + SD_RESP3);
471 r[1] = au_readl(host->iobase + SD_RESP2);
472 r[2] = au_readl(host->iobase + SD_RESP1);
473 r[3] = au_readl(host->iobase + SD_RESP0);
Pete Popovba264b32005-09-21 06:18:27 +0000474
Russell Kinge9225172006-02-02 12:23:12 +0000475 /* The CRC is omitted from the response, so really
476 * we only got 120 bytes, but the engine expects
477 * 128 bits, so we have to shift things up
478 */
Pete Popovba264b32005-09-21 06:18:27 +0000479
Russell Kinge9225172006-02-02 12:23:12 +0000480 for(i = 0; i < 4; i++) {
481 cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
482 if (i != 3)
483 cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
484 }
485 } else {
486 /* Techincally, we should be getting all 48 bits of
487 * the response (SD_RESP1 + SD_RESP2), but because
488 * our response omits the CRC, our data ends up
489 * being shifted 8 bits to the right. In this case,
490 * that means that the OSR data starts at bit 31,
491 * so we can just read RESP0 and return that
492 */
493 cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
Pete Popovba264b32005-09-21 06:18:27 +0000494 }
495 }
496
497 /* Figure out errors */
498
499 if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
Pierre Ossman17b04292007-07-22 22:18:46 +0200500 cmd->error = -EILSEQ;
Pete Popovba264b32005-09-21 06:18:27 +0000501
502 trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
503
Pierre Ossman17b04292007-07-22 22:18:46 +0200504 if (!trans || cmd->error) {
Pete Popovba264b32005-09-21 06:18:27 +0000505
506 IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
507 tasklet_schedule(&host->finish_task);
508 return;
509 }
510
511 host->status = HOST_S_DATA;
512
513 if (host->flags & HOST_F_DMA) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200514#ifdef CONFIG_SOC_AU1200 /* DBDMA */
Pete Popovba264b32005-09-21 06:18:27 +0000515 u32 channel = DMA_CHANNEL(host);
516
517 /* Start the DMA as soon as the buffer gets something in it */
518
519 if (host->flags & HOST_F_RECV) {
520 u32 mask = SD_STATUS_DB | SD_STATUS_NE;
521
522 while((status & mask) != mask)
523 status = au_readl(HOST_STATUS(host));
524 }
525
526 au1xxx_dbdma_start(channel);
Manuel Laussc4223c22008-06-09 08:36:13 +0200527#endif
Pete Popovba264b32005-09-21 06:18:27 +0000528 }
529}
530
531static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
532{
533
534 unsigned int pbus = get_au1x00_speed();
535 unsigned int divisor;
536 u32 config;
537
538 /* From databook:
539 divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
540 */
541
542 pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
543 pbus /= 2;
544
545 divisor = ((pbus / rate) / 2) - 1;
546
547 config = au_readl(HOST_CONFIG(host));
548
549 config &= ~(SD_CONFIG_DIV);
550 config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
551
552 au_writel(config, HOST_CONFIG(host));
553 au_sync();
554}
555
556static int
557au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
558{
Pavel Pisa2c171bf2006-05-19 21:48:03 +0100559 int datalen = data->blocks * data->blksz;
Pete Popovba264b32005-09-21 06:18:27 +0000560
Pete Popovba264b32005-09-21 06:18:27 +0000561 if (data->flags & MMC_DATA_READ)
562 host->flags |= HOST_F_RECV;
563 else
564 host->flags |= HOST_F_XMIT;
565
566 if (host->mrq->stop)
567 host->flags |= HOST_F_STOP;
568
569 host->dma.dir = DMA_BIDIRECTIONAL;
570
571 host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
572 data->sg_len, host->dma.dir);
573
574 if (host->dma.len == 0)
Pierre Ossman17b04292007-07-22 22:18:46 +0200575 return -ETIMEDOUT;
Pete Popovba264b32005-09-21 06:18:27 +0000576
Pavel Pisa2c171bf2006-05-19 21:48:03 +0100577 au_writel(data->blksz - 1, HOST_BLKSIZE(host));
Pete Popovba264b32005-09-21 06:18:27 +0000578
579 if (host->flags & HOST_F_DMA) {
Manuel Laussc4223c22008-06-09 08:36:13 +0200580#ifdef CONFIG_SOC_AU1200 /* DBDMA */
Pete Popovba264b32005-09-21 06:18:27 +0000581 int i;
582 u32 channel = DMA_CHANNEL(host);
583
584 au1xxx_dbdma_stop(channel);
585
586 for(i = 0; i < host->dma.len; i++) {
587 u32 ret = 0, flags = DDMA_FLAGS_NOIE;
588 struct scatterlist *sg = &data->sg[i];
589 int sg_len = sg->length;
590
591 int len = (datalen > sg_len) ? sg_len : datalen;
592
593 if (i == host->dma.len - 1)
594 flags = DDMA_FLAGS_IE;
595
596 if (host->flags & HOST_F_XMIT){
597 ret = au1xxx_dbdma_put_source_flags(channel,
Jens Axboe45711f12007-10-22 21:19:53 +0200598 (void *) sg_virt(sg), len, flags);
Pete Popovba264b32005-09-21 06:18:27 +0000599 }
600 else {
601 ret = au1xxx_dbdma_put_dest_flags(channel,
Jens Axboe45711f12007-10-22 21:19:53 +0200602 (void *) sg_virt(sg),
Pete Popovba264b32005-09-21 06:18:27 +0000603 len, flags);
604 }
605
Manuel Laussc4223c22008-06-09 08:36:13 +0200606 if (!ret)
Pete Popovba264b32005-09-21 06:18:27 +0000607 goto dataerr;
608
609 datalen -= len;
610 }
Manuel Laussc4223c22008-06-09 08:36:13 +0200611#endif
Pete Popovba264b32005-09-21 06:18:27 +0000612 }
613 else {
614 host->pio.index = 0;
615 host->pio.offset = 0;
616 host->pio.len = datalen;
617
618 if (host->flags & HOST_F_XMIT)
619 IRQ_ON(host, SD_CONFIG_TH);
620 else
621 IRQ_ON(host, SD_CONFIG_NE);
622 //IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
623 }
624
Pierre Ossman17b04292007-07-22 22:18:46 +0200625 return 0;
Pete Popovba264b32005-09-21 06:18:27 +0000626
Manuel Laussc4223c22008-06-09 08:36:13 +0200627dataerr:
628 dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
629 host->dma.dir);
Pierre Ossman17b04292007-07-22 22:18:46 +0200630 return -ETIMEDOUT;
Pete Popovba264b32005-09-21 06:18:27 +0000631}
632
633/* static void au1xmmc_request
634 This actually starts a command or data transaction
635*/
636
637static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
638{
639
640 struct au1xmmc_host *host = mmc_priv(mmc);
Yoichi Yuasac0f3b6c2007-05-13 18:23:15 +0200641 unsigned int flags = 0;
Pierre Ossman17b04292007-07-22 22:18:46 +0200642 int ret = 0;
Pete Popovba264b32005-09-21 06:18:27 +0000643
644 WARN_ON(irqs_disabled());
645 WARN_ON(host->status != HOST_S_IDLE);
646
647 host->mrq = mrq;
648 host->status = HOST_S_CMD;
649
Pete Popovba264b32005-09-21 06:18:27 +0000650 if (mrq->data) {
651 FLUSH_FIFO(host);
Yoichi Yuasac0f3b6c2007-05-13 18:23:15 +0200652 flags = mrq->data->flags;
Pete Popovba264b32005-09-21 06:18:27 +0000653 ret = au1xmmc_prepare_data(host, mrq->data);
654 }
655
Pierre Ossman17b04292007-07-22 22:18:46 +0200656 if (!ret)
Pierre Ossmanbe0192a2007-07-24 21:11:47 +0200657 ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data);
Pete Popovba264b32005-09-21 06:18:27 +0000658
Pierre Ossman17b04292007-07-22 22:18:46 +0200659 if (ret) {
Pete Popovba264b32005-09-21 06:18:27 +0000660 mrq->cmd->error = ret;
661 au1xmmc_finish_request(host);
662 }
663}
664
665static void au1xmmc_reset_controller(struct au1xmmc_host *host)
666{
667
668 /* Apply the clock */
669 au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
670 au_sync_delay(1);
671
672 au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
673 au_sync_delay(5);
674
675 au_writel(~0, HOST_STATUS(host));
676 au_sync();
677
678 au_writel(0, HOST_BLKSIZE(host));
679 au_writel(0x001fffff, HOST_TIMEOUT(host));
680 au_sync();
681
682 au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
683 au_sync();
684
685 au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
686 au_sync_delay(1);
687
688 au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
689 au_sync();
690
691 /* Configure interrupts */
692 au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
693 au_sync();
694}
695
696
697static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
698{
699 struct au1xmmc_host *host = mmc_priv(mmc);
700
Pete Popovba264b32005-09-21 06:18:27 +0000701 if (ios->power_mode == MMC_POWER_OFF)
702 au1xmmc_set_power(host, 0);
703 else if (ios->power_mode == MMC_POWER_ON) {
704 au1xmmc_set_power(host, 1);
705 }
706
707 if (ios->clock && ios->clock != host->clock) {
708 au1xmmc_set_clock(host, ios->clock);
709 host->clock = ios->clock;
710 }
711}
712
Manuel Laussc4223c22008-06-09 08:36:13 +0200713#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
714#define STATUS_DATA_IN (SD_STATUS_NE)
715#define STATUS_DATA_OUT (SD_STATUS_TH)
716
717static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
Pete Popovba264b32005-09-21 06:18:27 +0000718{
Manuel Laussc4223c22008-06-09 08:36:13 +0200719 struct au1xmmc_host *host = dev_id;
720 u32 status;
721
722 status = au_readl(HOST_STATUS(host));
723
724 if (!(status & SD_STATUS_I))
725 return IRQ_NONE; /* not ours */
726
727 if (host->mrq && (status & STATUS_TIMEOUT)) {
728 if (status & SD_STATUS_RAT)
729 host->mrq->cmd->error = -ETIMEDOUT;
730 else if (status & SD_STATUS_DT)
731 host->mrq->data->error = -ETIMEDOUT;
732
733 /* In PIO mode, interrupts might still be enabled */
734 IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
735
736 /* IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); */
737 tasklet_schedule(&host->finish_task);
738 }
739#if 0
740 else if (status & SD_STATUS_DD) {
741 /* Sometimes we get a DD before a NE in PIO mode */
742 if (!(host->flags & HOST_F_DMA) && (status & SD_STATUS_NE))
743 au1xmmc_receive_pio(host);
744 else {
745 au1xmmc_data_complete(host, status);
746 /* tasklet_schedule(&host->data_task); */
747 }
748 }
749#endif
750 else if (status & SD_STATUS_CR) {
751 if (host->status == HOST_S_CMD)
752 au1xmmc_cmd_complete(host, status);
753
754 } else if (!(host->flags & HOST_F_DMA)) {
755 if ((host->flags & HOST_F_XMIT) && (status & STATUS_DATA_OUT))
756 au1xmmc_send_pio(host);
757 else if ((host->flags & HOST_F_RECV) && (status & STATUS_DATA_IN))
758 au1xmmc_receive_pio(host);
759
760 } else if (status & 0x203F3C70) {
761 DBG("Unhandled status %8.8x\n", host->pdev->id,
762 status);
763 }
764
765 au_writel(status, HOST_STATUS(host));
766 au_sync();
767
768 return IRQ_HANDLED;
769}
770
771#ifdef CONFIG_SOC_AU1200
772/* 8bit memory DMA device */
773static dbdev_tab_t au1xmmc_mem_dbdev = {
774 .dev_id = DSCR_CMD0_ALWAYS,
775 .dev_flags = DEV_FLAGS_ANYUSE,
776 .dev_tsize = 0,
777 .dev_devwidth = 8,
778 .dev_physaddr = 0x00000000,
779 .dev_intlevel = 0,
780 .dev_intpolarity = 0,
781};
782static int memid;
783
784static void au1xmmc_dbdma_callback(int irq, void *dev_id)
785{
786 struct au1xmmc_host *host = (struct au1xmmc_host *)dev_id;
Pete Popovba264b32005-09-21 06:18:27 +0000787
788 /* Avoid spurious interrupts */
Pete Popovba264b32005-09-21 06:18:27 +0000789 if (!host->mrq)
790 return;
791
792 if (host->flags & HOST_F_STOP)
793 SEND_STOP(host);
794
795 tasklet_schedule(&host->data_task);
796}
797
Manuel Laussc4223c22008-06-09 08:36:13 +0200798static int au1xmmc_dbdma_init(struct au1xmmc_host *host)
Pete Popovba264b32005-09-21 06:18:27 +0000799{
Manuel Laussc4223c22008-06-09 08:36:13 +0200800 struct resource *res;
801 int txid, rxid;
Pete Popovba264b32005-09-21 06:18:27 +0000802
Manuel Laussc4223c22008-06-09 08:36:13 +0200803 res = platform_get_resource(host->pdev, IORESOURCE_DMA, 0);
804 if (!res)
805 return -ENODEV;
806 txid = res->start;
Pete Popovba264b32005-09-21 06:18:27 +0000807
Manuel Laussc4223c22008-06-09 08:36:13 +0200808 res = platform_get_resource(host->pdev, IORESOURCE_DMA, 1);
809 if (!res)
810 return -ENODEV;
811 rxid = res->start;
Pete Popovba264b32005-09-21 06:18:27 +0000812
Manuel Laussc4223c22008-06-09 08:36:13 +0200813 if (!memid)
814 return -ENODEV;
Pete Popovba264b32005-09-21 06:18:27 +0000815
Manuel Laussc4223c22008-06-09 08:36:13 +0200816 host->tx_chan = au1xxx_dbdma_chan_alloc(memid, txid,
817 au1xmmc_dbdma_callback, (void *)host);
818 if (!host->tx_chan) {
819 dev_err(&host->pdev->dev, "cannot allocate TX DMA\n");
820 return -ENODEV;
821 }
Pete Popovba264b32005-09-21 06:18:27 +0000822
Manuel Laussc4223c22008-06-09 08:36:13 +0200823 host->rx_chan = au1xxx_dbdma_chan_alloc(rxid, memid,
824 au1xmmc_dbdma_callback, (void *)host);
825 if (!host->rx_chan) {
826 dev_err(&host->pdev->dev, "cannot allocate RX DMA\n");
827 au1xxx_dbdma_chan_free(host->tx_chan);
828 return -ENODEV;
829 }
Pete Popovba264b32005-09-21 06:18:27 +0000830
Manuel Laussc4223c22008-06-09 08:36:13 +0200831 au1xxx_dbdma_set_devwidth(host->tx_chan, 8);
832 au1xxx_dbdma_set_devwidth(host->rx_chan, 8);
Pete Popovba264b32005-09-21 06:18:27 +0000833
Manuel Laussc4223c22008-06-09 08:36:13 +0200834 au1xxx_dbdma_ring_alloc(host->tx_chan, AU1XMMC_DESCRIPTOR_COUNT);
835 au1xxx_dbdma_ring_alloc(host->rx_chan, AU1XMMC_DESCRIPTOR_COUNT);
Pete Popovba264b32005-09-21 06:18:27 +0000836
Manuel Laussc4223c22008-06-09 08:36:13 +0200837 /* DBDMA is good to go */
838 host->flags |= HOST_F_DMA;
Pete Popovba264b32005-09-21 06:18:27 +0000839
Manuel Laussc4223c22008-06-09 08:36:13 +0200840 return 0;
841}
Pete Popovba264b32005-09-21 06:18:27 +0000842
Manuel Laussc4223c22008-06-09 08:36:13 +0200843static void au1xmmc_dbdma_shutdown(struct au1xmmc_host *host)
844{
845 if (host->flags & HOST_F_DMA) {
846 host->flags &= ~HOST_F_DMA;
847 au1xxx_dbdma_chan_free(host->tx_chan);
848 au1xxx_dbdma_chan_free(host->rx_chan);
849 }
850}
Pete Popovba264b32005-09-21 06:18:27 +0000851#endif
Pete Popovba264b32005-09-21 06:18:27 +0000852
Yoichi Yuasabf8c80a2006-12-05 07:43:38 +0100853static const struct mmc_host_ops au1xmmc_ops = {
Pete Popovba264b32005-09-21 06:18:27 +0000854 .request = au1xmmc_request,
855 .set_ios = au1xmmc_set_ios,
Manuel Lauss82999772007-01-25 10:29:24 +0100856 .get_ro = au1xmmc_card_readonly,
Pete Popovba264b32005-09-21 06:18:27 +0000857};
858
Manuel Laussc4223c22008-06-09 08:36:13 +0200859static void au1xmmc_poll_event(unsigned long arg)
860{
861 struct au1xmmc_host *host = (struct au1xmmc_host *)arg;
862 int card = au1xmmc_card_inserted(host);
863 int controller = (host->flags & HOST_F_ACTIVE) ? 1 : 0;
864
865 if (card != controller) {
866 host->flags &= ~HOST_F_ACTIVE;
867 if (card)
868 host->flags |= HOST_F_ACTIVE;
869 mmc_detect_change(host->mmc, 0);
870 }
871
872#ifdef DEBUG
873 if (host->mrq != NULL) {
874 u32 status = au_readl(HOST_STATUS(host));
875 DBG("PENDING - %8.8x\n", host->pdev->id, status);
876 }
877#endif
878 mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT);
879}
880
881static void au1xmmc_init_cd_poll_timer(struct au1xmmc_host *host)
882{
883 init_timer(&host->timer);
884 host->timer.function = au1xmmc_poll_event;
885 host->timer.data = (unsigned long)host;
886 host->timer.expires = jiffies + AU1XMMC_DETECT_TIMEOUT;
887}
888
Martin Michlmayrb256f9d2006-03-04 23:01:13 +0000889static int __devinit au1xmmc_probe(struct platform_device *pdev)
Pete Popovba264b32005-09-21 06:18:27 +0000890{
Manuel Laussc4223c22008-06-09 08:36:13 +0200891 struct mmc_host *mmc;
892 struct au1xmmc_host *host;
893 struct resource *r;
894 int ret;
Pete Popovba264b32005-09-21 06:18:27 +0000895
Manuel Laussc4223c22008-06-09 08:36:13 +0200896 mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
897 if (!mmc) {
898 dev_err(&pdev->dev, "no memory for mmc_host\n");
899 ret = -ENOMEM;
900 goto out0;
Pete Popovba264b32005-09-21 06:18:27 +0000901 }
902
Manuel Laussc4223c22008-06-09 08:36:13 +0200903 host = mmc_priv(mmc);
904 host->mmc = mmc;
905 host->platdata = pdev->dev.platform_data;
906 host->pdev = pdev;
Pete Popovba264b32005-09-21 06:18:27 +0000907
Manuel Laussc4223c22008-06-09 08:36:13 +0200908 ret = -ENODEV;
909 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
910 if (!r) {
911 dev_err(&pdev->dev, "no mmio defined\n");
912 goto out1;
913 }
Pete Popovba264b32005-09-21 06:18:27 +0000914
Manuel Laussc4223c22008-06-09 08:36:13 +0200915 host->ioarea = request_mem_region(r->start, r->end - r->start + 1,
916 pdev->name);
917 if (!host->ioarea) {
918 dev_err(&pdev->dev, "mmio already in use\n");
919 goto out1;
920 }
921
922 host->iobase = (unsigned long)ioremap(r->start, 0x3c);
923 if (!host->iobase) {
924 dev_err(&pdev->dev, "cannot remap mmio\n");
925 goto out2;
926 }
927
928 r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
929 if (!r) {
930 dev_err(&pdev->dev, "no IRQ defined\n");
931 goto out3;
932 }
933
934 host->irq = r->start;
935 /* IRQ is shared among both SD controllers */
936 ret = request_irq(host->irq, au1xmmc_irq, IRQF_SHARED,
937 DRIVER_NAME, host);
938 if (ret) {
939 dev_err(&pdev->dev, "cannot grab IRQ\n");
940 goto out3;
941 }
942
943 mmc->ops = &au1xmmc_ops;
944
945 mmc->f_min = 450000;
946 mmc->f_max = 24000000;
947
948 mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
949 mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
950
951 mmc->max_blk_size = 2048;
952 mmc->max_blk_count = 512;
953
954 mmc->ocr_avail = AU1XMMC_OCR;
955 mmc->caps = 0;
956
957 host->status = HOST_S_IDLE;
958
959 /* board-specific carddetect setup, if any */
960 if (host->platdata && host->platdata->cd_setup) {
961 ret = host->platdata->cd_setup(mmc, 1);
962 if (ret) {
963 dev_err(&pdev->dev, "board CD setup failed\n");
964 goto out4;
Pete Popovba264b32005-09-21 06:18:27 +0000965 }
Manuel Laussc4223c22008-06-09 08:36:13 +0200966 } else {
967 /* poll the board-specific is-card-in-socket-? method */
968 au1xmmc_init_cd_poll_timer(host);
969 }
Pete Popovba264b32005-09-21 06:18:27 +0000970
Manuel Laussc4223c22008-06-09 08:36:13 +0200971 tasklet_init(&host->data_task, au1xmmc_tasklet_data,
972 (unsigned long)host);
Pete Popovba264b32005-09-21 06:18:27 +0000973
Manuel Laussc4223c22008-06-09 08:36:13 +0200974 tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
975 (unsigned long)host);
Pete Popovba264b32005-09-21 06:18:27 +0000976
Manuel Laussc4223c22008-06-09 08:36:13 +0200977#ifdef CONFIG_SOC_AU1200
978 ret = au1xmmc_dbdma_init(host);
979 if (ret)
980 printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n");
981#endif
Pete Popovba264b32005-09-21 06:18:27 +0000982
Manuel Laussc4223c22008-06-09 08:36:13 +0200983#ifdef CONFIG_LEDS_CLASS
984 if (host->platdata && host->platdata->led) {
985 struct led_classdev *led = host->platdata->led;
986 led->name = mmc_hostname(mmc);
987 led->brightness = LED_OFF;
988 led->default_trigger = mmc_hostname(mmc);
989 ret = led_classdev_register(mmc_dev(mmc), led);
990 if (ret)
991 goto out5;
992 }
993#endif
Pierre Ossmanfe4a3c72006-11-21 17:54:23 +0100994
Manuel Laussc4223c22008-06-09 08:36:13 +0200995 au1xmmc_reset_controller(host);
Pete Popovba264b32005-09-21 06:18:27 +0000996
Manuel Laussc4223c22008-06-09 08:36:13 +0200997 ret = mmc_add_host(mmc);
998 if (ret) {
999 dev_err(&pdev->dev, "cannot add mmc host\n");
1000 goto out6;
1001 }
Pete Popovba264b32005-09-21 06:18:27 +00001002
Manuel Laussc4223c22008-06-09 08:36:13 +02001003 platform_set_drvdata(pdev, mmc);
Pete Popovba264b32005-09-21 06:18:27 +00001004
Manuel Laussc4223c22008-06-09 08:36:13 +02001005 /* start the carddetect poll timer if necessary */
1006 if (!(host->platdata && host->platdata->cd_setup))
Pete Popovba264b32005-09-21 06:18:27 +00001007 add_timer(&host->timer);
1008
Manuel Laussc4223c22008-06-09 08:36:13 +02001009 printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X"
1010 " (mode=%s)\n", pdev->id, host->iobase,
1011 host->flags & HOST_F_DMA ? "dma" : "pio");
Pete Popovba264b32005-09-21 06:18:27 +00001012
Manuel Laussc4223c22008-06-09 08:36:13 +02001013 return 0; /* all ok */
Pete Popovba264b32005-09-21 06:18:27 +00001014
Manuel Laussc4223c22008-06-09 08:36:13 +02001015out6:
1016#ifdef CONFIG_LEDS_CLASS
1017 if (host->platdata && host->platdata->led)
1018 led_classdev_unregister(host->platdata->led);
1019out5:
1020#endif
1021 au_writel(0, HOST_ENABLE(host));
1022 au_writel(0, HOST_CONFIG(host));
1023 au_writel(0, HOST_CONFIG2(host));
1024 au_sync();
1025
1026#ifdef CONFIG_SOC_AU1200
1027 au1xmmc_dbdma_shutdown(host);
1028#endif
1029
1030 tasklet_kill(&host->data_task);
1031 tasklet_kill(&host->finish_task);
1032
1033 if (host->platdata && host->platdata->cd_setup)
1034 host->platdata->cd_setup(mmc, 0);
1035out4:
1036 free_irq(host->irq, host);
1037out3:
1038 iounmap((void *)host->iobase);
1039out2:
1040 release_resource(host->ioarea);
1041 kfree(host->ioarea);
1042out1:
1043 mmc_free_host(mmc);
1044out0:
1045 return ret;
Pete Popovba264b32005-09-21 06:18:27 +00001046}
1047
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001048static int __devexit au1xmmc_remove(struct platform_device *pdev)
Pete Popovba264b32005-09-21 06:18:27 +00001049{
Manuel Laussc4223c22008-06-09 08:36:13 +02001050 struct mmc_host *mmc = platform_get_drvdata(pdev);
1051 struct au1xmmc_host *host;
Pete Popovba264b32005-09-21 06:18:27 +00001052
Manuel Laussc4223c22008-06-09 08:36:13 +02001053 if (mmc) {
1054 host = mmc_priv(mmc);
Pete Popovba264b32005-09-21 06:18:27 +00001055
Manuel Laussc4223c22008-06-09 08:36:13 +02001056 mmc_remove_host(mmc);
Pete Popovba264b32005-09-21 06:18:27 +00001057
Manuel Laussc4223c22008-06-09 08:36:13 +02001058#ifdef CONFIG_LEDS_CLASS
1059 if (host->platdata && host->platdata->led)
1060 led_classdev_unregister(host->platdata->led);
1061#endif
1062
1063 if (host->platdata && host->platdata->cd_setup)
1064 host->platdata->cd_setup(mmc, 0);
1065 else
1066 del_timer_sync(&host->timer);
1067
1068 au_writel(0, HOST_ENABLE(host));
1069 au_writel(0, HOST_CONFIG(host));
1070 au_writel(0, HOST_CONFIG2(host));
1071 au_sync();
Pete Popovba264b32005-09-21 06:18:27 +00001072
1073 tasklet_kill(&host->data_task);
1074 tasklet_kill(&host->finish_task);
1075
Manuel Laussc4223c22008-06-09 08:36:13 +02001076#ifdef CONFIG_SOC_AU1200
1077 au1xmmc_dbdma_shutdown(host);
1078#endif
Pete Popovba264b32005-09-21 06:18:27 +00001079 au1xmmc_set_power(host, 0);
1080
Manuel Laussc4223c22008-06-09 08:36:13 +02001081 free_irq(host->irq, host);
1082 iounmap((void *)host->iobase);
1083 release_resource(host->ioarea);
1084 kfree(host->ioarea);
Pete Popovba264b32005-09-21 06:18:27 +00001085
Manuel Laussc4223c22008-06-09 08:36:13 +02001086 mmc_free_host(mmc);
Pete Popovba264b32005-09-21 06:18:27 +00001087 }
Pete Popovba264b32005-09-21 06:18:27 +00001088 return 0;
1089}
1090
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001091static struct platform_driver au1xmmc_driver = {
Pete Popovba264b32005-09-21 06:18:27 +00001092 .probe = au1xmmc_probe,
1093 .remove = au1xmmc_remove,
1094 .suspend = NULL,
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001095 .resume = NULL,
1096 .driver = {
1097 .name = DRIVER_NAME,
Kay Sieversbc65c722008-04-15 14:34:28 -07001098 .owner = THIS_MODULE,
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001099 },
Pete Popovba264b32005-09-21 06:18:27 +00001100};
1101
1102static int __init au1xmmc_init(void)
1103{
Manuel Laussc4223c22008-06-09 08:36:13 +02001104#ifdef CONFIG_SOC_AU1200
1105 /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
1106 * of 8 bits. And since devices are shared, we need to create
1107 * our own to avoid freaking out other devices.
1108 */
1109 memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
1110 if (!memid)
1111 printk(KERN_ERR "au1xmmc: cannot add memory dbdma dev\n");
1112#endif
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001113 return platform_driver_register(&au1xmmc_driver);
Pete Popovba264b32005-09-21 06:18:27 +00001114}
1115
1116static void __exit au1xmmc_exit(void)
1117{
Manuel Laussc4223c22008-06-09 08:36:13 +02001118#ifdef CONFIG_SOC_AU1200
1119 if (memid)
1120 au1xxx_ddma_del_device(memid);
1121#endif
Martin Michlmayrb256f9d2006-03-04 23:01:13 +00001122 platform_driver_unregister(&au1xmmc_driver);
Pete Popovba264b32005-09-21 06:18:27 +00001123}
1124
1125module_init(au1xmmc_init);
1126module_exit(au1xmmc_exit);
1127
Pete Popovba264b32005-09-21 06:18:27 +00001128MODULE_AUTHOR("Advanced Micro Devices, Inc");
1129MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
1130MODULE_LICENSE("GPL");
Kay Sieversbc65c722008-04-15 14:34:28 -07001131MODULE_ALIAS("platform:au1xxx-mmc");