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-bak-12022005
blob530b0f4dd974a9a9eb0bdebda0c37d53b1ff5698
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/moxa.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/mmc/protocol.h>
25 #include <asm/dma.h>
26 #include <asm/io.h>
27 #include <asm/irq.h>
28 #include <asm/sizes.h>
30 #include "moxasd.h"
32 #define MSD_RETRY_COUNT         10000
33 //#define CONFIG_MMC_DEBUG
34 #ifdef CONFIG_MMC_DEBUG
35 #define DBG(x...)       printk(x)
36 #else
37 #define DBG(x...)
38 #endif
40 struct moxasd_host {
41         struct mmc_host         *mmc;
42         spinlock_t              lock;
43         moxasd_reg              *reg;
44 #ifdef MSD_SUPPORT_GET_CLOCK
45         unsigned int            sysclk;
46 #endif
47         struct mmc_request      *mrq;
48         struct mmc_data         *data;
50         struct scatterlist      *cur_sg;        /* Current SG entry */
51         unsigned int            num_sg;         /* Number of entries left */
52         void                    *mapped_sg;     /* vaddr of mapped sg */
53         unsigned int            offset;         /* Offset into current entry */
54         unsigned int            remain;         /* Data left in curren entry */
55         int                     size;           /* Total size of transfer */
57         struct tasklet_struct   card_change_tasklet;
58         struct tasklet_struct   fifo_run_tasklet;
61 static inline void moxasd_init_sg(struct moxasd_host* host, struct mmc_data* data)
63         /*
64          * Get info. about SG list from data structure.
65          */
66         host->cur_sg = data->sg;
67         host->num_sg = data->sg_len;
69         host->offset = 0;
70         host->remain = host->cur_sg->length;
73 static inline int moxasd_next_sg(struct moxasd_host* host)
75         /*
76          * Skip to next SG entry.
77          */
78         host->cur_sg++;
79         host->num_sg--;
81         /*
82          * Any entries left?
83          */
84         if (host->num_sg > 0) {
85                 host->offset = 0;
86                 host->remain = host->cur_sg->length;
87         }
89         return host->num_sg;
92 static inline char *moxasd_kmap_sg(struct moxasd_host* host)
94         host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
95                 host->cur_sg->offset;
96         return host->mapped_sg;
99 static inline void moxasd_check_data_crc(struct moxasd_host *host, struct mmc_data *data)
101         unsigned int    status;
103         status = readl(&host->reg->status);
104         if ( status & MSD_DATA_CRC_OK ) {
105                 writel(MSD_CLR_DATA_CRC_OK, &host->reg->clear);
106         }
107         if ( status & MSD_DATA_CRC_FAIL ) {
108                 writel(MSD_CLR_DATA_CRC_FAIL, &host->reg->clear);
109                 data->error = MMC_ERR_TIMEOUT;
110                 DBG("moxasd_check_data_crc data CRC fail !\n");
111         }
112         if ( status & MSD_DATA_END ) {
113                 writel(MSD_CLR_DATA_END, &host->reg->clear);
114         }
117 static inline int moxasd_wait_fifo_ready(struct moxasd_host *host, unsigned int flags)
119         unsigned int    status;
120         int             retry=0;
122         while ( retry++ < MSD_RETRY_COUNT ) {
123                 status = readl(&host->reg->status);
124                 if ( status & MSD_CARD_DETECT ) {       // card is removed
125                         DBG("moxasd_wait_fifo_ready card is removed !\n");
126                         return 0;
127                 }
128                 if ( flags & MMC_DATA_WRITE ) {
129                         if ( status & MSD_FIFO_URUN ) {
130                                 writel(MSD_CLR_FIFO_URUN, &host->reg->clear);
131                                 return 1;
132                         }
133                 } else {
134                         if ( status & MSD_FIFO_ORUN ) {
135                                 writel(MSD_CLR_FIFO_ORUN, &host->reg->clear);
136                                 return 1;
137                         }
138                 }
139                 if ( status & MSD_DATA_TIMEOUT ) {
140                         writel(MSD_CLR_DATA_TIMEOUT, &host->reg->clear);
141                         DBG("moxasd_wait_fifo_ready data timeout error !\n");
142                         return 0;
143                 }
144         }
146         return 0;
149 static void     moxasd_do_fifo(struct moxasd_host *host, struct mmc_data *data)
151         char    *buffer;
152         int     wcnt, i;
154         if ( !moxasd_wait_fifo_ready(host, data->flags) ) {     // FIFO fail
155                 data->error = MMC_ERR_TIMEOUT;
156                 host->size = data->bytes_xfered;
157                 return;
158         }
159         buffer = moxasd_kmap_sg(host) + host->offset;
160         if ( host->remain >= MSD_FIFO_LENB )
161                 wcnt = MSD_FIFO_LENW;
162         else
163                 wcnt = host->remain >> 2;
164         if ( data->flags & MMC_DATA_WRITE ) {
165                 for ( i=0; i<wcnt; i++, buffer+=4 )
166                         writel(*(unsigned int *)buffer, &host->reg->data_window);
167         } else {
168                 for ( i=0; i<wcnt; i++, buffer+=4 )
169                         *(unsigned int *)buffer = readl(&host->reg->data_window);
170         }
171         wcnt <<= 2;
172         host->offset += wcnt;
173         host->remain -= wcnt;
174         data->bytes_xfered += wcnt;
175         kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
176         if ( host->remain <= 0 ) {
177                 if ( !moxasd_next_sg(host) ) {
178                         host->size = data->bytes_xfered;
179                         data->error = MMC_ERR_NONE;
180                 }
181         }
184 static void moxasd_request_done(struct moxasd_host *host)
186         struct mmc_request      *mrq=host->mrq;
188         spin_lock_bh(&host->lock);
189         if ( mrq == NULL ) {
190                 spin_unlock_bh(&host->lock);
191                 return;
192         }
193         host->mrq = NULL;
194         host->data = NULL;
195         mmc_request_done(host->mmc, mrq);
196         spin_unlock_bh(&host->lock);
199 static void moxasd_prepare_data(struct moxasd_host *host, struct mmc_data *data)
201         unsigned int    timeout, datactrl;
203         host->data = data;
205         // initialize the timeout value
206         timeout = (host->mmc->f_max/1000000) * (data->timeout_ns/1000);
207         timeout += data->timeout_clks;
208         writel(timeout, &host->reg->data_timer);
210         // initialize the data size
211         host->size = data->blocks << data->blksz_bits;
212         writel(host->size, &host->reg->data_length);
214         // initialize the data control
215         datactrl = data->blksz_bits & MSD_BLK_SIZE_MASK;
216         if ( data->flags & MMC_DATA_WRITE ) {
217                 datactrl |= MSD_DATA_WRITE;
218         }
219 #ifdef MSD_SUPPORT_DMA
220         datactrl |= MSD_DMA_EN;
221 #endif
222         datactrl |= MSD_DATA_EN;
223         writel(datactrl, &host->reg->data_control);
224         moxasd_init_sg(host, data);
227 static void moxasd_send_command(struct moxasd_host *host, struct mmc_command *cmd)
229         unsigned int    status, cmdctrl;
230         int             retry=0;
232         // first clear status
233         writel(MSD_CLR_RSP_TIMEOUT|MSD_CLR_RSP_CRC_OK|MSD_CLR_RSP_CRC_FAIL|MSD_CLR_CMD_SENT, &host->reg->clear);
235         // write argument
236         writel(cmd->arg, &host->reg->argument);
238         // write command
239         cmdctrl = cmd->opcode & MSD_CMD_IDX_MASK;
240         if ( cmdctrl == SD_APP_SET_BUS_WIDTH ||
241              cmdctrl == SD_APP_OP_COND ||
242              cmdctrl == SD_APP_SEND_SCR )       // this is SD application specific command
243                 cmdctrl |= MSD_APP_CMD;
244         if ( cmd->flags & MMC_RSP_LONG )
245                 cmdctrl |= (MSD_LONG_RSP|MSD_NEED_RSP);
246         if ( cmd->flags & MMC_RSP_SHORT )
247                 cmdctrl |= MSD_NEED_RSP;
248         writel(cmdctrl|MSD_CMD_EN, &host->reg->command);
250         // wait response
251         while ( retry++ < MSD_RETRY_COUNT ) {
252                 status = readl(&host->reg->status);
253                 if ( status & MSD_CARD_DETECT ) {
254                         DBG("moxasd_send_command error for card reomved\n");
255                         cmd->error = MMC_ERR_TIMEOUT;
256                         return;
257                 }
258                 if ( cmdctrl & MSD_NEED_RSP ) {
259                         if ( status & MSD_RSP_TIMEOUT ) {
260                                 writel(MSD_CLR_RSP_TIMEOUT, &host->reg->clear);
261                                 DBG("moxasd_send_command rsp timeout error !\n");
262                                 cmd->error = MMC_ERR_TIMEOUT;
263                                 return;
264                         }
265 #if 0
266                         if ( status & MSD_RSP_CRC_FAIL ) {
267 #else
268                         if ( (cmd->flags&MMC_RSP_CRC) && (status&MSD_RSP_CRC_FAIL) ) {
269 #endif
270                                 writel(MSD_CLR_RSP_CRC_FAIL, &host->reg->clear);
271                                 DBG("moxasd_send_command rsp CRC fail error !\n");
272                                 cmd->error = MMC_ERR_BADCRC;
273                                 return;
274                         }
275                         if ( status & MSD_RSP_CRC_OK ) {
276                                 writel(MSD_CLR_RSP_CRC_OK, &host->reg->clear);
277                                 // read response
278                                 cmd->resp[0] = readl(&host->reg->response0);
279                                 cmd->resp[1] = readl(&host->reg->response1);
280                                 cmd->resp[2] = readl(&host->reg->response2);
281                                 cmd->resp[3] = readl(&host->reg->response3);
282                                 cmd->error = MMC_ERR_NONE;
283                                 return;
284                         }
285                 } else {
286                         if ( status & MSD_CMD_SENT ) {
287                                 writel(MSD_CLR_CMD_SENT, &host->reg->clear);
288                                 cmd->error = MMC_ERR_NONE;
289                                 return;
290                         }
291                 }
292         }
293         cmd->error = MMC_ERR_TIMEOUT;
296 static irqreturn_t moxasd_irq(int irq, void *devid, struct pt_regs *regs)
298         struct moxasd_host      *host=devid;
299         unsigned int            status;
301         status = readl(&host->reg->status);
302         if ( status & MSD_CARD_CHANGE ) {       // has card inserted or removed
303                 tasklet_schedule(&host->card_change_tasklet);
304         }
305         if ( status & (MSD_FIFO_ORUN|MSD_FIFO_URUN) ) {
306                 DBG("moxasd_irq FIFO\n");
307                 tasklet_schedule(&host->fifo_run_tasklet);
308         }
310         return IRQ_HANDLED;
313 static void card_change(unsigned long param)
315         struct moxasd_host      *host=(struct moxasd_host *)param;
316         unsigned int            status;
317         int                     delay;
319         status = readl(&host->reg->status);
320         if ( status & MSD_CARD_DETECT ) {       // card inserted
321                 if ( host->reg->clock_control & MSD_CLK_SD ) {  // SD
322                         host->mmc->f_max = 25000000;
323                         host->mmc->mode = MMC_MODE_SD;
324                 } else {
325                         host->mmc->f_max = 20000000;
326                         host->mmc->mode = MMC_MODE_MMC;
327                 }
328                 delay = 500;
329         } else {        // card remove
330                 delay = 0;
331         }
333         // clear the status
334         writel(MSD_CLR_CARD_CHANGE, &host->reg->clear);
336         mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
339 static void fifo_run(unsigned long param)
341         struct moxasd_host      *host=(struct moxasd_host *)param;
342         struct mmc_data         *data;
344         //spin_lock_bh(&host->lock);
345         if ( host->mrq == NULL ) {
346                 //spin_unlock_bh(&host->lock);
347                 return;
348         }
349         if ( host->data == NULL ) {
350                 goto fifo_run_done;
351         }
352         data = host->data;
353         moxasd_do_fifo(host, data);
354         if ( host->size == data->bytes_xfered ) {
355                 // maybe need to check the data is OK or fail
356                 if ( data->error == MMC_ERR_NONE ) {
357                         moxasd_check_data_crc(host, data);
358                 }
359                 if ( data->stop ) {
360                         moxasd_send_command(host, data->stop);
361                 }
362                 DBG("moxasd_fifo_run finished data read/write\n");
363         } else {
364                 tasklet_schedule(&host->fifo_run_tasklet);
365                 //spin_unlock_bh(&host->lock);
366                 return;
367         }
368         
369 fifo_run_done:
370         //spin_unlock_bh(&host->lock);
371         moxasd_request_done(host);
374 static void moxasd_request(struct mmc_host *mmc, struct mmc_request *mrq)
376         struct moxasd_host      *host=mmc_priv(mmc);
377         struct mmc_command      *cmd;
379         spin_lock_bh(&host->lock);
380         host->mrq = mrq;
381         cmd = mrq->cmd;
383         // if no card inserted, return timeout error
384         if ( readl(&host->reg->status) & MSD_CARD_DETECT ) {
385                 cmd->error = MMC_ERR_TIMEOUT;
386                 goto request_done;
387         }
389         // request include data or not
390         if ( cmd->data ) {
391                 moxasd_prepare_data(host, cmd->data);
392         }
394         // do request command
395         moxasd_send_command(host, cmd);
397         if ( cmd->data && cmd->error == MMC_ERR_NONE ) {
398                 //tasklet_schedule(&host->fifo_run_tasklet);
399                 spin_unlock_bh(&host->lock);
400                 return;
401         }
403 request_done:
404         spin_unlock_bh(&host->lock);
405         moxasd_request_done(host);
408 #define MIN_POWER       (MMC_VDD_360 - MSD_SD_POWER_MASK)
409 static void moxasd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
411         struct moxasd_host      *host=mmc_priv(mmc);
413         spin_lock_bh(&host->lock);
414         if (ios->clock) {
415                 int     div;
416 #ifdef MSD_SUPPORT_GET_CLOCK
417                 div = (host->sysclk / (host->mmc->f_max * 2)) - 1;
418 #else
419                 div = (APB_CLK / (host->mmc->f_max * 2)) - 1;
420 #endif
421                 if ( div > MSD_CLK_DIV_MASK )
422                         div = MSD_CLK_DIV_MASK;
423                 else if ( div < 0 )
424                         div = 0;
425                 if ( host->mmc->mode == MMC_MODE_SD )
426                         div |= MSD_CLK_SD;
427                 writel(div, &host->reg->clock_control);
428         } else if ( !(readl(&host->reg->clock_control) & MSD_CLK_DIS) ) {
429                 /*
430                  * Ensure that the clock is off.
431                  */
432                 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
433         }
435         if ( ios->power_mode == MMC_POWER_OFF ) {
436                 writel(readl(&host->reg->power_control)&~MSD_SD_POWER_ON, &host->reg->power_control);
437         } else {
438                 unsigned short  power;
439                 if ( ios->vdd < MIN_POWER )
440                         power = 0;
441                 else
442                         power = ios->vdd - MIN_POWER;
443                 writel(MSD_SD_POWER_ON|(unsigned int)power, &host->reg->power_control);
444         }
446 #if 1
447         if ( ios->bus_width == MMC_BUS_WIDTH_1 ) {
448                 writel(MSD_SINGLE_BUS, &host->reg->bus_width);
449         } else {
450                 writel(MSD_WIDE_BUS, &host->reg->bus_width);
451         }
452 #endif
453         spin_unlock_bh(&host->lock);
456 /* 
457  * To check write protect or not. Return 0 for none, 1 for write protect.
458  */
459 static int      moxasd_get_ro(struct mmc_host *mmc)
461         struct moxasd_host      *host=mmc_priv(mmc);
463         if ( readl(&host->reg->status) & MSD_WRITE_PROT )
464                 return 1;
465         else
466                 return 0;
469 static struct mmc_host_ops moxasd_ops = {
470         .request        = moxasd_request,
471         .set_ios        = moxasd_set_ios,
472         .get_ro         = moxasd_get_ro,
475 static int moxasd_probe(struct device *dev)
477         struct mmc_host         *mmc;
478         struct moxasd_host      *host=NULL;
479         int                     ret;
481         mmc = mmc_alloc_host(sizeof(struct moxasd_host), dev);
482         if (!mmc) {
483                 ret = -ENOMEM;
484                 goto out;
485         }
487         mmc->ops = &moxasd_ops;
488         mmc->f_min = 400000;
489         mmc->f_max = 25000000;
490         mmc->mode = MMC_MODE_SD;
491 #if 1
492         mmc->ocr_avail = 0xffff00;      // support 2.0v - 3.6v power
493 #else
494         mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
495         mmc->caps = MMC_CAP_4_BIT_DATA;
496         mmc->max_hw_segs = 128;
497         mmc->max_phys_segs = 128;
498         mmc->max_sectors = 128;
499         mmc->max_seg_size = mmc->max_sectors * 512;
500 #endif
502         host = mmc_priv(mmc);
503         host->mmc = mmc;
504         spin_lock_init(&host->lock);
505         tasklet_init(&host->card_change_tasklet, card_change, (unsigned long)host);
506         tasklet_init(&host->fifo_run_tasklet, fifo_run, (unsigned long)host);
507         host->reg = (moxasd_reg *)CPE_SD_BASE;
509 #ifdef MSD_SUPPORT_GET_CLOCK
510         // get system clock
511         {
512         unsigned int    mul, val, div;
513         mul = (*(volatile unsigned int *)(CPE_PMU_BASE+0x30) >> 3) & 0x1ff;
514         val = (*(volatile unsigned int *)(CPE_PMU_BASE+0x0c) >> 4) & 0x7;
515         switch ( val ) {
516         case 0 :        div = 2;        break;
517         case 1 :        div = 3;        break;
518         case 2 :        div = 4;        break;
519         case 3 :        div = 6;        break;
520         case 4 :        div = 8;        break;
521         default :       div = 2;        break;
522         }
523         host->sysclk = (38684*mul + 10000) / (div * 10000);
524         host->sysclk = (host->sysclk * 1000000) / 2;
525         }
526 #endif
528         // change I/O multiplexing to SD, so the GPIO 17-10 will be fail
529         *(volatile unsigned int *)(CPE_PMU_BASE+0x100) &= (~(0xff<<10));
531         /*
532          * Ensure that the host controller is shut down, and setup
533          * with our defaults.
534          */
535         writel(0, &host->reg->interrupt_mask);  // disable all interrupt
536         writel(MSD_SDC_RST, &host->reg->command);       // reset chip
537         while ( readl(&host->reg->command) & MSD_SDC_RST);      // wait for reset finished
538         writel(0, &host->reg->interrupt_mask);  // disable all interrupt
540         // to check any card inserted or not
541         if ( !(readl(&host->reg->status) & MSD_CARD_DETECT) ) { // is inserted
542                 if ( readl(&host->reg->clock_control) & MSD_CLK_SD ) {  // is SD card
543                         mmc->f_max = 25000000;
544                         mmc->mode = MMC_MODE_SD;
545                 } else {        // is MMC card
546                         mmc->f_max = 20000000;
547                         mmc->mode = MMC_MODE_MMC;
548                 }
549         }
551         mmc->caps = MMC_CAP_4_BIT_DATA;
552         writel(MSD_WIDE_BUS, &host->reg->bus_width);
554         cpe_int_set_irq(IRQ_SD, EDGE, H_ACTIVE);
555         ret = request_irq(IRQ_SD, moxasd_irq, SA_INTERRUPT, "MOXASD", host);
556         if (ret)
557                 goto out;
559         writel(MSD_INT_CARD_CHANGE|MSD_INT_FIFO_ORUN|MSD_INT_FIFO_URUN, &host->reg->interrupt_mask);
560         dev_set_drvdata(dev, mmc);
561         mmc_add_host(mmc);
563         return 0;
565  out:
566         if (mmc)
567                 mmc_free_host(mmc);
569         return ret;
572 static int moxasd_remove(struct device *dev)
574         struct mmc_host *mmc=dev_get_drvdata(dev);
576         dev_set_drvdata(dev, NULL);
578         if (mmc) {
579                 struct moxasd_host      *host=mmc_priv(mmc);
581                 mmc_remove_host(mmc);
583                 // stop SD/MMC
584                 writel(0, &host->reg->interrupt_mask);
585                 writel(0, &host->reg->power_control);
586                 writel(readl(&host->reg->clock_control)|MSD_CLK_DIS, &host->reg->clock_control);
588                 free_irq(IRQ_SD, host);
589                 tasklet_kill(&host->card_change_tasklet);
590                 tasklet_kill(&host->fifo_run_tasklet);
592                 mmc_free_host(mmc);
593         }
594         return 0;
597 static struct platform_device moxasd_device = {
598         .name   = "moxart-sd",
599         .id     = -1,
602 static struct device_driver moxasd_driver = {
603         .name           = "moxart-sd",
604         .bus            = &platform_bus_type,
605         .probe          = moxasd_probe,
606         .remove         = moxasd_remove,
609 static int __init moxasd_init(void)
611         printk("Moxa CPU SD/MMC Device Driver V1.0 initialize.\n");
612         platform_device_register(&moxasd_device);
613         return driver_register(&moxasd_driver);
616 static void __exit moxasd_exit(void)
618         platform_device_unregister(&moxasd_device);
619         driver_unregister(&moxasd_driver);
622 module_init(moxasd_init);
623 module_exit(moxasd_exit);
625 MODULE_DESCRIPTION("Moxa CPU SD/Multimedia Card Interface Driver");
626 MODULE_LICENSE("GPL");