sync hh.org
[hh.org.git] / drivers / mmc / s3c2410mci.c
blobc65386f148a52770c3b8f87336ef05c76e8bc03b
1 /*
2 * linux/drivers/mmc/s3c2410mci.h - Samsung S3C2410 SDI Interface driver
4 * Copyright (C) 2004 Thomas Kleffel, 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.
9 */
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
12 #include <linux/init.h>
13 #include <linux/ioport.h>
14 #include <linux/device.h>
15 #include <linux/interrupt.h>
16 #include <linux/blkdev.h>
17 #include <linux/delay.h>
18 #include <linux/err.h>
19 #include <linux/dma-mapping.h>
20 #include <linux/mmc/host.h>
21 #include <linux/mmc/protocol.h>
23 #include <asm/dma.h>
24 #include <asm/dma-mapping.h>
25 #include <asm/arch/dma.h>
27 #include <asm/io.h>
28 #include <asm/irq.h>
29 #include <asm/hardware/amba.h>
30 #include <asm/hardware/clock.h>
31 #include <asm/mach/mmc.h>
33 #include <asm/arch/regs-sdi.h>
34 #include <asm/arch/regs-gpio.h>
36 //#define S3C2410SDI_DMA_BACKBUF
38 #ifdef CONFIG_MMC_DEBUG
39 #define DBG(x...) printk(KERN_DEBUG x)
40 #else
41 #define DBG(x...) do { } while (0)
42 #endif
44 #include "s3c2410mci.h"
46 #define DRIVER_NAME "mmci-s3c2410"
47 #define PFX DRIVER_NAME ": "
49 #define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
51 // #define KERN_DEBUG KERN_INFO
53 typedef enum {
54 DMAP_READ,
55 DMAP_WRITE,
56 } eDMAPurpose_t;
58 static struct s3c2410_dma_client s3c2410sdi_dma_client = {
59 .name = "s3c2410-sdi",
65 * ISR for SDI Interface IRQ
66 * Communication between driver and ISR works as follows:
67 * host->mrq points to current request
68 * host->complete_what tells the ISR when the request is considered done
69 * COMPLETION_CMDSENT when the command was sent
70 * COMPLETION_RSPFIN when a response was received
71 * COMPLETION_XFERFINISH when the data transfer is finished
72 * COMPLETION_XFERFINISH_RSPFIN both of the above.
73 * host->complete_request is the completion-object the driver waits for
75 * 1) Driver sets up host->mrq and host->complete_what
76 * 2) Driver prepares the transfer
77 * 3) Driver enables interrupts
78 * 4) Driver starts transfer
79 * 5) Driver waits for host->complete_rquest
80 * 6) ISR checks for request status (errors and success)
81 * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error
82 * 7) ISR completes host->complete_request
83 * 8) ISR disables interrupts
84 * 9) Driver wakes up and takes care of the request
87 static irqreturn_t s3c2410sdi_irq(int irq, void *dev_id, struct pt_regs *regs)
89 struct s3c2410sdi_host *host;
90 u32 sdi_csta, sdi_dsta, sdi_dcnt;
91 u32 sdi_cclear, sdi_dclear;
92 unsigned long iflags;
94 host = (struct s3c2410sdi_host *)dev_id;
96 //Check for things not supposed to happen
97 if(!host) return IRQ_HANDLED;
99 sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);
100 sdi_dsta = readl(host->base + S3C2410_SDIDSTA);
101 sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);
103 DBG(PFX "IRQ csta=0x%08x dsta=0x%08x dcnt:0x%08x\n", sdi_csta, sdi_dsta, sdi_dcnt);
105 spin_lock_irqsave( &host->complete_lock, iflags);
107 if( host->complete_what==COMPLETION_NONE ) {
108 goto clear_imask;
111 if(!host->mrq) {
112 goto clear_imask;
116 sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);
117 sdi_dsta = readl(host->base + S3C2410_SDIDSTA);
118 sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);
119 sdi_cclear = 0;
120 sdi_dclear = 0;
123 if(sdi_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
124 host->mrq->cmd->error = MMC_ERR_TIMEOUT;
125 goto transfer_closed;
128 if(sdi_csta & S3C2410_SDICMDSTAT_CMDSENT) {
129 if(host->complete_what == COMPLETION_CMDSENT) {
130 host->mrq->cmd->error = MMC_ERR_NONE;
131 goto transfer_closed;
134 sdi_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
137 if(sdi_csta & S3C2410_SDICMDSTAT_CRCFAIL) {
138 if(host->mrq->cmd->flags & MMC_RSP_CRC) {
139 host->mrq->cmd->error = MMC_ERR_BADCRC;
140 goto transfer_closed;
143 sdi_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;
146 if(sdi_csta & S3C2410_SDICMDSTAT_RSPFIN) {
147 if(host->complete_what == COMPLETION_RSPFIN) {
148 host->mrq->cmd->error = MMC_ERR_NONE;
149 goto transfer_closed;
152 if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {
153 host->mrq->cmd->error = MMC_ERR_NONE;
154 host->complete_what = COMPLETION_XFERFINISH;
157 sdi_cclear |= S3C2410_SDICMDSTAT_RSPFIN;
160 if(sdi_dsta & S3C2410_SDIDSTA_FIFOFAIL) {
161 host->mrq->cmd->error = MMC_ERR_NONE;
162 host->mrq->data->error = MMC_ERR_FIFO;
163 goto transfer_closed;
166 if(sdi_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {
167 host->mrq->cmd->error = MMC_ERR_NONE;
168 host->mrq->data->error = MMC_ERR_BADCRC;
169 goto transfer_closed;
172 if(sdi_dsta & S3C2410_SDIDSTA_CRCFAIL) {
173 host->mrq->cmd->error = MMC_ERR_NONE;
174 host->mrq->data->error = MMC_ERR_BADCRC;
175 goto transfer_closed;
178 if(sdi_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {
179 host->mrq->cmd->error = MMC_ERR_NONE;
180 host->mrq->data->error = MMC_ERR_TIMEOUT;
181 goto transfer_closed;
184 if(sdi_dsta & S3C2410_SDIDSTA_XFERFINISH) {
185 if(host->complete_what == COMPLETION_XFERFINISH) {
186 host->mrq->cmd->error = MMC_ERR_NONE;
187 host->mrq->data->error = MMC_ERR_NONE;
188 goto transfer_closed;
191 if(host->complete_what == COMPLETION_XFERFINISH_RSPFIN) {
192 host->mrq->data->error = MMC_ERR_NONE;
193 host->complete_what = COMPLETION_RSPFIN;
196 sdi_dclear |= S3C2410_SDIDSTA_XFERFINISH;
199 writel(sdi_cclear, host->base + S3C2410_SDICMDSTAT);
200 writel(sdi_dclear, host->base + S3C2410_SDIDSTA);
202 spin_unlock_irqrestore( &host->complete_lock, iflags);
203 DBG(PFX "IRQ still waiting.\n");
204 return IRQ_HANDLED;
207 transfer_closed:
208 host->complete_what = COMPLETION_NONE;
209 complete(&host->complete_request);
210 writel(0, host->base + S3C2410_SDIIMSK);
211 spin_unlock_irqrestore( &host->complete_lock, iflags);
212 DBG(PFX "IRQ transfer closed.\n");
213 return IRQ_HANDLED;
215 clear_imask:
216 regular_clear_imask:
217 writel(0, host->base + S3C2410_SDIIMSK);
218 spin_unlock_irqrestore( &host->complete_lock, iflags);
219 DBG(PFX "IRQ clear imask.\n");
220 return IRQ_HANDLED;
226 * ISR for the CardDetect Pin
229 static irqreturn_t s3c2410sdi_irq_cd(int irq, void *dev_id, struct pt_regs *regs)
231 struct s3c2410sdi_host *host = (struct s3c2410sdi_host *)dev_id;
232 mmc_detect_change(host->mmc);
234 return IRQ_HANDLED;
239 void s3c2410sdi_dma_done_callback(s3c2410_dma_chan_t *dma_ch, void *buf_id,
240 int size, s3c2410_dma_buffresult_t result)
241 { unsigned long iflags;
242 u32 sdi_csta, sdi_dsta,sdi_dcnt;
243 struct s3c2410sdi_host *host = (struct s3c2410sdi_host *)buf_id;
245 sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);
246 sdi_dsta = readl(host->base + S3C2410_SDIDSTA);
247 sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);
249 DBG(PFX "DMAD csta=0x%08x dsta=0x%08x dcnt:0x%08x result:0x%08x\n", sdi_csta, sdi_dsta, sdi_dcnt, result);
251 spin_lock_irqsave( &host->complete_lock, iflags);
253 if(!host->mrq) goto out;
254 if(!host->mrq->data) goto out;
257 sdi_csta = readl(host->base + S3C2410_SDICMDSTAT);
258 sdi_dsta = readl(host->base + S3C2410_SDIDSTA);
259 sdi_dcnt = readl(host->base + S3C2410_SDIDCNT);
261 if( result!=S3C2410_RES_OK ) {
262 goto fail_request;
266 if(host->mrq->data->flags & MMC_DATA_READ) {
267 if( sdi_dcnt>0 ) {
268 goto fail_request;
272 out:
273 complete(&host->complete_dma);
274 spin_unlock_irqrestore( &host->complete_lock, iflags);
275 return;
278 fail_request:
279 host->mrq->data->error = MMC_ERR_DMA;
280 host->complete_what = COMPLETION_NONE;
281 complete(&host->complete_dma);
282 complete(&host->complete_request);
283 writel(0, host->base + S3C2410_SDIIMSK);
284 goto out;
289 void s3c2410sdi_dma_setup(struct s3c2410sdi_host *host, eDMAPurpose_t purpose) {
290 s3c2410_dmasrc_t source;
292 switch(purpose) {
293 case DMAP_READ:
294 source = S3C2410_DMASRC_HW;
295 break;
297 case DMAP_WRITE:
298 source = S3C2410_DMASRC_MEM;
299 break;
302 s3c2410_dma_devconfig(host->dma, source, 3, host->mem->start + S3C2410_SDIDATA);
303 s3c2410_dma_config(host->dma, 4, (1<<23) | (2<<24));
304 s3c2410_dma_set_buffdone_fn(host->dma, s3c2410sdi_dma_done_callback);
305 s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
308 static void s3c2410sdi_request(struct mmc_host *mmc, struct mmc_request *mrq) {
309 struct s3c2410sdi_host *host = mmc_priv(mmc);
310 u32 sdi_carg, sdi_ccon, sdi_timer;
311 u32 sdi_bsize, sdi_dcon, sdi_imsk;
313 DBG(KERN_DEBUG PFX "request: [CMD] opcode:0x%02x arg:0x%08x flags:%x retries:%u\n",
314 mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags, mrq->cmd->retries);
317 sdi_ccon = mrq->cmd->opcode & S3C2410_SDICMDCON_INDEX;
318 sdi_ccon|= S3C2410_SDICMDCON_SENDERHOST;
319 sdi_ccon|= S3C2410_SDICMDCON_CMDSTART;
321 sdi_carg = mrq->cmd->arg;
323 //FIXME: Timer value ?!
324 sdi_timer= 0xF000;
326 sdi_bsize= 0;
327 sdi_dcon = 0;
328 sdi_imsk = 0;
330 //enable interrupts for transmission errors
331 sdi_imsk |= S3C2410_SDIIMSK_RESPONSEND;
332 sdi_imsk |= S3C2410_SDIIMSK_CRCSTATUS;
335 host->complete_what = COMPLETION_CMDSENT;
337 if (mrq->cmd->flags & MMC_RSP_MASK) {
338 host->complete_what = COMPLETION_RSPFIN;
340 sdi_ccon |= S3C2410_SDICMDCON_WAITRSP;
341 sdi_imsk |= S3C2410_SDIIMSK_CMDTIMEOUT;
343 } else {
344 //We need the CMDSENT-Interrupt only if we want are not waiting
345 //for a response
346 sdi_imsk |= S3C2410_SDIIMSK_CMDSENT;
349 if(mrq->cmd->flags & MMC_RSP_LONG) {
350 sdi_ccon|= S3C2410_SDICMDCON_LONGRSP;
353 if(mrq->cmd->flags & MMC_RSP_CRC) {
354 sdi_imsk |= S3C2410_SDIIMSK_RESPONSECRC;
358 if (mrq->data) {
359 host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
363 sdi_bsize = (1 << mrq->data->blksz_bits);
365 sdi_dcon = (mrq->data->blocks & S3C2410_SDIDCON_BLKNUM_MASK);
366 sdi_dcon |= S3C2410_SDIDCON_DMAEN;
368 sdi_imsk |= S3C2410_SDIIMSK_FIFOFAIL;
369 sdi_imsk |= S3C2410_SDIIMSK_DATACRC;
370 sdi_imsk |= S3C2410_SDIIMSK_DATATIMEOUT;
371 sdi_imsk |= S3C2410_SDIIMSK_DATAFINISH;
372 sdi_imsk |= 0xFFFFFFE0;
374 DBG(PFX "request: [DAT] bsize:%u blocks:%u bytes:%u\n",
375 sdi_bsize, mrq->data->blocks, mrq->data->blocks * sdi_bsize);
377 if(mrq->data->flags & MMC_DATA_WIDE) {
378 sdi_dcon |= S3C2410_SDIDCON_WIDEBUS;
381 if(!(mrq->data->flags & MMC_DATA_STREAM)) {
382 sdi_dcon |= S3C2410_SDIDCON_BLOCKMODE;
385 if(mrq->data->flags & MMC_DATA_WRITE) {
386 sdi_dcon |= S3C2410_SDIDCON_TXAFTERRESP;
387 sdi_dcon |= S3C2410_SDIDCON_XFER_TXSTART;
388 s3c2410sdi_dma_setup(host, DMAP_WRITE);
389 #ifdef S3C2410SDI_DMA_BACKBUF
390 memcpy(host->dmabuf_log, mrq->data->req->buffer, mrq->data->blocks * sdi_bsize);
391 #endif
394 if(mrq->data->flags & MMC_DATA_READ) {
395 sdi_dcon |= S3C2410_SDIDCON_RXAFTERCMD;
396 sdi_dcon |= S3C2410_SDIDCON_XFER_RXSTART;
397 s3c2410sdi_dma_setup(host, DMAP_READ);
402 //start DMA
403 #ifdef S3C2410SDI_DMA_BACKBUF
404 s3c2410_dma_enqueue(host->dma, (void *) host,
405 host->dmabuf_phys,
406 (mrq->data->blocks << mrq->data->blksz_bits) );
407 #else
408 s3c2410_dma_enqueue(host->dma, (void *) host,
409 virt_to_phys(mrq->data->req->buffer),
410 (mrq->data->blocks << mrq->data->blksz_bits) );
411 #endif
414 host->mrq = mrq;
416 init_completion(&host->complete_request);
417 init_completion(&host->complete_dma);
419 //Clear command and data status registers
420 writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
421 writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
423 // Setup SDI controller
424 writel(sdi_bsize,host->base + S3C2410_SDIBSIZE);
425 writel(sdi_timer,host->base + S3C2410_SDITIMER);
426 writel(sdi_imsk,host->base + S3C2410_SDIIMSK);
428 // Setup SDI command argument and data control
429 writel(sdi_carg, host->base + S3C2410_SDICMDARG);
430 writel(sdi_dcon, host->base + S3C2410_SDIDCON);
432 // This initiates transfer
433 writel(sdi_ccon, host->base + S3C2410_SDICMDCON);
435 // Wait for transfer to complete
436 wait_for_completion(&host->complete_request);
437 DBG("[CMD] request complete.\n");
438 if(mrq->data) {
439 wait_for_completion(&host->complete_dma);
440 DBG("[DAT] DMA complete.\n");
443 // Wait for DMA to complete
444 // if(mrq->data) wait_for_completion(&host->complete_dma);
446 //Cleanup controller
447 writel(0, host->base + S3C2410_SDICMDARG);
448 writel(0, host->base + S3C2410_SDIDCON);
449 writel(0, host->base + S3C2410_SDICMDCON);
450 writel(0, host->base + S3C2410_SDIIMSK);
452 // Read response
453 mrq->cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);
454 mrq->cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);
455 mrq->cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);
456 mrq->cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
458 host->mrq = NULL;
460 DBG(PFX "request done.\n");
462 // If we have no data transfer we are finished here
463 if (!mrq->data) goto request_done;
465 // Calulate the amout of bytes transfer, but only if there was
466 // no error
467 if(mrq->data->error == MMC_ERR_NONE) {
468 mrq->data->bytes_xfered = (mrq->data->blocks << mrq->data->blksz_bits);
469 if(mrq->data->flags & MMC_DATA_READ);
470 #ifdef S3C2410SDI_DMA_BACKBUF
471 memcpy(mrq->data->req->buffer, host->dmabuf_log, mrq->data->bytes_xfered);
472 #endif
473 } else {
474 mrq->data->bytes_xfered = 0;
477 // If we had an error while transfering data we flush the
478 // DMA channel to clear out any garbage
479 if(mrq->data->error != MMC_ERR_NONE) {
480 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
481 DBG(PFX "flushing DMA.\n");
483 // Issue stop command
484 if(mrq->data->stop) mmc_wait_for_cmd(mmc, mrq->data->stop, 3);
487 request_done:
489 mrq->done(mrq);
492 static void s3c2410sdi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) {
493 struct s3c2410sdi_host *host = mmc_priv(mmc);
494 u32 sdi_psc, sdi_con;
496 //Set power
497 sdi_con = readl(host->base + S3C2410_SDICON);
498 switch(ios->power_mode) {
499 case MMC_POWER_ON:
500 case MMC_POWER_UP:
501 s3c2410_gpio_setpin(S3C2410_GPA17, 1); // card power on
503 s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK);
504 s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD);
505 s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0);
506 s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
507 s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2);
508 s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3);
510 sdi_con|= S3C2410_SDICON_FIFORESET;
511 break;
513 case MMC_POWER_OFF:
514 default:
515 s3c2410_gpio_setpin(S3C2410_GPA17, 0); // card power off
517 s3c2410_gpio_setpin(S3C2410_GPE5, 0);
518 s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);
519 break;
522 //Set clock
523 for(sdi_psc=0;sdi_psc<255;sdi_psc++) {
524 if( (clk_get_rate(host->clk) / (2*(sdi_psc+1))) <= ios->clock) break;
527 if(sdi_psc > 255) sdi_psc = 255;
528 writel(sdi_psc, host->base + S3C2410_SDIPRE);
530 //Set CLOCK_ENABLE
531 if(ios->clock) sdi_con |= S3C2410_SDICON_CLOCKTYPE;
532 else sdi_con &=~S3C2410_SDICON_CLOCKTYPE;
534 writel(sdi_con, host->base + S3C2410_SDICON);
537 static struct mmc_host_ops s3c2410sdi_ops = {
538 .request = s3c2410sdi_request,
539 .set_ios = s3c2410sdi_set_ios,
542 static int s3c2410sdi_probe(struct device *dev)
544 struct platform_device *pdev = to_platform_device(dev);
545 struct mmc_host *mmc;
546 struct s3c2410sdi_host *host;
548 int ret;
550 mmc = mmc_alloc_host(sizeof(struct s3c2410sdi_host), dev);
551 if (!mmc) {
552 ret = -ENOMEM;
553 goto probe_out;
556 host = mmc_priv(mmc);
558 spin_lock_init( &host->complete_lock );
559 host->complete_what = COMPLETION_NONE;
560 host->mmc = mmc;
561 host->dma = S3C2410SDI_DMA;
562 host->irq_cd = IRQ_EINT2;
565 host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
566 if (!host->mem) {
567 printk(KERN_INFO PFX "failed to get io memory region resouce.\n");
568 ret = -ENOENT;
569 goto probe_free_host;
572 host->mem = request_mem_region(host->mem->start,
573 RESSIZE(host->mem), pdev->name);
575 if (!host->mem) {
576 printk(KERN_INFO PFX "failed to request io memory region.\n");
577 ret = -ENOENT;
578 goto probe_free_host;
581 host->base = ioremap(host->mem->start, RESSIZE(host->mem));
582 if (host->base == 0) {
583 printk(KERN_INFO PFX "failed to ioremap() io memory region.\n");
584 ret = -EINVAL;
585 goto probe_free_mem_region;
588 host->irq = platform_get_irq(pdev, 0);
589 if (host->irq == 0) {
590 printk(KERN_INFO PFX "failed to get interrupt resouce.\n");
591 ret = -EINVAL;
592 goto probe_iounmap;
595 if(request_irq(host->irq, s3c2410sdi_irq, 0, DRIVER_NAME, host)) {
596 printk(KERN_INFO PFX "failed to request sdi interrupt.\n");
597 ret = -ENOENT;
598 goto probe_iounmap;
601 s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
602 set_irq_type(host->irq_cd, IRQT_BOTHEDGE);
604 if(request_irq(host->irq_cd, s3c2410sdi_irq_cd, 0, DRIVER_NAME, host)) {
605 printk(KERN_WARNING PFX "failed to request card detect interrupt.\n" );
606 ret = -ENOENT;
607 goto probe_free_irq;
610 if(s3c2410_dma_request(S3C2410SDI_DMA, &s3c2410sdi_dma_client, NULL)) {
611 printk(KERN_WARNING PFX "unable to get DMA channel.\n" );
612 ret = -EBUSY;
613 goto probe_free_irq_cd;
616 host->clk = clk_get(dev, "sdi");
617 if (IS_ERR(host->clk)) {
618 printk(KERN_INFO PFX "failed to find clock source.\n");
619 ret = PTR_ERR(host->clk);
620 host->clk = NULL;
621 goto probe_free_host;
624 if((ret = clk_use(host->clk))) {
625 printk(KERN_INFO PFX "failed to use clock source.\n");
626 goto clk_free;
629 if((ret = clk_enable(host->clk))) {
630 printk(KERN_INFO PFX "failed to enable clock source.\n");
631 goto clk_unuse;
635 mmc->ops = &s3c2410sdi_ops;
636 mmc->ocr_avail = MMC_VDD_32_33;
637 mmc->flags = MMC_HOST_WIDEMODE;
638 mmc->f_min = clk_get_rate(host->clk) / 512;
639 mmc->f_max = clk_get_rate(host->clk) / 2;
642 //HACK: There seems to be a hardware bug in TomTom GO.
643 if(mmc->f_max>3000000) mmc->f_max=3000000;
647 * Since we only have a 16-bit data length register, we must
648 * ensure that we don't exceed 2^16-1 bytes in a single request.
649 * Choose 64 (512-byte) sectors as the limit.
651 mmc->max_sectors = 64;
654 * Set the maximum segment size. Since we aren't doing DMA
655 * (yet) we are only limited by the data length register.
658 mmc->max_seg_size = mmc->max_sectors << 9;
659 #ifdef S3C2410SDI_DMA_BACKBUF
660 host->dmabuf_log = dma_alloc_coherent(NULL, mmc->max_seg_size ,&host->dmabuf_phys, GFP_KERNEL|GFP_DMA);
662 if(!host->dmabuf_log) {
663 printk(KERN_INFO PFX "failed to allocate DMA buffer.\n");
664 goto clk_disable;
667 host->dmabuf_size = mmc->max_seg_size;
669 printk(KERN_INFO PFX "probe: mapped sdi_base=%p irq=%u irq_cd=%u dma=%u dmabuf_l=%p dmabuf_p=%p.\n",
670 host->base, host->irq, host->irq_cd, host->dma, host->dmabuf_log, host->dmabuf_phys);
671 #else
672 printk(KERN_INFO PFX "probe: mapped sdi_base=%p irq=%u irq_cd=%u dma=%u.\n",
673 host->base, host->irq, host->irq_cd, host->dma);
674 #endif
675 if((ret = mmc_add_host(mmc))) {
676 printk(KERN_INFO PFX "failed to add mmc host.\n");
677 goto free_dmabuf;
680 dev_set_drvdata(dev, mmc);
682 printk(KERN_INFO PFX "initialisation done.\n");
683 return 0;
685 free_dmabuf:
686 #ifdef S3C2410SDI_DMA_BACKBUF
687 dma_free_coherent(NULL, host->dmabuf_size, host->dmabuf_log, host->dmabuf_phys);
688 #endif
690 clk_disable:
691 clk_disable(host->clk);
693 clk_unuse:
694 clk_unuse(host->clk);
696 clk_free:
697 clk_put(host->clk);
699 probe_free_irq_cd:
700 free_irq(host->irq_cd, host);
702 probe_free_irq:
703 free_irq(host->irq, host);
705 probe_iounmap:
706 iounmap(host->base);
708 probe_free_mem_region:
709 release_mem_region(host->mem->start, RESSIZE(host->mem));
711 probe_free_host:
712 mmc_free_host(mmc);
713 probe_out:
714 return ret;
717 static int s3c2410sdi_remove(struct device *dev)
719 struct mmc_host *mmc = dev_get_drvdata(dev);
720 struct s3c2410sdi_host *host = mmc_priv(mmc);
722 mmc_remove_host(mmc);
723 #ifdef S3C2410SDI_DMA_BACKBUF
724 dma_free_coherent(NULL, host->dmabuf_size, host->dmabuf_log, host->dmabuf_phys);
725 #endif
726 clk_disable(host->clk);
727 clk_unuse(host->clk);
728 clk_put(host->clk);
729 free_irq(host->irq_cd, host);
730 free_irq(host->irq, host);
731 iounmap(host->base);
732 release_mem_region(host->mem->start, RESSIZE(host->mem));
733 mmc_free_host(mmc);
735 return 0;
738 static struct device_driver s3c2410sdi_driver =
740 .name = "s3c2410-sdi",
741 .bus = &platform_bus_type,
742 .probe = s3c2410sdi_probe,
743 .remove = s3c2410sdi_remove,
746 static int __init s3c2410sdi_init(void)
748 return driver_register(&s3c2410sdi_driver);
751 static void __exit s3c2410sdi_exit(void)
753 driver_unregister(&s3c2410sdi_driver);
756 module_init(s3c2410sdi_init);
757 module_exit(s3c2410sdi_exit);
759 MODULE_DESCRIPTION("Samsung S3C2410 Multimedia Card Interface driver");
760 MODULE_LICENSE("GPL");