MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / mmc / host / moxasd.c
blobcdbf65ba49d44eee25005c0dd930ddf51ab17712
1 /*
2 * linux/drivers/mmc/moxasd.c - Moxa CPU SD/MMC driver
4 * Copyright (C) 2005 Moxa Tech., All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #if 1 // add by Victor Yu. 02-09-2007
12 #include <linux/version.h>
13 #endif
14 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007
15 #include <linux/config.h>
16 #endif
17 #include <asm/arch/cpe/cpe.h>
18 #include <asm/arch/cpe_int.h>
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/ioport.h>
22 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007
23 #include <linux/platform_device.h>
24 #else
25 #include <linux/device.h>
26 #endif // LINUX_VERSION_CODE
27 #include <linux/delay.h>
28 #include <linux/interrupt.h>
29 #include <linux/blkdev.h>
30 #include <linux/dma-mapping.h>
31 #include <linux/mmc/host.h>
32 #include <linux/sched.h>
33 #include <linux/mmc/sd.h>
35 #include <asm/dma.h>
36 #include <asm/io.h>
37 #include <asm/irq.h>
38 #include <asm/sizes.h>
39 #include <asm/arch/gpio.h>
41 #include "moxasd.h"
43 #if 1 // add by Victor Yu. 12-02-2008
44 #ifndef MMC_VDD_360
45 #define MMC_VDD_360 23
46 #endif
47 #endif
49 #if 0 // mask by Victor Yu. 03-19-2007
50 #define MSD_RETRY_COUNT 1000
51 #else
52 #define MSD_RETRY_COUNT 100
53 #endif
54 //#define CONFIG_MMC_DEBUG
55 #ifdef CONFIG_MMC_DEBUG
56 #define DBG(x...) printk(x)
57 #else
58 #define DBG(x...)
59 #endif
61 struct moxasd_host {
62 struct mmc_host *mmc;
63 spinlock_t lock;
64 moxasd_reg *reg;
65 apb_dma_priv *dma;
66 #ifdef MSD_SUPPORT_GET_CLOCK
67 unsigned int sysclk;
68 #endif
69 struct mmc_request *mrq;
70 struct mmc_data *data;
72 struct scatterlist *cur_sg; /* Current SG entry */
73 unsigned int num_sg; /* Number of entries left */
74 void *mapped_sg; /* vaddr of mapped sg */
75 unsigned int remain; /* Data left in curren entry */
76 int size; /* Total size of transfer */
78 struct tasklet_struct card_change_tasklet;
79 struct tasklet_struct fifo_run_tasklet;
82 static inline void moxasd_init_sg(struct moxasd_host* host, struct mmc_data* data)
85 * Get info. about SG list from data structure.
87 host->cur_sg = data->sg;
88 host->num_sg = data->sg_len;
90 host->remain = host->cur_sg->length;
91 #if 1 // add by Victor Yu. 07-04-2007
92 if ( host->remain > host->size )
93 host->remain = host->size;
94 host->mapped_sg = NULL;
95 #endif
96 data->error = MMC_ERR_NONE;
99 static inline int moxasd_next_sg(struct moxasd_host* host)
101 #if 1 // add by Victor Yu. 07-04-2007
102 struct mmc_data *data=host->data;
103 #endif
105 * Skip to next SG entry.
107 host->cur_sg++;
108 host->num_sg--;
111 * Any entries left?
113 if (host->num_sg > 0) {
114 host->remain = host->cur_sg->length;
115 #if 1 // add by Victor Yu. 07-04-2007
117 int remain;
118 remain = host->size - data->bytes_xfered;
119 if ( remain > 0 && remain < host->remain ) {
120 host->remain = remain;
123 #endif
126 return host->num_sg;
129 static inline char *moxasd_kmap_sg(struct moxasd_host* host)
131 host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
132 return host->mapped_sg + host->cur_sg->offset;
135 static void moxasd_do_fifo(struct moxasd_host *host, struct mmc_data *data)
137 char *buffer;
138 int wcnt, i;
140 #if 1 // add by Victor Yu. 07-06-2007
141 if ( host->mapped_sg ) {
142 kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
143 moxasd_next_sg(host);
145 #endif
146 if ( host->size == data->bytes_xfered ) {
147 return;
149 buffer = moxasd_kmap_sg(host);
150 if ( host->size > MSD_FIFO_LENB && host->dma ) {
151 apb_dma_conf_param param;
152 param.size = host->remain;
153 param.burst_mode = APB_DMAB_BURST_MODE;
154 param.data_width = APB_DMAB_DATA_WIDTH_4;
155 if ( data->flags & MMC_DATA_WRITE ) {
156 param.source_addr = (unsigned int)buffer;
157 param.dest_addr = (unsigned int)&host->reg->data_window;
158 param.dest_inc = APB_DMAB_DEST_INC_0;
159 param.source_inc = APB_DMAB_DEST_INC_4_16;
160 param.dest_sel = APB_DMAB_DEST_APB;
161 param.source_sel = APB_DMAB_SOURCE_AHB;
162 } else {
163 param.dest_addr = (unsigned int)buffer;
164 param.source_addr = (unsigned int)&host->reg->data_window;
165 param.source_inc = APB_DMAB_DEST_INC_0;
166 param.dest_inc = APB_DMAB_DEST_INC_4_16;
167 param.source_sel = APB_DMAB_DEST_APB;
168 param.dest_sel = APB_DMAB_SOURCE_AHB;
170 data->bytes_xfered += host->remain;
171 apb_dma_conf(host->dma, &param);
172 apb_dma_enable(host->dma);
173 } else {
174 wcnt = host->remain >> 2;
175 if ( data->flags & MMC_DATA_WRITE ) {
176 for ( i=0; i<wcnt; i++, buffer+=4 )
177 writel(*(unsigned int *)buffer, &host->reg->data_window);
178 } else {
179 for ( i=0; i<wcnt; i++, buffer+=4 )
180 *(unsigned int *)buffer = readl(&host->reg->data_window);
182 wcnt <<= 2;
183 host->remain -= wcnt;
184 data->bytes_xfered += wcnt;
188 static void moxasd_request_done(struct moxasd_host *host)
190 struct mmc_request *mrq=host->mrq;
192 if ( mrq == NULL ) {
193 return;
195 host->mrq = NULL;
196 host->data = NULL;
197 mmc_request_done(host->mmc, mrq);
200 static void moxasd_prepare_data(struct moxasd_host *host, struct mmc_data *data)
202 unsigned int timeout, datactrl;
203 #if 1 // add by Victor Yu. 12-01-2008
204 //#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007
205 int blksz_bits;
206 #endif // LINUX_VERSION_CODE
208 host->data = data;
209 // initialize the data size
210 #if 1 // add by Victor Yu. 12-01-2008
211 //#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007
212 host->size = data->blocks * data->blksz;
213 blksz_bits = ffs(data->blksz) - 1;
214 BUG_ON(1 << blksz_bits != data->blksz);
215 #else
216 host->size = data->blocks << data->blksz_bits;
217 #endif // LINUX_VERSION_CODE
218 moxasd_init_sg(host, data);
220 // initialize the timeout value
221 timeout = (host->mmc->f_max/1000) * (data->timeout_ns/1000);
222 timeout *= 2;
224 // initialize the data control
225 #if 1 // add by Victor Yu. 12-01-2008
226 //#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007
227 datactrl = (blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN;
228 #else
229 datactrl = (data->blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN;
230 #endif // LINUX_VERSION_CODE
231 if ( data->flags & MMC_DATA_WRITE ) {
232 datactrl |= MSD_DATA_WRITE;
234 if ( host->size > MSD_FIFO_LENB && host->dma ) {
235 datactrl |= MSD_DMA_EN;
237 writel(timeout, &host->reg->data_timer);
238 writel(host->size, &host->reg->data_length);
239 writel(datactrl, &host->reg->data_control);
241 if ( host->size > MSD_FIFO_LENB && host->dma ) {
242 writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
243 moxasd_do_fifo(host, data);
244 //tasklet_schedule(&host->fifo_run_tasklet);
245 } else {
246 writel(MSD_INT_FIFO_URUN|MSD_INT_FIFO_ORUN|MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
250 static void moxasd_send_command(struct moxasd_host *host, struct mmc_command *cmd)
252 unsigned int status, cmdctrl;
253 int retry=0;
255 #if 1 // add by Victor Yu. 03-19-2007
256 cmd->error = MMC_ERR_TIMEOUT;
257 #endif
259 // first clear status
260 writel(MSD_CLR_RSP_TIMEOUT|MSD_CLR_RSP_CRC_OK|MSD_CLR_RSP_CRC_FAIL|MSD_CLR_CMD_SENT, &host->reg->clear);
262 // write argument
263 writel(cmd->arg, &host->reg->argument);
265 // write command
266 cmdctrl = cmd->opcode & MSD_CMD_IDX_MASK;
267 if ( cmdctrl == SD_APP_SET_BUS_WIDTH ||
268 cmdctrl == SD_APP_OP_COND ||
269 cmdctrl == SD_APP_SEND_SCR ) // this is SD application specific command
270 cmdctrl |= MSD_APP_CMD;
271 #if 0 // mask by Victor Yu. 12-03-2008
272 if ( cmd->flags & MMC_RSP_LONG ) {
273 cmdctrl |= (MSD_LONG_RSP|MSD_NEED_RSP);
275 if ( cmd->flags & MMC_RSP_SHORT ) {
276 cmdctrl |= MSD_NEED_RSP;
278 #else
279 if ( cmd->flags & MMC_RSP_136 ) {
280 cmdctrl |= (MSD_LONG_RSP|MSD_NEED_RSP);
281 } else {
282 cmdctrl |= MSD_NEED_RSP;
284 #endif
285 writel(cmdctrl|MSD_CMD_EN, &host->reg->command);
287 // wait response
288 while ( retry++ < MSD_RETRY_COUNT ) {
289 status = readl(&host->reg->status);
290 if ( status & MSD_CARD_DETECT ) { // card is removed
291 cmd->error = MMC_ERR_TIMEOUT;
292 break;
294 if ( cmdctrl & MSD_NEED_RSP ) {
295 if ( status & MSD_RSP_TIMEOUT ) {
296 writel(MSD_CLR_RSP_TIMEOUT, &host->reg->clear);
297 cmd->error = MMC_ERR_TIMEOUT;
298 break;
300 #if 0
301 if ( status & MSD_RSP_CRC_FAIL ) {
302 #else
303 if ( (cmd->flags&MMC_RSP_CRC) && (status&MSD_RSP_CRC_FAIL) ) {
304 #endif
305 writel(MSD_CLR_RSP_CRC_FAIL, &host->reg->clear);
306 cmd->error = MMC_ERR_BADCRC;
307 break;
309 if ( status & MSD_RSP_CRC_OK ) {
310 writel(MSD_CLR_RSP_CRC_OK, &host->reg->clear);
311 // read response
312 cmd->resp[0] = readl(&host->reg->response0);
313 cmd->resp[1] = readl(&host->reg->response1);
314 cmd->resp[2] = readl(&host->reg->response2);
315 cmd->resp[3] = readl(&host->reg->response3);
316 cmd->error = MMC_ERR_NONE;
317 break;
319 } else {
320 if ( status & MSD_CMD_SENT ) {
321 writel(MSD_CLR_CMD_SENT, &host->reg->clear);
322 cmd->error = MMC_ERR_NONE;
323 break;
329 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
330 static irqreturn_t moxasd_irq(int irq, void *devid)
331 #else
332 static irqreturn_t moxasd_irq(int irq, void *devid, struct pt_regs *regs)
333 #endif // LINUX_VERSION_CODE
335 struct moxasd_host *host=devid;
336 unsigned int status;
338 // get the interrupt status
339 status = readl(&host->reg->status);
341 // acknowledge the interurpt
342 if ( status & MSD_CARD_CHANGE ) { // has card inserted or removed
343 //writel(MSD_CLR_CARD_CHANGE, &host->reg->clear);
344 tasklet_schedule(&host->card_change_tasklet);
347 if ( status & (MSD_FIFO_ORUN|MSD_FIFO_URUN) ) {
348 writel(status&(MSD_FIFO_ORUN|MSD_FIFO_URUN), &host->reg->clear);
349 tasklet_schedule(&host->fifo_run_tasklet);
352 return IRQ_HANDLED;
355 static void moxasd_fifo_run(unsigned long param)
357 struct moxasd_host *host=(struct moxasd_host *)param;
358 struct mmc_data *data;
359 unsigned long flags;
361 spin_lock_irqsave(&host->lock, flags);
362 host = (struct moxasd_host *)param;
363 data = host->data;
364 if ( host->mrq == NULL || data == NULL ) {
365 spin_unlock_irqrestore(&host->lock, flags);
366 return;
368 moxasd_do_fifo(host, data);
369 if ( host->size == data->bytes_xfered ) {
370 #if 1 // mask by Victor Yu. 07-04-2007
371 unsigned int status;
372 while ( 1 ) {
373 status = readl(&host->reg->status);
374 if ( status & (MSD_DATA_CRC_OK|MSD_DATA_CRC_FAIL|MSD_DATA_END) )
375 break;
376 current->state = TASK_INTERRUPTIBLE;
377 schedule_timeout(5);
379 if ( status & MSD_DATA_CRC_OK ) {
380 writel(MSD_CLR_DATA_CRC_OK, &host->reg->clear);
382 if ( status & MSD_DATA_CRC_FAIL ) {
383 writel(MSD_CLR_DATA_CRC_FAIL, &host->reg->clear);
384 data->error = MMC_ERR_TIMEOUT;
386 if ( status & MSD_DATA_END ) {
387 writel(MSD_CLR_DATA_END, &host->reg->clear);
389 #endif
390 if ( data->stop ) {
391 moxasd_send_command(host, data->stop);
393 } else {
394 spin_unlock_irqrestore(&host->lock, flags);
395 return;
398 moxasd_request_done(host);
399 spin_unlock_irqrestore(&host->lock, flags);
402 static void moxasd_card_change(unsigned long param)
404 struct moxasd_host *host=(struct moxasd_host *)param;
405 unsigned int status;
406 int delay;
407 unsigned long flags;
409 spin_lock_irqsave(&host->lock, flags);
410 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007
411 udelay(1000);
412 udelay(1000);
413 udelay(1000);
414 #else
415 udelay(3000);
416 #endif // LINUX_VERSION_CODE
417 status = readl(&host->reg->status);
418 if ( status & MSD_CARD_DETECT ) { // card removed
419 printk("Moxa CPU SD/MMC card is removed.\n");
420 delay = 0;
421 if ( host->data ) {
422 if ( host->dma && host->size > MSD_FIFO_LENB ) {
423 apb_dma_disable(host->dma);
425 host->size = host->data->bytes_xfered;
426 moxasd_fifo_run(*(unsigned long *)host);
427 host->data->error = MMC_ERR_TIMEOUT;
428 moxasd_request_done(host);
430 #if 1 // add by Victor Yu. 12-03-2008
431 if ( host->mrq ) {
432 host->mrq->cmd->error = MMC_ERR_TIMEOUT;
433 moxasd_request_done(host);
435 #endif
436 } else { // card inserted
437 printk("Moxa CPU SD/MMC card is inserted.\n");
438 if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) { // SD
439 host->mmc->f_max = 25000000;
440 host->mmc->mode = MMC_MODE_SD;
441 } else {
442 host->mmc->f_max = 20000000;
443 host->mmc->mode = MMC_MODE_MMC;
445 delay = 500;
447 writel(MSD_CLR_CARD_CHANGE, &host->reg->clear);
448 spin_unlock_irqrestore(&host->lock, flags);
449 mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
452 static void moxasd_dma_irq(void *param)
454 struct moxasd_host *host=(struct moxasd_host *)param;
456 if ( host )
457 tasklet_schedule(&host->fifo_run_tasklet);
460 static void moxasd_request(struct mmc_host *mmc, struct mmc_request *mrq)
462 struct moxasd_host *host=mmc_priv(mmc);
463 struct mmc_command *cmd;
464 unsigned long flags;
466 spin_lock_irqsave(&host->lock, flags);
467 host->mrq = mrq;
468 cmd = mrq->cmd;
470 // if no card inserted, return timeout error
471 if ( readl(&host->reg->status) & MSD_CARD_DETECT ) { // card is removed
472 cmd->error = MMC_ERR_TIMEOUT;
473 goto request_done;
476 // request include data or not
477 if ( cmd->data ) {
478 moxasd_prepare_data(host, cmd->data);
481 // do request command
482 moxasd_send_command(host, cmd);
484 if ( cmd->data && cmd->error == MMC_ERR_NONE ) {
485 spin_unlock_irqrestore(&host->lock, flags);
486 return;
489 request_done:
490 moxasd_request_done(host);
491 spin_unlock_irqrestore(&host->lock, flags);
494 #define MIN_POWER (MMC_VDD_360 - MSD_SD_POWER_MASK)
495 static void moxasd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
497 struct moxasd_host *host=mmc_priv(mmc);
498 unsigned long flags;
500 spin_lock_irqsave(&host->lock, flags);
501 if (ios->clock) {
502 int div;
503 #ifdef MSD_SUPPORT_GET_CLOCK
504 div = (host->sysclk / (host->mmc->f_max * 2)) - 1;
505 #else
506 div = (APB_CLK / (host->mmc->f_max * 2)) - 1;
507 #endif
508 if ( div > MSD_CLK_DIV_MASK )
509 div = MSD_CLK_DIV_MASK;
510 else if ( div < 0 )
511 div = 0;
512 if ( host->mmc->mode == MMC_MODE_SD )
513 div |= MSD_CLK_SD;
514 writel(div, &host->reg->clock_control);
515 } else if ( !(readl(&host->reg->clock_control) & MSD_CLK_DIS) ) {
517 * Ensure that the clock is off.
519 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
522 if ( ios->power_mode == MMC_POWER_OFF ) {
523 writel(readl(&host->reg->power_control)&~MSD_SD_POWER_ON, &host->reg->power_control);
524 } else {
525 unsigned short power;
526 if ( ios->vdd < MIN_POWER )
527 power = 0;
528 else
529 power = ios->vdd - MIN_POWER;
530 writel(MSD_SD_POWER_ON|(unsigned int)power, &host->reg->power_control);
533 #if 1
534 if ( ios->bus_width == MMC_BUS_WIDTH_1 ) {
535 writel(MSD_SINGLE_BUS, &host->reg->bus_width);
536 } else {
537 writel(MSD_WIDE_BUS, &host->reg->bus_width);
539 #endif
540 spin_unlock_irqrestore(&host->lock, flags);
544 * To check write protect or not. Return 0 for none, 1 for write protect.
546 static int moxasd_get_ro(struct mmc_host *mmc)
548 struct moxasd_host *host=mmc_priv(mmc);
550 if ( readl(&host->reg->status) & MSD_WRITE_PROT )
551 return 1;
552 else
553 return 0;
556 static struct mmc_host_ops moxasd_ops = {
557 .request = moxasd_request,
558 .set_ios = moxasd_set_ios,
559 .get_ro = moxasd_get_ro,
562 static int moxasd_probe(struct device *dev)
564 struct mmc_host *mmc;
565 struct moxasd_host *host=NULL;
566 int ret;
568 mmc = mmc_alloc_host(sizeof(struct moxasd_host), dev);
569 if (!mmc) {
570 ret = -ENOMEM;
571 goto out;
574 mmc->ops = &moxasd_ops;
575 mmc->f_min = 400000;
576 mmc->f_max = 25000000;
577 mmc->mode = MMC_MODE_SD;
578 #if 1
579 mmc->ocr_avail = 0xffff00; // support 2.0v - 3.6v power
580 #else
581 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
582 mmc->caps = MMC_CAP_4_BIT_DATA;
583 mmc->max_hw_segs = 128;
584 mmc->max_phys_segs = 128;
585 mmc->max_sectors = 128;
586 mmc->max_seg_size = mmc->max_sectors * 512;
587 #endif
589 host = mmc_priv(mmc);
590 host->mmc = mmc;
591 spin_lock_init(&host->lock);
592 tasklet_init(&host->card_change_tasklet, moxasd_card_change, (unsigned long)host);
593 tasklet_init(&host->fifo_run_tasklet, moxasd_fifo_run, (unsigned long)host);
594 host->reg = (moxasd_reg *)CPE_SD_VA_BASE;
595 host->dma = apb_dma_alloc(APB_DMA_SD_REQ_NO);
596 if ( host->dma ) {
597 apb_dma_set_irq(host->dma, moxasd_dma_irq, host);
600 #ifdef MSD_SUPPORT_GET_CLOCK
601 // get system clock
603 unsigned int mul, val, div;
604 mul = (*(volatile unsigned int *)(CPE_PMU_VA_BASE+0x30) >> 3) & 0x1ff;
605 val = (*(volatile unsigned int *)(CPE_PMU_VA_BASE+0x0c) >> 4) & 0x7;
606 switch ( val ) {
607 case 0 : div = 2; break;
608 case 1 : div = 3; break;
609 case 2 : div = 4; break;
610 case 3 : div = 6; break;
611 case 4 : div = 8; break;
612 default : div = 2; break;
614 host->sysclk = (38684*mul + 10000) / (div * 10000);
615 host->sysclk = (host->sysclk * 1000000) / 2;
617 #endif
619 // change I/O multiplexing to SD, so the GPIO 17-10 will be fail
620 mcpu_gpio_mp_clear(0xff<<10);
623 * Ensure that the host controller is shut down, and setup
624 * with our defaults.
626 writel(0, &host->reg->interrupt_mask); // disable all interrupt
627 writel(MSD_SDC_RST, &host->reg->command); // reset chip
628 while ( readl(&host->reg->command) & MSD_SDC_RST); // wait for reset finished
629 writel(0, &host->reg->interrupt_mask); // disable all interrupt
631 // to check any card inserted or not
632 if ( !(readl(&host->reg->status) & MSD_CARD_DETECT) ) { // is inserted
633 if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) { // is SD card
634 mmc->f_max = 25000000;
635 mmc->mode = MMC_MODE_SD;
636 } else { // is MMC card
637 mmc->f_max = 20000000;
638 mmc->mode = MMC_MODE_MMC;
642 mmc->caps = MMC_CAP_4_BIT_DATA;
643 writel(MSD_WIDE_BUS, &host->reg->bus_width);
645 cpe_int_set_irq(IRQ_SD, EDGE, H_ACTIVE);
646 ret = request_irq(IRQ_SD, moxasd_irq, SA_INTERRUPT, "MOXASD", host);
647 if (ret)
648 goto out;
650 //writel(MSD_INT_CARD_CHANGE|MSD_INT_FIFO_ORUN|MSD_INT_FIFO_URUN, &host->reg->interrupt_mask);
651 writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
652 dev_set_drvdata(dev, mmc);
653 mmc_add_host(mmc);
655 return 0;
657 out:
658 if (mmc)
659 mmc_free_host(mmc);
661 return ret;
664 static int moxasd_remove(struct device *dev)
666 struct mmc_host *mmc=dev_get_drvdata(dev);
668 dev_set_drvdata(dev, NULL);
670 if (mmc) {
671 struct moxasd_host *host=mmc_priv(mmc);
673 mmc_remove_host(mmc);
675 // stop SD/MMC
676 if ( host->dma ) {
677 apb_dma_disable(host->dma);
678 apb_dma_release_irq(host->dma);
679 apb_dma_release(host->dma);
681 writel(0, &host->reg->interrupt_mask);
682 writel(0, &host->reg->power_control);
683 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
685 free_irq(IRQ_SD, host);
686 tasklet_kill(&host->card_change_tasklet);
687 tasklet_kill(&host->fifo_run_tasklet);
689 mmc_free_host(mmc);
691 return 0;
694 static struct platform_device moxasd_device = {
695 .name = "moxart-sd",
696 .id = -1,
699 static struct device_driver moxasd_driver = {
700 .name = "moxart-sd",
701 .bus = &platform_bus_type,
702 .probe = moxasd_probe,
703 .remove = moxasd_remove,
706 #if 1 // add by Victor Yu. 03-08-2007
707 extern int moxa_gpio_sd_used_flag; // define on arch/arm/kernel/armksyms.c
708 #endif
709 static int __init moxasd_init(void)
711 int ret;
713 printk("Moxa CPU SD/MMC Device Driver V1.1 initialize ");
714 #if 0 // add by Victor Yu. 03-08-2007
716 unsigned long flags;
717 local_irq_save(flags);
718 if ( moxa_gpio_sd_used_flag ) {
719 printk("The IO has used by other device driver !\n");
720 local_irq_restore(flags);
721 return -ENODEV;
723 moxa_gpio_sd_used_flag = 1;
724 local_irq_restore(flags);
726 #endif
727 platform_device_register(&moxasd_device);
728 ret = driver_register(&moxasd_driver);
729 if ( ret ) {
730 printk("Modules load fail !\n");
731 platform_device_unregister(&moxasd_device);
732 } else {
733 printk("Modules load OK.\n");
735 return ret;
738 static void __exit moxasd_exit(void)
740 platform_device_unregister(&moxasd_device);
741 driver_unregister(&moxasd_driver);
742 #if 0 // add by Victor Yu. 12-05-2007
744 unsigned long flags;
745 local_irq_save(flags);
746 moxa_gpio_sd_used_flag = 0;
747 local_irq_restore(flags);
749 #endif
752 module_init(moxasd_init);
753 module_exit(moxasd_exit);
755 MODULE_DESCRIPTION("Moxa CPU SD/Multimedia Card Interface Driver");
756 MODULE_LICENSE("GPL");