MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / mmc.old / moxasd.c.old
blobae2fba0612ebae18a239a8c8b7baef9ac8f621c0
1 /*
2  *  linux/drivers/mmc/moxasd.c - Moxa CPU SD/MMC driver
3  *
4  *  Copyright (C) 2005 Moxa Tech., All Rights Reserved.
5  *
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.
9  *
10  */
11 #include <linux/config.h>
12 #include <asm/arch/cpe/cpe.h>
13 #include <asm/arch/cpe_int.h>
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/ioport.h>
17 #include <linux/device.h>
18 #include <linux/delay.h>
19 #include <linux/interrupt.h>
20 #include <linux/blkdev.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/mmc/host.h>
23 #include <linux/sched.h>
24 #include <linux/delay.h>
25 #include <linux/mmc/protocol.h>
27 #include <asm/dma.h>
28 #include <asm/io.h>
29 #include <asm/irq.h>
30 #include <asm/sizes.h>
31 #include <asm/arch/gpio.h>
33 #include "moxasd.h"
35 //#define MSD_SUPPORT_GET_CLOCK 1
37 #define MSD_RETRY_COUNT         1000
39 //#define CONFIG_MMC_DEBUG
40 #ifdef CONFIG_MMC_DEBUG
41 #define DBG(x...)       printk(x)
42 #else
43 #define DBG(x...)
44 #endif
46 struct moxasd_host {
47         struct mmc_host         *mmc;
48         spinlock_t              lock;
49         moxasd_reg              *reg;
50         apb_dma_priv            *dma;
51 #ifdef MSD_SUPPORT_GET_CLOCK
52         unsigned int            sysclk;
53 #endif
54         struct mmc_request      *mrq;
55         struct mmc_data         *data;
57         struct scatterlist      *cur_sg;        /* Current SG entry */
58         unsigned int            num_sg;         /* Number of entries left */
59         void                    *mapped_sg;     /* vaddr of mapped sg */
60         unsigned int            offset;         /* Offset into current entry */
61         unsigned int            remain;         /* Data left in curren entry */
62         int                     size;           /* Total size of transfer */
64         struct tasklet_struct   card_change_tasklet;
65         struct tasklet_struct   fifo_run_tasklet;
68 static inline void moxasd_init_sg(struct moxasd_host* host, struct mmc_data* data)
70         /*
71          * Get info. about SG list from data structure.
72          */
74         host->cur_sg = data->sg;
75         host->num_sg = data->sg_len;
77         host->offset = 0;
78         host->remain = host->cur_sg->length;
79         data->error = MMC_ERR_NONE;
82 static inline int moxasd_next_sg(struct moxasd_host* host)
84         /*
85          * Skip to next SG entry.
86          */
88         host->cur_sg++;
89         host->num_sg--;
91         /*
92          * Any entries left?
93          */
94         if (host->num_sg > 0) {
95                 host->offset = 0;
96                 host->remain = host->cur_sg->length;
97         }
99         return host->num_sg;
102 static inline char *moxasd_kmap_sg(struct moxasd_host* host)
104         host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
105                 host->cur_sg->offset;
106         return host->mapped_sg;
109 static inline void moxasd_check_data_crc(struct moxasd_host *host, struct mmc_data *data)
111         unsigned int    status;
113         status = readl(&host->reg->status);
114         if ( status & MSD_DATA_CRC_OK ) {
115                 writel(MSD_CLR_DATA_CRC_OK, &host->reg->clear);
116         }
117         if ( status & MSD_DATA_CRC_FAIL ) {
118                 writel(MSD_CLR_DATA_CRC_FAIL, &host->reg->clear);
119                 data->error = MMC_ERR_TIMEOUT;
120         }
121         if ( status & MSD_DATA_END ) {
122                 writel(MSD_CLR_DATA_END, &host->reg->clear);
123         }
126 static inline int moxasd_check_fifo_ready(struct moxasd_host *host)
128         unsigned int    status;
130         status = readl(&host->reg->status);
131         if ( status & MSD_CARD_DETECT ) {       // card is removed
132                 return 0;
133         }
134         if ( status & (MSD_FIFO_URUN|MSD_FIFO_ORUN) ) {
135                 writel(status&(MSD_FIFO_URUN|MSD_FIFO_ORUN), &host->reg->clear);
136         }
137         if ( status & MSD_DATA_TIMEOUT ) {
138                 writel(MSD_CLR_DATA_TIMEOUT, &host->reg->clear);
139                 return 0;
140         }
141         return 1;
144 static void     moxasd_do_fifo(struct moxasd_host *host, struct mmc_data *data)
146         char    *buffer;
147         int     wcnt, i;
148         
149         if ( host->size == data->bytes_xfered ) {
150                 return;
151         }
152         //buffer = moxasd_kmap_sg(host) + host->offset;
153         buffer = moxasd_kmap_sg(host);
154         if ( host->size > MSD_FIFO_LENB && host->dma ) {
155                 apb_dma_conf_param      param;
156                 param.size = host->remain;
157                 param.burst_mode = APB_DMAB_BURST_MODE;
158                 param.data_width = APB_DMAB_DATA_WIDTH_4;
159                 if ( data->flags & MMC_DATA_WRITE ) {
160                         param.source_addr = (unsigned int)buffer;
161                         param.dest_addr = (unsigned int)&host->reg->data_window;
162                         param.dest_inc = APB_DMAB_DEST_INC_0;
163                         param.source_inc = APB_DMAB_DEST_INC_4_16;
164                         param.dest_sel = APB_DMAB_DEST_APB;
165                         param.source_sel = APB_DMAB_SOURCE_AHB;
166                 } else { 
167                         param.dest_addr = (unsigned int)buffer;
168                         param.source_addr = (unsigned int)&host->reg->data_window;
169                         param.source_inc = APB_DMAB_DEST_INC_0;
170                         param.dest_inc = APB_DMAB_DEST_INC_4_16;
171                         param.source_sel = APB_DMAB_DEST_APB;
172                         param.dest_sel = APB_DMAB_SOURCE_AHB;
173                 }
174                 data->bytes_xfered += host->remain;
175 #if 0   // don't need to do this
176                 host->offset = host->remain;
177                 host->remain = 0;
178 #endif
179                 apb_dma_conf(host->dma, &param);
180                 kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
181                 moxasd_next_sg(host);
182                 apb_dma_enable(host->dma);
183         } else {
184 #if 0
185                 if ( host->remain >= MSD_FIFO_LENB )
186                         wcnt = MSD_FIFO_LENW;
187                 else
188 #endif
189                         wcnt = host->remain >> 2;
190                 if ( data->flags & MMC_DATA_WRITE ) {
191                         for ( i=0; i<wcnt; i++, buffer+=4 )
192                                 writel(*(unsigned int *)buffer, &host->reg->data_window);
193                 } else {
194                         for ( i=0; i<wcnt; i++, buffer+=4 )
195                                 *(unsigned int *)buffer = readl(&host->reg->data_window);
196                 }
197                 wcnt <<= 2;
198                 host->offset += wcnt;
199                 host->remain -= wcnt;
200                 data->bytes_xfered += wcnt;
201                 kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
202                 /* because this will be just one time
203                 if ( host->remain <= 0 )
204                         moxasd_next_sg(host);
205                 */
206         }
209 static void moxasd_request_done(struct moxasd_host *host)
211         struct mmc_request      *mrq=host->mrq;
213         if ( mrq == NULL ) {
214                 return;
215         }
216         host->mrq = NULL;
217         host->data = NULL;
218         mmc_request_done(host->mmc, mrq);
221 static void moxasd_prepare_data(struct moxasd_host *host, struct mmc_data *data)
223         unsigned int    timeout, datactrl;
225         host->data = data;
226         moxasd_init_sg(host, data);
228         // initialize the timeout value
229         timeout = (host->mmc->f_max/1000000) * (data->timeout_ns/1000);
230         timeout += data->timeout_clks;
231         writel(timeout, &host->reg->data_timer);
233         // initialize the data size
234         host->size = data->blocks << data->blksz_bits;
235         writel(host->size, &host->reg->data_length);
237         // initialize the data control
238         datactrl = (data->blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN;
239         if ( data->flags & MMC_DATA_WRITE ) {
240                 datactrl |= MSD_DATA_WRITE;
241         }
242         if ( host->size > MSD_FIFO_LENB && host->dma ) {
243                 datactrl |= MSD_DMA_EN;
244         }
245         writel(datactrl, &host->reg->data_control);
247 #if 1
248         //if ( host->size > MSD_FIFO_LENB && (data->flags & MMC_DATA_READ) ) {
249         if ( host->size > MSD_FIFO_LENB ) {
250                 // disable the overrun & underrun interrupt
251                 unsigned long flags;
252                 save_flags(flags);
253                 cli();
254                 writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
255                 restore_flags(flags);
256                 moxasd_do_fifo(host, data);
257         } else {
258                 // enable the overrun & underrun interrupt
259                 unsigned long flags;
260                 save_flags(flags);
261                 cli();
262                 writel(MSD_INT_FIFO_URUN|MSD_INT_FIFO_ORUN|MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
263                 restore_flags(flags);
264         }
265 #endif
268 static void moxasd_send_command(struct moxasd_host *host, struct mmc_command *cmd)
270         unsigned int    status, cmdctrl;
271         int             retry=0;
273         // first clear status
274         writel(MSD_CLR_RSP_TIMEOUT|MSD_CLR_RSP_CRC_OK|MSD_CLR_RSP_CRC_FAIL|MSD_CLR_CMD_SENT, &host->reg->clear);
276         // write argument
277         writel(cmd->arg, &host->reg->argument);
279         // write command
280         cmdctrl = cmd->opcode & MSD_CMD_IDX_MASK;
281         if ( cmdctrl == SD_APP_SET_BUS_WIDTH ||
282              cmdctrl == SD_APP_OP_COND ||
283              cmdctrl == SD_APP_SEND_SCR )       // this is SD application specific command
284                 cmdctrl |= MSD_APP_CMD;
285         if ( cmd->flags & MMC_RSP_LONG )
286                 cmdctrl |= (MSD_LONG_RSP|MSD_NEED_RSP);
287         if ( cmd->flags & MMC_RSP_SHORT )
288                 cmdctrl |= MSD_NEED_RSP;
289         writel(cmdctrl|MSD_CMD_EN, &host->reg->command);
292         // wait response
293         while ( retry++ < MSD_RETRY_COUNT ) {
294                 status = readl(&host->reg->status);
295                 if ( status & MSD_CARD_DETECT ) {       // card is removed
296                         cmd->error = MMC_ERR_TIMEOUT;
297                         return;
298                 }
299                 if ( cmdctrl & MSD_NEED_RSP ) {
300                         if ( status & MSD_RSP_TIMEOUT ) {
301                                 writel(MSD_CLR_RSP_TIMEOUT, &host->reg->clear);
302                                 cmd->error = MMC_ERR_TIMEOUT;
303                                 return;
304                         }
305 #if 0
306                         if ( status & MSD_RSP_CRC_FAIL ) {
307 #else
308                         if ( (cmd->flags&MMC_RSP_CRC) && (status&MSD_RSP_CRC_FAIL) ) {
309 #endif
310                                 writel(MSD_CLR_RSP_CRC_FAIL, &host->reg->clear);
311                                 cmd->error = MMC_ERR_BADCRC;
312                                 return;
313                         }
314                         if ( status & MSD_RSP_CRC_OK ) {
315                                 writel(MSD_CLR_RSP_CRC_OK, &host->reg->clear);
316                                 // read response
317                                 cmd->resp[0] = readl(&host->reg->response0);
318                                 cmd->resp[1] = readl(&host->reg->response1);
319                                 cmd->resp[2] = readl(&host->reg->response2);
320                                 cmd->resp[3] = readl(&host->reg->response3);
321                                 cmd->error = MMC_ERR_NONE;
322                                 return;
323                         }
324                 } else {
325                         if ( status & MSD_CMD_SENT ) {
326                                 writel(MSD_CLR_CMD_SENT, &host->reg->clear);
327                                 cmd->error = MMC_ERR_NONE;
328                                 return;
329                         }
330                 }
331         }
333 //      cmd->error = MMC_ERR_TIMEOUT;
334         cmd->error = MMC_ERR_NONE;
338 static irqreturn_t moxasd_irq(int irq, void *devid, struct pt_regs *regs)
340         struct moxasd_host      *host=devid;
341         unsigned int            status;
343         // get the interrupt status
345         status = readl(&host->reg->status);
346         
347         // acknowledge the interurpt
348         if ( status & MSD_CARD_CHANGE ) {       // has card inserted or removed
349                 //writel(MSD_CLR_CARD_CHANGE, &host->reg->clear);
350                 tasklet_schedule(&host->card_change_tasklet);
351         }
353         if ( status & (MSD_FIFO_ORUN|MSD_FIFO_URUN) ) {
354                 writel(status&(MSD_FIFO_ORUN|MSD_FIFO_URUN), &host->reg->clear);
355                 tasklet_schedule(&host->fifo_run_tasklet);
356         }
358         return IRQ_HANDLED;
361 static void moxasd_fifo_run(unsigned long param)
363         struct moxasd_host      *host=(struct moxasd_host *)param;
364         struct mmc_data         *data;
366         /*
367         if ( !moxasd_check_fifo_ready(host) && host->data ) {
368                 host->size = host->data->bytes_xfered;
369                 host->data->error = MMC_ERR_TIMEOUT;
370                 if ( host->dma && host->size > MSD_FIFO_LENB ) {
371                         apb_dma_disable(host->dma);
372                 }
373         }
374         writel(readl(&host->reg->status)&(MSD_FIFO_URUN|MSD_FIFO_ORUN), &host->reg->clear);
375         */
376         
377         spin_lock(&host->lock);
378         if ( host->mrq == NULL ) {
379                 spin_unlock(&host->lock);
380                 return;
381         }
382 #if 0   // never happened
383         if ( host->data == NULL ) {
384                 goto moxasd_fifo_run_done;
385         }
386 #endif
387         data = host->data;
388         moxasd_do_fifo(host, data);
389         if ( host->size == data->bytes_xfered ) {
390 #if 0
391                 // maybe need to check the data is OK or fail
392                 if ( data->error == MMC_ERR_NONE ) {
393                         moxasd_check_data_crc(host, data);
394                 }
395 #endif
396                 if ( data->stop ) {
397                         moxasd_send_command(host, data->stop);
398                 }
399         } else {
400                 spin_unlock(&host->lock);
401                 //tasklet_schedule(&host->fifo_run_tasklet);
402                 return;
403         }
404         
405 //moxasd_fifo_run_done:
406         moxasd_request_done(host);
407         spin_unlock(&host->lock);
410 static void moxasd_card_change(unsigned long param)
412         struct moxasd_host      *host=(struct moxasd_host *)param;
413         unsigned int            status;
414         int                     delay;
416         spin_lock(&host->lock);
417         udelay(3000);   // to wait the hardware stably for card inserted or removed
418         status = readl(&host->reg->status);
419         if ( status & MSD_CARD_DETECT ) {       // card removed
420                 printk("Moxa CPU SD/MMC card is removed.\n");
421                 delay = 0;
422                 if ( host->data ) {
423                         if ( host->dma && host->size > MSD_FIFO_LENB )
424                                 apb_dma_disable(host->dma);
425                         host->size = host->data->bytes_xfered;
426                         spin_unlock(&host->lock);
427                         moxasd_fifo_run(*(unsigned long *)host);
428                         spin_lock(&host->lock);
429                 }
430         } else {        // card inserted
431                 printk("Moxa CPU SD/MMC card is inserted.\n");
432                 if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) {  // SD
433                         host->mmc->f_max = 25000000;
435                         host->mmc->mode = MMC_MODE_SD;
436                 } else {
437                         host->mmc->f_max = 20000000;
438                         host->mmc->mode = MMC_MODE_MMC;
439                 }
440                 delay = 500;
441         }
442         writel(MSD_CLR_CARD_CHANGE, &host->reg->clear);
443         spin_unlock(&host->lock);
444         mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
447 static void moxasd_dma_irq(void *param)
449         struct moxasd_host      *host=(struct moxasd_host *)param;
451         if ( host->data ) {
452                 struct mmc_data *data=host->data;
453                 if ( host->dma->error_flag ) {
454                         host->size = data->bytes_xfered;
455                         data->error = MMC_ERR_TIMEOUT;
456                 }
457 #if 1
458                 tasklet_schedule(&host->fifo_run_tasklet);
459 #endif
460         }
463 static void moxasd_request(struct mmc_host *mmc, struct mmc_request *mrq)
465         struct moxasd_host      *host=mmc_priv(mmc);
466         struct mmc_command      *cmd;
467         
468         spin_lock(&host->lock);
469         host->mrq = mrq;
470         cmd = mrq->cmd;
471         
472         // if no card inserted, return timeout error
473         if ( readl(&host->reg->status) & MSD_CARD_DETECT ) {    // card is removed
474                 cmd->error = MMC_ERR_TIMEOUT;
475                 goto request_done;
476         }
478         // request include data or not
479         if ( cmd->data ) {
480                 moxasd_prepare_data(host, cmd->data);
481         }
483         
484         // do request command
485         moxasd_send_command(host, cmd);
487         if ( cmd->data && cmd->error == MMC_ERR_NONE ) {
488                 spin_unlock(&host->lock);
489                 return;
490         }
493 request_done:
494         moxasd_request_done(host);
495         spin_unlock(&host->lock);
498 #define MIN_POWER       (MMC_VDD_360 - MSD_SD_POWER_MASK)
499 static void moxasd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
501         struct moxasd_host      *host=mmc_priv(mmc);
503         spin_lock(&host->lock);
504         if (ios->clock) {
505                 int     div;
506 #ifdef MSD_SUPPORT_GET_CLOCK
507                 div = (host->sysclk / (host->mmc->f_max * 2)) - 1;
508 #else
509                 div = (APB_CLK / (host->mmc->f_max * 2)) - 1;
510 #endif
511                 if ( div > MSD_CLK_DIV_MASK )
512                         div = MSD_CLK_DIV_MASK;
513                 else if ( div < 0 )
514                         div = 0;
515                 if ( host->mmc->mode == MMC_MODE_SD )
516                         div |= MSD_CLK_SD;
517                 writel(div, &host->reg->clock_control);
518         } else if ( !(readl(&host->reg->clock_control) & MSD_CLK_DIS) ) {
519                 /*
520                  * Ensure that the clock is off.
521                  */
522                 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
523         }
525         if ( ios->power_mode == MMC_POWER_OFF ) {
526                 writel(readl(&host->reg->power_control)&~MSD_SD_POWER_ON, &host->reg->power_control);
527         } else {
528                 unsigned short  power;
529                 if ( ios->vdd < MIN_POWER )
530                         power = 0;
531                 else
532                         power = ios->vdd - MIN_POWER;
533                 writel(MSD_SD_POWER_ON|(unsigned int)power, &host->reg->power_control);
534         }
536 #if 1
537         if ( ios->bus_width == MMC_BUS_WIDTH_1 ) {
538                 writel(MSD_SINGLE_BUS, &host->reg->bus_width);
539         } else {
540                 writel(MSD_WIDE_BUS, &host->reg->bus_width);
541         }
542 #endif
543         spin_unlock(&host->lock);
546 /* 
547  * To check write protect or not. Return 0 for none, 1 for write protect.
548  */
549 static int      moxasd_get_ro(struct mmc_host *mmc)
551         struct moxasd_host      *host=mmc_priv(mmc);
553         if ( readl(&host->reg->status) & MSD_WRITE_PROT )
554                 return 1;
555         else
556                 return 0;
559 static struct mmc_host_ops moxasd_ops = {
560         .request        = moxasd_request,
561         .set_ios        = moxasd_set_ios,
562         .get_ro         = moxasd_get_ro,
565 static int moxasd_probe(struct device *dev)
567         struct mmc_host         *mmc;
568         struct moxasd_host      *host=NULL;
569         int                     ret;
571         mmc = mmc_alloc_host(sizeof(struct moxasd_host), dev);
572         if (!mmc) {
573                 ret = -ENOMEM;
574                 goto out;
575         }
577         mmc->ops = &moxasd_ops;
578         mmc->f_min = 400000;
579         mmc->f_max = 25000000;
581         mmc->mode = MMC_MODE_SD;
582 #if 1
583         mmc->ocr_avail = 0xffff00;      // support 2.0v - 3.6v power
584 #else
585         mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
586         mmc->caps = MMC_CAP_4_BIT_DATA;
587         mmc->max_hw_segs = 128;
588         mmc->max_phys_segs = 128;
589         mmc->max_sectors = 128;
590         mmc->max_seg_size = mmc->max_sectors * 512;
591 #endif
593         host = mmc_priv(mmc);
594         host->mmc = mmc;
595         spin_lock_init(&host->lock);
596         tasklet_init(&host->card_change_tasklet, moxasd_card_change, (unsigned long)host);
597         tasklet_init(&host->fifo_run_tasklet, moxasd_fifo_run, (unsigned long)host);
598         host->reg = (moxasd_reg *)CPE_SD_VA_BASE;
599         host->dma = apb_dma_alloc(APB_DMA_SD_REQ_NO);
600         if ( host->dma ) {
601                 apb_dma_set_irq(host->dma, moxasd_dma_irq, host);
602         }
604 #ifdef MSD_SUPPORT_GET_CLOCK
605         // get system clock
606         {
607         unsigned int    mul, val, div;
608         mul = (*(volatile unsigned int *)(CPE_PMU_VA_BASE+0x30) >> 3) & 0x1ff;
609         val = (*(volatile unsigned int *)(CPE_PMU_VA_BASE+0x0c) >> 4) & 0x7;
610         switch ( val ) {
611         case 0 :        div = 2;        break;
612         case 1 :        div = 3;        break;
613         case 2 :        div = 4;        break;
614         case 3 :        div = 6;        break;
615         case 4 :        div = 8;        break;
616         default :       div = 2;        break;
617         }
618         host->sysclk = (38684*mul + 10000) / (div * 10000);
619         host->sysclk = (host->sysclk * 1000000) / 2;
620         }
621 #endif
623         // change I/O multiplexing to SD, so the GPIO 17-10 will be fail
624 #if 0   // mask by Victor Yu. 03-06-2006
625         *(volatile unsigned int *)(CPE_PMU_VA_BASE+0x100) &= (~(0xff<<10));
626 #else   // add by Victor Yu. 03-06-2006
627         mcpu_gpio_mp_clear(0xff<<10);
628 #endif
630         /*
631          * Ensure that the host controller is shut down, and setup
632          * with our defaults.
633          */
634         writel(0, &host->reg->interrupt_mask);  // disable all interrupt
635         writel(MSD_SDC_RST, &host->reg->command);       // reset chip
636         while ( readl(&host->reg->command) & MSD_SDC_RST);      // wait for reset finished
637         writel(0, &host->reg->interrupt_mask);  // disable all interrupt
639         // to check any card inserted or not
640 #if 1
641         if ( !(readl(&host->reg->status) & MSD_CARD_DETECT) ) { // is inserted
642                 if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) {  // is SD card
643                         mmc->f_max = 25000000;
644                         mmc->mode = MMC_MODE_SD;
645                 } else {        // is MMC card
646                         mmc->f_max = 20000000;
647                         mmc->mode = MMC_MODE_MMC;
648                 }
649         }
650 #endif
652         mmc->caps = MMC_CAP_4_BIT_DATA;
653         writel(MSD_WIDE_BUS, &host->reg->bus_width);
655         cpe_int_set_irq(IRQ_SD, EDGE, H_ACTIVE);
656         ret = request_irq(IRQ_SD, moxasd_irq, SA_INTERRUPT, "MOXASD", host);
657         if (ret)
658                 goto out;
660         //writel(MSD_INT_CARD_CHANGE|MSD_INT_FIFO_ORUN|MSD_INT_FIFO_URUN, &host->reg->interrupt_mask);
661         writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
662         dev_set_drvdata(dev, mmc);
663         mmc_add_host(mmc);
665         return 0;
667  out:
668         if (mmc)
669                 mmc_free_host(mmc);
671         return ret;
674 static int moxasd_remove(struct device *dev)
676         struct mmc_host *mmc=dev_get_drvdata(dev);
677         
678         dev_set_drvdata(dev, NULL);
680         if (mmc) {
681                 struct moxasd_host      *host=mmc_priv(mmc);
683                 mmc_remove_host(mmc);
685                 // stop SD/MMC
686                 if ( host->dma ) {
687                         apb_dma_disable(host->dma);
688                         apb_dma_release_irq(host->dma);
689                         apb_dma_release(host->dma);
690                 }
691                 writel(0, &host->reg->interrupt_mask);
692                 writel(0, &host->reg->power_control);
693                 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
695                 free_irq(IRQ_SD, host);
696                 tasklet_kill(&host->card_change_tasklet);
697                 tasklet_kill(&host->fifo_run_tasklet);
699                 mmc_free_host(mmc);
700         }
701         return 0;
704 static struct platform_device moxasd_device = {
705         .name   = "moxart-sd",
706         .id     = -1,
709 static struct device_driver moxasd_driver = {
710         .name           = "moxart-sd",
711         .bus            = &platform_bus_type,
712         .probe          = moxasd_probe,
713         .remove         = moxasd_remove,
716 static int __init moxasd_init(void)
718         int     ret;
720         printk("Moxa CPU SD/MMC Device Driver V1.0 initialize ");
721         platform_device_register(&moxasd_device);
722         ret = driver_register(&moxasd_driver);
723         if ( ret ) {
724                 printk("fail !\n");
725                 platform_device_unregister(&moxasd_device);
726         } else {
727                 printk("OK.\n");
728         }
729         return ret;
732 static void __exit moxasd_exit(void)
734         platform_device_unregister(&moxasd_device);
735         driver_unregister(&moxasd_driver);
738 module_init(moxasd_init);
739 module_exit(moxasd_exit);
741 MODULE_DESCRIPTION("Moxa CPU SD/Multimedia Card Interface Driver");
742 MODULE_LICENSE("GPL");