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