MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / mmc / moxasd.c
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 #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/moxa.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/protocol.h>
34
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>
40
41 #include "moxasd.h"
42
43 #if 0   // mask by Victor Yu. 03-19-2007
44 #define MSD_RETRY_COUNT         1000
45 #else
46 #define MSD_RETRY_COUNT         100
47 #endif
48 //#define CONFIG_MMC_DEBUG
49 #ifdef CONFIG_MMC_DEBUG
50 #define DBG(x...)       printk(x)
51 #else
52 #define DBG(x...)
53 #endif
54
55 struct moxasd_host {
56         struct mmc_host         *mmc;
57         spinlock_t              lock;
58         moxasd_reg              *reg;
59         apb_dma_priv            *dma;
60 #ifdef MSD_SUPPORT_GET_CLOCK
61         unsigned int            sysclk;
62 #endif
63         struct mmc_request      *mrq;
64         struct mmc_data         *data;
65
66         struct scatterlist      *cur_sg;        /* Current SG entry */
67         unsigned int            num_sg;         /* Number of entries left */
68         void                    *mapped_sg;     /* vaddr of mapped sg */
69         unsigned int            remain;         /* Data left in curren entry */
70         int                     size;           /* Total size of transfer */
71
72         struct tasklet_struct   card_change_tasklet;
73         struct tasklet_struct   fifo_run_tasklet;
74 };
75
76 static inline void moxasd_init_sg(struct moxasd_host* host, struct mmc_data* data)
77 {
78         /*
79          * Get info. about SG list from data structure.
80          */
81         host->cur_sg = data->sg;
82         host->num_sg = data->sg_len;
83
84         host->remain = host->cur_sg->length;
85 #if 1   // add by Victor Yu. 07-04-2007
86         if ( host->remain > host->size )
87                 host->remain = host->size;
88         host->mapped_sg = NULL;
89 #endif
90         data->error = MMC_ERR_NONE;
91 }
92
93 static inline int moxasd_next_sg(struct moxasd_host* host)
94 {
95 #if 1   // add by Victor Yu. 07-04-2007
96         struct mmc_data *data=host->data;
97 #endif
98         /*
99          * Skip to next SG entry.
100          */
101         host->cur_sg++;
102         host->num_sg--;
103
104         /*
105          * Any entries left?
106          */
107         if (host->num_sg > 0) {
108                 host->remain = host->cur_sg->length;
109 #if 1   // add by Victor Yu. 07-04-2007
110                 {
111                 int     remain;
112                 remain = host->size - data->bytes_xfered;
113                 if ( remain > 0 && remain < host->remain ) {
114                         host->remain = remain;
115                 }
116                 }
117 #endif
118         }
119
120         return host->num_sg;
121 }
122
123 static inline char *moxasd_kmap_sg(struct moxasd_host* host)
124 {
125         host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
126         return host->mapped_sg + host->cur_sg->offset;
127 }
128
129 static void     moxasd_do_fifo(struct moxasd_host *host, struct mmc_data *data)
130 {
131         char    *buffer;
132         int     wcnt, i;
133
134 #if 1   // add by Victor Yu. 07-06-2007
135         if ( host->mapped_sg ) {
136                 kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
137                 moxasd_next_sg(host);
138         }
139 #endif
140         if ( host->size == data->bytes_xfered ) {
141                 return;
142         }
143         buffer = moxasd_kmap_sg(host);
144         if ( host->size > MSD_FIFO_LENB && host->dma ) {
145                 apb_dma_conf_param      param;
146                 param.size = host->remain;
147                 param.burst_mode = APB_DMAB_BURST_MODE;
148                 param.data_width = APB_DMAB_DATA_WIDTH_4;
149                 if ( data->flags & MMC_DATA_WRITE ) {
150                         param.source_addr = (unsigned int)buffer;
151                         param.dest_addr = (unsigned int)&host->reg->data_window;
152                         param.dest_inc = APB_DMAB_DEST_INC_0;
153                         param.source_inc = APB_DMAB_DEST_INC_4_16;
154                         param.dest_sel = APB_DMAB_DEST_APB;
155                         param.source_sel = APB_DMAB_SOURCE_AHB;
156                 } else { 
157                         param.dest_addr = (unsigned int)buffer;
158                         param.source_addr = (unsigned int)&host->reg->data_window;
159                         param.source_inc = APB_DMAB_DEST_INC_0;
160                         param.dest_inc = APB_DMAB_DEST_INC_4_16;
161                         param.source_sel = APB_DMAB_DEST_APB;
162                         param.dest_sel = APB_DMAB_SOURCE_AHB;
163                 }
164                 data->bytes_xfered += host->remain;
165                 apb_dma_conf(host->dma, &param);
166                 apb_dma_enable(host->dma);
167         } else {
168                 wcnt = host->remain >> 2;
169                 if ( data->flags & MMC_DATA_WRITE ) {
170                         for ( i=0; i<wcnt; i++, buffer+=4 )
171                                 writel(*(unsigned int *)buffer, &host->reg->data_window);
172                 } else {
173                         for ( i=0; i<wcnt; i++, buffer+=4 )
174                                 *(unsigned int *)buffer = readl(&host->reg->data_window);
175                 }
176                 wcnt <<= 2;
177                 host->remain -= wcnt;
178                 data->bytes_xfered += wcnt;
179         }
180 }
181
182 static void moxasd_request_done(struct moxasd_host *host)
183 {
184         struct mmc_request      *mrq=host->mrq;
185
186         if ( mrq == NULL ) {
187                 return;
188         }
189         host->mrq = NULL;
190         host->data = NULL;
191         mmc_request_done(host->mmc, mrq);
192 }
193
194 static void moxasd_prepare_data(struct moxasd_host *host, struct mmc_data *data)
195 {
196         unsigned int    timeout, datactrl;
197 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)  // add by Victor Yu. 03-07-2007
198         int             blksz_bits;
199 #endif  // LINUX_VERSION_CODE
200
201         host->data = data;
202         // initialize the data size
203 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)  // add by Victor Yu. 03-07-2007
204         host->size = data->blocks * data->blksz;
205         blksz_bits = ffs(data->blksz) - 1;
206         BUG_ON(1 << blksz_bits != data->blksz);
207 #else
208         host->size = data->blocks << data->blksz_bits;
209 #endif  // LINUX_VERSION_CODE
210         moxasd_init_sg(host, data);
211
212         // initialize the timeout value
213         timeout = (host->mmc->f_max/1000) * (data->timeout_ns/1000);
214         timeout *= 2;
215
216         // initialize the data control
217 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)  // add by Victor Yu. 03-07-2007
218         datactrl = (blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN;
219 #else
220         datactrl = (data->blksz_bits & MSD_BLK_SIZE_MASK) | MSD_DATA_EN;
221 #endif  // LINUX_VERSION_CODE
222         if ( data->flags & MMC_DATA_WRITE ) {
223                 datactrl |= MSD_DATA_WRITE;
224         }
225         if ( host->size > MSD_FIFO_LENB && host->dma ) {
226                 datactrl |= MSD_DMA_EN;
227         }
228         writel(timeout, &host->reg->data_timer);
229         writel(host->size, &host->reg->data_length);
230         writel(datactrl, &host->reg->data_control);
231
232         if ( host->size > MSD_FIFO_LENB && host->dma ) {
233                 writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
234                 moxasd_do_fifo(host, data);
235                 //tasklet_schedule(&host->fifo_run_tasklet);
236         } else {
237                 writel(MSD_INT_FIFO_URUN|MSD_INT_FIFO_ORUN|MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
238         }
239 }
240
241 static void moxasd_send_command(struct moxasd_host *host, struct mmc_command *cmd)
242 {
243         unsigned int    status, cmdctrl;
244         int             retry=0;
245
246 #if 1   // add by Victor Yu. 03-19-2007
247         cmd->error = MMC_ERR_TIMEOUT;
248 #endif
249
250         // first clear status
251         writel(MSD_CLR_RSP_TIMEOUT|MSD_CLR_RSP_CRC_OK|MSD_CLR_RSP_CRC_FAIL|MSD_CLR_CMD_SENT, &host->reg->clear);
252
253         // write argument
254         writel(cmd->arg, &host->reg->argument);
255
256         // write command
257         cmdctrl = cmd->opcode & MSD_CMD_IDX_MASK;
258         if ( cmdctrl == SD_APP_SET_BUS_WIDTH ||
259              cmdctrl == SD_APP_OP_COND ||
260              cmdctrl == SD_APP_SEND_SCR )       // this is SD application specific command
261                 cmdctrl |= MSD_APP_CMD;
262         if ( cmd->flags & MMC_RSP_LONG )
263                 cmdctrl |= (MSD_LONG_RSP|MSD_NEED_RSP);
264         if ( cmd->flags & MMC_RSP_SHORT )
265                 cmdctrl |= MSD_NEED_RSP;
266         writel(cmdctrl|MSD_CMD_EN, &host->reg->command);
267
268         // wait response
269         while ( retry++ < MSD_RETRY_COUNT ) {
270                 status = readl(&host->reg->status);
271                 if ( status & MSD_CARD_DETECT ) {       // card is removed
272                         cmd->error = MMC_ERR_TIMEOUT;
273                         break;
274                 }
275                 if ( cmdctrl & MSD_NEED_RSP ) {
276                         if ( status & MSD_RSP_TIMEOUT ) {
277                                 writel(MSD_CLR_RSP_TIMEOUT, &host->reg->clear);
278                                 cmd->error = MMC_ERR_TIMEOUT;
279                                 break;
280                         }
281 #if 0
282                         if ( status & MSD_RSP_CRC_FAIL ) {
283 #else
284                         if ( (cmd->flags&MMC_RSP_CRC) && (status&MSD_RSP_CRC_FAIL) ) {
285 #endif
286                                 writel(MSD_CLR_RSP_CRC_FAIL, &host->reg->clear);
287                                 cmd->error = MMC_ERR_BADCRC;
288                                 break;
289                         }
290                         if ( status & MSD_RSP_CRC_OK ) {
291                                 writel(MSD_CLR_RSP_CRC_OK, &host->reg->clear);
292                                 // read response
293                                 cmd->resp[0] = readl(&host->reg->response0);
294                                 cmd->resp[1] = readl(&host->reg->response1);
295                                 cmd->resp[2] = readl(&host->reg->response2);
296                                 cmd->resp[3] = readl(&host->reg->response3);
297                                 cmd->error = MMC_ERR_NONE;
298                                 break;
299                         }
300                 } else {
301                         if ( status & MSD_CMD_SENT ) {
302                                 writel(MSD_CLR_CMD_SENT, &host->reg->clear);
303                                 cmd->error = MMC_ERR_NONE;
304                                 break;
305                         }
306                 }
307         }
308 }
309
310 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
311 static irqreturn_t moxasd_irq(int irq, void *devid)
312 #else
313 static irqreturn_t moxasd_irq(int irq, void *devid, struct pt_regs *regs)
314 #endif  // LINUX_VERSION_CODE
315 {
316         struct moxasd_host      *host=devid;
317         unsigned int            status;
318
319         // get the interrupt status
320         status = readl(&host->reg->status);
321         
322         // acknowledge the interurpt
323         if ( status & MSD_CARD_CHANGE ) {       // has card inserted or removed
324                 //writel(MSD_CLR_CARD_CHANGE, &host->reg->clear);
325                 tasklet_schedule(&host->card_change_tasklet);
326         }
327
328         if ( status & (MSD_FIFO_ORUN|MSD_FIFO_URUN) ) {
329                 writel(status&(MSD_FIFO_ORUN|MSD_FIFO_URUN), &host->reg->clear);
330                 tasklet_schedule(&host->fifo_run_tasklet);
331         }
332
333         return IRQ_HANDLED;
334 }
335
336 static void moxasd_fifo_run(unsigned long param)
337 {
338         struct moxasd_host      *host=(struct moxasd_host *)param;
339         struct mmc_data         *data;
340         unsigned long           flags;
341
342         spin_lock_irqsave(&host->lock, flags);
343         host = (struct moxasd_host *)param;
344         data = host->data;
345         if ( host->mrq == NULL || data == NULL ) {
346                 spin_unlock_irqrestore(&host->lock, flags);
347                 return;
348         }
349         moxasd_do_fifo(host, data);
350         if ( host->size == data->bytes_xfered ) {
351 #if 1   // mask by Victor Yu. 07-04-2007
352                 unsigned int            status;
353                 while ( 1 ) {
354                         status = readl(&host->reg->status);
355                         if ( status & (MSD_DATA_CRC_OK|MSD_DATA_CRC_FAIL|MSD_DATA_END) )
356                                 break;
357                         current->state = TASK_INTERRUPTIBLE;
358                         schedule_timeout(5);
359                 }
360                 if ( status & MSD_DATA_CRC_OK ) {
361                         writel(MSD_CLR_DATA_CRC_OK, &host->reg->clear);
362                 }
363                 if ( status & MSD_DATA_CRC_FAIL ) {
364                         writel(MSD_CLR_DATA_CRC_FAIL, &host->reg->clear);
365                         data->error = MMC_ERR_TIMEOUT;
366                 }
367                 if ( status & MSD_DATA_END ) {
368                         writel(MSD_CLR_DATA_END, &host->reg->clear);
369                 }
370 #endif
371                 if ( data->stop ) {
372                         moxasd_send_command(host, data->stop);
373                 }
374         } else {
375                 spin_unlock_irqrestore(&host->lock, flags);
376                 return;
377         }
378         
379         moxasd_request_done(host);
380         spin_unlock_irqrestore(&host->lock, flags);
381 }
382
383 static void moxasd_card_change(unsigned long param)
384 {
385         struct moxasd_host      *host=(struct moxasd_host *)param;
386         unsigned int            status;
387         int                     delay;
388         unsigned long           flags;
389
390         spin_lock_irqsave(&host->lock, flags);
391 #if LINUX_VERSION_CODE  > KERNEL_VERSION(2,6,9) // add by Victor Yu. 03-07-2007
392         udelay(1000);
393         udelay(1000);
394         udelay(1000);
395 #else
396         udelay(3000);
397 #endif  // LINUX_VERSION_CODE
398         status = readl(&host->reg->status);
399         if ( status & MSD_CARD_DETECT ) {       // card removed
400                 printk("Moxa CPU SD/MMC card is removed.\n");
401                 delay = 0;
402                 if ( host->data ) {
403                         if ( host->dma && host->size > MSD_FIFO_LENB )
404                                 apb_dma_disable(host->dma);
405                         host->size = host->data->bytes_xfered;
406                         moxasd_fifo_run(*(unsigned long *)host);
407                         host->data->error = MMC_ERR_TIMEOUT;
408                         moxasd_request_done(host);
409                 }
410         } else {        // card inserted
411                 printk("Moxa CPU SD/MMC card is inserted.\n");
412                 if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) {  // SD
413                         host->mmc->f_max = 25000000;
414                         host->mmc->mode = MMC_MODE_SD;
415                 } else {
416                         host->mmc->f_max = 20000000;
417                         host->mmc->mode = MMC_MODE_MMC;
418                 }
419                 delay = 500;
420         }
421         writel(MSD_CLR_CARD_CHANGE, &host->reg->clear);
422         spin_unlock_irqrestore(&host->lock, flags);
423         mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
424 }
425
426 static void moxasd_dma_irq(void *param)
427 {
428         struct moxasd_host      *host=(struct moxasd_host *)param;
429
430         if ( host )
431                 tasklet_schedule(&host->fifo_run_tasklet);
432 }
433
434 static void moxasd_request(struct mmc_host *mmc, struct mmc_request *mrq)
435 {
436         struct moxasd_host      *host=mmc_priv(mmc);
437         struct mmc_command      *cmd;
438         unsigned long           flags;
439
440         spin_lock_irqsave(&host->lock, flags);
441         host->mrq = mrq;
442         cmd = mrq->cmd;
443
444         // if no card inserted, return timeout error
445         if ( readl(&host->reg->status) & MSD_CARD_DETECT ) {    // card is removed
446                 cmd->error = MMC_ERR_TIMEOUT;
447                 goto request_done;
448         }
449
450         // request include data or not
451         if ( cmd->data ) {
452                 moxasd_prepare_data(host, cmd->data);
453         }
454
455         // do request command
456         moxasd_send_command(host, cmd);
457
458         if ( cmd->data && cmd->error == MMC_ERR_NONE ) {
459                 spin_unlock_irqrestore(&host->lock, flags);
460                 return;
461         }
462
463 request_done:
464         moxasd_request_done(host);
465         spin_unlock_irqrestore(&host->lock, flags);
466 }
467
468 #define MIN_POWER       (MMC_VDD_360 - MSD_SD_POWER_MASK)
469 static void moxasd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
470 {
471         struct moxasd_host      *host=mmc_priv(mmc);
472         unsigned long           flags;
473
474         spin_lock_irqsave(&host->lock, flags);
475         if (ios->clock) {
476                 int     div;
477 #ifdef MSD_SUPPORT_GET_CLOCK
478                 div = (host->sysclk / (host->mmc->f_max * 2)) - 1;
479 #else
480                 div = (APB_CLK / (host->mmc->f_max * 2)) - 1;
481 #endif
482                 if ( div > MSD_CLK_DIV_MASK )
483                         div = MSD_CLK_DIV_MASK;
484                 else if ( div < 0 )
485                         div = 0;
486                 if ( host->mmc->mode == MMC_MODE_SD )
487                         div |= MSD_CLK_SD;
488                 writel(div, &host->reg->clock_control);
489         } else if ( !(readl(&host->reg->clock_control) & MSD_CLK_DIS) ) {
490                 /*
491                  * Ensure that the clock is off.
492                  */
493                 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
494         }
495
496         if ( ios->power_mode == MMC_POWER_OFF ) {
497                 writel(readl(&host->reg->power_control)&~MSD_SD_POWER_ON, &host->reg->power_control);
498         } else {
499                 unsigned short  power;
500                 if ( ios->vdd < MIN_POWER )
501                         power = 0;
502                 else
503                         power = ios->vdd - MIN_POWER;
504                 writel(MSD_SD_POWER_ON|(unsigned int)power, &host->reg->power_control);
505         }
506
507 #if 1
508         if ( ios->bus_width == MMC_BUS_WIDTH_1 ) {
509                 writel(MSD_SINGLE_BUS, &host->reg->bus_width);
510         } else {
511                 writel(MSD_WIDE_BUS, &host->reg->bus_width);
512         }
513 #endif
514         spin_unlock_irqrestore(&host->lock, flags);
515 }
516
517 /* 
518  * To check write protect or not. Return 0 for none, 1 for write protect.
519  */
520 static int      moxasd_get_ro(struct mmc_host *mmc)
521 {
522         struct moxasd_host      *host=mmc_priv(mmc);
523
524         if ( readl(&host->reg->status) & MSD_WRITE_PROT )
525                 return 1;
526         else
527                 return 0;
528 }
529
530 static struct mmc_host_ops moxasd_ops = {
531         .request        = moxasd_request,
532         .set_ios        = moxasd_set_ios,
533         .get_ro         = moxasd_get_ro,
534 };
535
536 static int moxasd_probe(struct device *dev)
537 {
538         struct mmc_host         *mmc;
539         struct moxasd_host      *host=NULL;
540         int                     ret;
541
542         mmc = mmc_alloc_host(sizeof(struct moxasd_host), dev);
543         if (!mmc) {
544                 ret = -ENOMEM;
545                 goto out;
546         }
547
548         mmc->ops = &moxasd_ops;
549         mmc->f_min = 400000;
550         mmc->f_max = 25000000;
551         mmc->mode = MMC_MODE_SD;
552 #if 1
553         mmc->ocr_avail = 0xffff00;      // support 2.0v - 3.6v power
554 #else
555         mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
556         mmc->caps = MMC_CAP_4_BIT_DATA;
557         mmc->max_hw_segs = 128;
558         mmc->max_phys_segs = 128;
559         mmc->max_sectors = 128;
560         mmc->max_seg_size = mmc->max_sectors * 512;
561 #endif
562
563         host = mmc_priv(mmc);
564         host->mmc = mmc;
565         spin_lock_init(&host->lock);
566         tasklet_init(&host->card_change_tasklet, moxasd_card_change, (unsigned long)host);
567         tasklet_init(&host->fifo_run_tasklet, moxasd_fifo_run, (unsigned long)host);
568         host->reg = (moxasd_reg *)CPE_SD_BASE;
569         host->dma = apb_dma_alloc(APB_DMA_SD_REQ_NO);
570         if ( host->dma ) {
571                 apb_dma_set_irq(host->dma, moxasd_dma_irq, host);
572         }
573
574 #ifdef MSD_SUPPORT_GET_CLOCK
575         // get system clock
576         {
577         unsigned int    mul, val, div;
578         mul = (*(volatile unsigned int *)(CPE_PMU_BASE+0x30) >> 3) & 0x1ff;
579         val = (*(volatile unsigned int *)(CPE_PMU_BASE+0x0c) >> 4) & 0x7;
580         switch ( val ) {
581         case 0 :        div = 2;        break;
582         case 1 :        div = 3;        break;
583         case 2 :        div = 4;        break;
584         case 3 :        div = 6;        break;
585         case 4 :        div = 8;        break;
586         default :       div = 2;        break;
587         }
588         host->sysclk = (38684*mul + 10000) / (div * 10000);
589         host->sysclk = (host->sysclk * 1000000) / 2;
590         }
591 #endif
592
593         // change I/O multiplexing to SD, so the GPIO 17-10 will be fail
594         mcpu_gpio_mp_clear(0xff<<10);
595 #ifdef CONFIG_ARCH_UC7101
596 #define SD_LED  (1<<30)
597         mcpu_gpio_mp_set(SD_LED);
598         mcpu_gpio_inout(SD_LED, MCPU_GPIO_OUTPUT);
599         mcpu_gpio_set(SD_LED, MCPU_GPIO_HIGH);
600 #endif
601
602         /*
603          * Ensure that the host controller is shut down, and setup
604          * with our defaults.
605          */
606         writel(0, &host->reg->interrupt_mask);  // disable all interrupt
607         writel(MSD_SDC_RST, &host->reg->command);       // reset chip
608         while ( readl(&host->reg->command) & MSD_SDC_RST);      // wait for reset finished
609         writel(0, &host->reg->interrupt_mask);  // disable all interrupt
610
611         // to check any card inserted or not
612         if ( !(readl(&host->reg->status) & MSD_CARD_DETECT) ) { // is inserted
613                 if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) {  // is SD card
614                         mmc->f_max = 25000000;
615                         mmc->mode = MMC_MODE_SD;
616                 } else {        // is MMC card
617                         mmc->f_max = 20000000;
618                         mmc->mode = MMC_MODE_MMC;
619                 }
620         }
621
622         mmc->caps = MMC_CAP_4_BIT_DATA;
623         writel(MSD_WIDE_BUS, &host->reg->bus_width);
624
625         cpe_int_set_irq(IRQ_SD, EDGE, H_ACTIVE);
626         ret = request_irq(IRQ_SD, moxasd_irq, SA_INTERRUPT, "MOXASD", host);
627         if (ret)
628                 goto out;
629
630         //writel(MSD_INT_CARD_CHANGE|MSD_INT_FIFO_ORUN|MSD_INT_FIFO_URUN, &host->reg->interrupt_mask);
631         writel(MSD_INT_CARD_CHANGE, &host->reg->interrupt_mask);
632         dev_set_drvdata(dev, mmc);
633         mmc_add_host(mmc);
634
635         return 0;
636
637  out:
638         if (mmc)
639                 mmc_free_host(mmc);
640
641         return ret;
642 }
643
644 static int moxasd_remove(struct device *dev)
645 {
646         struct mmc_host *mmc=dev_get_drvdata(dev);
647
648         dev_set_drvdata(dev, NULL);
649
650         if (mmc) {
651                 struct moxasd_host      *host=mmc_priv(mmc);
652
653                 mmc_remove_host(mmc);
654
655                 // stop SD/MMC
656                 if ( host->dma ) {
657                         apb_dma_disable(host->dma);
658                         apb_dma_release_irq(host->dma);
659                         apb_dma_release(host->dma);
660                 }
661                 writel(0, &host->reg->interrupt_mask);
662                 writel(0, &host->reg->power_control);
663                 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
664
665                 free_irq(IRQ_SD, host);
666                 tasklet_kill(&host->card_change_tasklet);
667                 tasklet_kill(&host->fifo_run_tasklet);
668
669                 mmc_free_host(mmc);
670         }
671         return 0;
672 }
673
674 static struct platform_device moxasd_device = {
675         .name   = "moxart-sd",
676         .id     = -1,
677 };
678
679 static struct device_driver moxasd_driver = {
680         .name           = "moxart-sd",
681         .bus            = &platform_bus_type,
682         .probe          = moxasd_probe,
683         .remove         = moxasd_remove,
684 };
685
686 #if 1   // add by Victor Yu. 03-08-2007
687 extern int      moxa_gpio_sd_used_flag; // define on arch/arm/kernel/armksyms.c
688 #endif
689 static int __init moxasd_init(void)
690 {
691         int     ret;
692
693         printk("Moxa CPU SD/MMC Device Driver V1.0 initialize ");
694 #if 1   // add by Victor Yu. 03-08-2007
695         {
696         unsigned long   flags;
697         local_irq_save(flags);
698         if ( moxa_gpio_sd_used_flag ) {
699                 printk("The IO has used by other device driver !\n");
700                 local_irq_restore(flags);
701                 return -ENODEV;
702         }
703         moxa_gpio_sd_used_flag = 1;
704         local_irq_restore(flags);
705         }
706 #endif
707         platform_device_register(&moxasd_device);
708         ret = driver_register(&moxasd_driver);
709         if ( ret ) {
710                 printk("Modules load fail !\n");
711                 platform_device_unregister(&moxasd_device);
712         } else {
713                 printk("Modules load OK.\n");
714         }
715         return ret;
716 }
717
718 static void __exit moxasd_exit(void)
719 {
720         platform_device_unregister(&moxasd_device);
721         driver_unregister(&moxasd_driver);
722 #if 1   // add by Victor Yu. 12-05-2007
723         {
724         unsigned long   flags;
725         local_irq_save(flags);
726         moxa_gpio_sd_used_flag = 0;
727         local_irq_restore(flags);
728         }
729 #endif
730 }
731
732 module_init(moxasd_init);
733 module_exit(moxasd_exit);
734
735 MODULE_DESCRIPTION("Moxa CPU SD/Multimedia Card Interface Driver");
736 MODULE_LICENSE("GPL");