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