1 From ed9a479d4e02e6415e4242211266845013ecad77 Mon Sep 17 00:00:00 2001
2 From: mokopatches <mokopatches@openmoko.org>
3 Date: Wed, 16 Jul 2008 14:44:50 +0100
4 Subject: [PATCH] s3c_mci.patch
5 This is a MMC/SD driver for the Samsung S3C24xx SD/MMC controller, originally
6 developed years ago by Thomas Kleffel <tk@maintech.de>.
8 Due to time restraints, he had no time to further maintain the driver and
9 follow the mainline Linux changes in the SD/MMC stack.
11 With his authorization, I have taken over the task of making it compliant to
12 the current mainline SD/MMC API and take care of the mainline kernel merge.
14 After a potential kernel inclusion, we would co-maintain the driver.
16 Acked-by: Thomas Kleffel <tk@maintech.de>
17 Signed-off-by: Harald Welte <laforge@gnumonks.org>
19 arch/arm/mach-s3c2412/s3c2412.c | 3 +
20 arch/arm/mach-s3c2440/s3c2440.c | 3 +
21 arch/arm/mach-s3c2442/s3c2442.c | 4 +
22 drivers/mmc/host/Kconfig | 11 +
23 drivers/mmc/host/Makefile | 2 +-
24 drivers/mmc/host/s3cmci.c | 1419 +++++++++++++++++++++++++++++++
25 drivers/mmc/host/s3cmci.h | 69 ++
26 include/asm-arm/arch-s3c2410/mci.h | 13 +
27 include/asm-arm/arch-s3c2410/regs-sdi.h | 22 +-
28 9 files changed, 1542 insertions(+), 4 deletions(-)
29 create mode 100644 drivers/mmc/host/s3cmci.c
30 create mode 100644 drivers/mmc/host/s3cmci.h
31 create mode 100644 include/asm-arm/arch-s3c2410/mci.h
33 diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
34 index 98a0de9..ee4436d 100644
35 --- a/arch/arm/mach-s3c2412/s3c2412.c
36 +++ b/arch/arm/mach-s3c2412/s3c2412.c
37 @@ -216,5 +216,8 @@ int __init s3c2412_init(void)
39 printk("S3C2412: Initialising architecture\n");
41 + /* make sure SD/MMC driver can distinguish 2412 from 2410 */
42 + s3c_device_sdi.name = "s3c2412-sdi";
44 return sysdev_register(&s3c2412_sysdev);
46 diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
47 index 90e1da6..6c18cbd 100644
48 --- a/arch/arm/mach-s3c2440/s3c2440.c
49 +++ b/arch/arm/mach-s3c2440/s3c2440.c
50 @@ -46,6 +46,9 @@ int __init s3c2440_init(void)
51 s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
52 s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
54 + /* make sure SD/MMC driver can distinguish 2440 from 2410 */
55 + s3c_device_sdi.name = "s3c2440-sdi";
57 /* register our system device for everything else */
59 return sysdev_register(&s3c2440_sysdev);
60 diff --git a/arch/arm/mach-s3c2442/s3c2442.c b/arch/arm/mach-s3c2442/s3c2442.c
61 index fbf8264..fbfb330 100644
62 --- a/arch/arm/mach-s3c2442/s3c2442.c
63 +++ b/arch/arm/mach-s3c2442/s3c2442.c
66 #include <asm/plat-s3c24xx/s3c2442.h>
67 #include <asm/plat-s3c24xx/cpu.h>
68 +#include <asm/plat-s3c24xx/devs.h>
70 static struct sys_device s3c2442_sysdev = {
71 .cls = &s3c2442_sysclass,
72 @@ -30,5 +31,8 @@ int __init s3c2442_init(void)
74 printk("S3C2442: Initialising architecture\n");
76 + /* make sure SD/MMC driver can distinguish 2440 from 2410 */
77 + s3c_device_sdi.name = "s3c2440-sdi";
79 return sysdev_register(&s3c2442_sysdev);
81 diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
82 index dead617..fd59856 100644
83 --- a/drivers/mmc/host/Kconfig
84 +++ b/drivers/mmc/host/Kconfig
85 @@ -130,3 +130,14 @@ config MMC_SPI
87 If unsure, or if your system has no SPI master driver, say N.
90 + tristate "Samsung S3C24xx SD/MMC Card Interface support"
91 + depends on ARCH_S3C2410 && MMC
93 + This selects a driver for the MCI interface found in
94 + Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
95 + If you have a board based on one of those and a MMC/SD
96 + slot, say Y or M here.
100 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
101 index 3877c87..071d256 100644
102 --- a/drivers/mmc/host/Makefile
103 +++ b/drivers/mmc/host/Makefile
104 @@ -17,4 +17,4 @@ obj-$(CONFIG_MMC_OMAP) += omap.o
105 obj-$(CONFIG_MMC_AT91) += at91_mci.o
106 obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
107 obj-$(CONFIG_MMC_SPI) += mmc_spi.o
109 +obj-$(CONFIG_MMC_S3C) += s3cmci.o
110 diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
112 index 0000000..edba055
114 +++ b/drivers/mmc/host/s3cmci.c
117 + * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
119 + * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
120 + * Copyright (C) 2007 Harald Welte <laforge@gnumonks.org>
122 + * This program is free software; you can redistribute it and/or modify
123 + * it under the terms of the GNU General Public License version 2 as
124 + * published by the Free Software Foundation.
127 +#include <linux/module.h>
128 +#include <linux/dma-mapping.h>
129 +#include <linux/clk.h>
130 +#include <linux/mmc/host.h>
131 +#include <linux/platform_device.h>
132 +#include <linux/irq.h>
134 +#include <asm/dma.h>
135 +#include <asm/dma-mapping.h>
138 +#include <asm/arch/regs-sdi.h>
139 +#include <asm/arch/regs-gpio.h>
140 +#include <asm/arch/mci.h>
141 +#include <asm/arch/dma.h>
145 +#define DRIVER_NAME "s3c-mci"
148 + dbg_err = (1 << 0),
149 + dbg_debug = (1 << 1),
150 + dbg_info = (1 << 2),
151 + dbg_irq = (1 << 3),
153 + dbg_dma = (1 << 5),
154 + dbg_pio = (1 << 6),
155 + dbg_fail = (1 << 7),
156 + dbg_conf = (1 << 8),
159 +static const int dbgmap_err = dbg_err | dbg_fail;
160 +static const int dbgmap_info = dbg_info | dbg_conf;
161 +static const int dbgmap_debug = dbg_debug;
163 +#define dbg(host, channels, args...) \
165 + if (dbgmap_err & channels) \
166 + dev_err(&host->pdev->dev, args); \
167 + else if (dbgmap_info & channels) \
168 + dev_info(&host->pdev->dev, args);\
169 + else if (dbgmap_debug & channels) \
170 + dev_dbg(&host->pdev->dev, args); \
173 +#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
175 +static struct s3c2410_dma_client s3cmci_dma_client = {
179 +static void finalize_request(struct s3cmci_host *host);
180 +static void s3cmci_send_request(struct mmc_host *mmc);
181 +static void s3cmci_reset(struct s3cmci_host *host);
183 +#ifdef CONFIG_MMC_DEBUG
184 +static inline void dbg_dumpregs(struct s3cmci_host *host, char *prefix)
186 + u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize;
187 + u32 datcon, datcnt, datsta, fsta, imask;
189 + con = readl(host->base + S3C2410_SDICON);
190 + pre = readl(host->base + S3C2410_SDIPRE);
191 + cmdarg = readl(host->base + S3C2410_SDICMDARG);
192 + cmdcon = readl(host->base + S3C2410_SDICMDCON);
193 + cmdsta = readl(host->base + S3C2410_SDICMDSTAT);
194 + r0 = readl(host->base + S3C2410_SDIRSP0);
195 + r1 = readl(host->base + S3C2410_SDIRSP1);
196 + r2 = readl(host->base + S3C2410_SDIRSP2);
197 + r3 = readl(host->base + S3C2410_SDIRSP3);
198 + timer = readl(host->base + S3C2410_SDITIMER);
199 + bsize = readl(host->base + S3C2410_SDIBSIZE);
200 + datcon = readl(host->base + S3C2410_SDIDCON);
201 + datcnt = readl(host->base + S3C2410_SDIDCNT);
202 + datsta = readl(host->base + S3C2410_SDIDSTA);
203 + fsta = readl(host->base + S3C2410_SDIFSTA);
204 + imask = readl(host->base + host->sdiimsk);
206 + dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n",
207 + prefix, con, pre, timer);
209 + dbg(host, dbg_debug, "%s CCON:[%08x] CARG:[%08x] CSTA:[%08x]\n",
210 + prefix, cmdcon, cmdarg, cmdsta);
212 + dbg(host, dbg_debug, "%s DCON:[%08x] FSTA:[%08x]"
213 + " DSTA:[%08x] DCNT:[%08x]\n",
214 + prefix, datcon, fsta, datsta, datcnt);
216 + dbg(host, dbg_debug, "%s R0:[%08x] R1:[%08x]"
217 + " R2:[%08x] R3:[%08x]\n",
218 + prefix, r0, r1, r2, r3);
221 +static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd,
224 + snprintf(host->dbgmsg_cmd, 300,
225 + "#%u%s op:CMD%d arg:0x%08x flags:0x08%x retries:%u",
226 + host->ccnt, (stop?" (STOP)":""), cmd->opcode,
227 + cmd->arg, cmd->flags, cmd->retries);
230 + snprintf(host->dbgmsg_dat, 300,
231 + "#%u bsize:%u blocks:%u bytes:%u",
232 + host->dcnt, cmd->data->blksz,
234 + cmd->data->blocks * cmd->data->blksz);
236 + host->dbgmsg_dat[0] = '\0';
240 +static void dbg_dumpcmd(struct s3cmci_host *host, struct mmc_command *cmd,
243 + unsigned int dbglvl = fail?dbg_fail:dbg_debug;
248 + if (cmd->error == 0)
249 + dbg(host, dbglvl, "CMD[OK] %s R0:0x%08x\n",
250 + host->dbgmsg_cmd, cmd->resp[0]);
252 + dbg(host, dbglvl, "CMD[FAIL(%d)] %s Status:%s\n",
253 + cmd->error, host->dbgmsg_cmd, host->status);
258 + if (cmd->data->error == 0)
259 + dbg(host, dbglvl, "DAT[OK] %s\n", host->dbgmsg_dat);
261 + dbg(host, dbglvl, "DAT[FAIL(%d)] %s DCNT:0x%08x\n",
262 + cmd->data->error, host->dbgmsg_dat,
263 + readl(host->base + S3C2410_SDIDCNT));
265 +#endif /* CONFIG_MMC_DEBUG */
267 +static inline u32 enable_imask(struct s3cmci_host *host, u32 imask)
271 + newmask = readl(host->base + host->sdiimsk);
274 + writel(newmask, host->base + host->sdiimsk);
279 +static inline u32 disable_imask(struct s3cmci_host *host, u32 imask)
283 + newmask = readl(host->base + host->sdiimsk);
286 + writel(newmask, host->base + host->sdiimsk);
291 +static inline void clear_imask(struct s3cmci_host *host)
293 + writel(0, host->base + host->sdiimsk);
296 +static inline int get_data_buffer(struct s3cmci_host *host,
297 + u32 *bytes, u8 **pointer)
299 + struct scatterlist *sg;
301 + if (host->pio_active == XFER_NONE)
304 + if ((!host->mrq) || (!host->mrq->data))
307 + if (host->pio_sgptr >= host->mrq->data->sg_len) {
308 + dbg(host, dbg_debug, "no more buffers (%i/%i)\n",
309 + host->pio_sgptr, host->mrq->data->sg_len);
312 + sg = &host->mrq->data->sg[host->pio_sgptr];
314 + *bytes = sg->length;
315 + *pointer = page_address(sg_page(sg)) + sg->offset;
319 + dbg(host, dbg_sg, "new buffer (%i/%i)\n",
320 + host->pio_sgptr, host->mrq->data->sg_len);
325 +#define FIFO_FILL(host) (readl(host->base + S3C2410_SDIFSTA) & \
326 + S3C2410_SDIFSTA_COUNTMASK)
327 +#define FIFO_FREE(host) (63 - (readl(host->base + S3C2410_SDIFSTA) \
328 + & S3C2410_SDIFSTA_COUNTMASK))
330 +static inline void do_pio_read(struct s3cmci_host *host)
334 + void __iomem *from_ptr;
336 + /* write real prescaler to host, it might be set slow to fix */
337 + writel(host->prescaler, host->base + S3C2410_SDIPRE);
339 + from_ptr = host->base + host->sdidata;
341 + while ((fifo = FIFO_FILL(host))) {
342 + if (!host->pio_bytes) {
343 + res = get_data_buffer(host, &host->pio_bytes,
346 + host->pio_active = XFER_NONE;
347 + host->complete_what = COMPLETION_FINALIZE;
349 + dbg(host, dbg_pio, "pio_read(): "
350 + "complete (no more data).\n");
354 + dbg(host, dbg_pio, "pio_read(): new target: "
355 + "[%i]@[%p]\n", host->pio_bytes, host->pio_ptr);
358 + dbg(host, dbg_pio, "pio_read(): fifo:[%02i] "
359 + "buffer:[%03i] dcnt:[%08X]\n", fifo, host->pio_bytes,
360 + readl(host->base + S3C2410_SDIDCNT));
362 + if (fifo > host->pio_bytes)
363 + fifo = host->pio_bytes;
365 + host->pio_bytes -= fifo;
366 + host->pio_count += fifo;
368 + /* we might have an unaligned start of data */
369 + while (((unsigned long)host->pio_ptr & 0x03) && fifo) {
370 + *(host->pio_ptr++) = readb(host->base + host->sdidata_b);
374 + /* and a major chunk of data in the middle */
375 + for (; fifo >= 4; fifo -=4) {
376 + *(u32 *) host->pio_ptr = readl(from_ptr);
380 + /* as well as some non-modulo-four trailer */
382 + *(host->pio_ptr++) = readb(host->base + host->sdidata_b);
387 + if (!host->pio_bytes) {
388 + res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);
390 + dbg(host, dbg_pio, "pio_read(): "
391 + "complete (no more buffers).\n");
392 + host->pio_active = XFER_NONE;
393 + host->complete_what = COMPLETION_FINALIZE;
399 + enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF
400 + | S3C2410_SDIIMSK_RXFIFOLAST);
403 +static inline void do_pio_write(struct s3cmci_host *host)
408 + void __iomem *to_ptr;
410 + to_ptr = host->base + host->sdidata;
412 + while ((fifo = FIFO_FREE(host))) {
413 + if (!host->pio_bytes) {
414 + res = get_data_buffer(host, &host->pio_bytes,
417 + dbg(host, dbg_pio, "pio_write(): "
418 + "complete (no more data).\n");
419 + host->pio_active = XFER_NONE;
424 + dbg(host, dbg_pio, "pio_write(): "
425 + "new source: [%i]@[%p]\n",
426 + host->pio_bytes, host->pio_ptr);
430 + if (fifo > host->pio_bytes)
431 + fifo = host->pio_bytes;
433 + host->pio_bytes -= fifo;
434 + host->pio_count += fifo;
436 + /* we might have an unaligned start of data */
437 + while (((unsigned long)host->pio_ptr & 0x03) && fifo) {
438 + writeb(*(host->pio_ptr++), host->base + host->sdidata_b);
442 + /* and a major chunk of data in the middle */
443 + for (; fifo >= 4; fifo -=4) {
444 + writel(*(u32 *) host->pio_ptr, to_ptr);
445 + host->pio_ptr += 4;
448 + /* as well as some non-modulo-four trailer */
450 + writeb(*(host->pio_ptr++), host->base + host->sdidata_b);
455 + enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
458 +static void pio_tasklet(unsigned long data)
460 + struct s3cmci_host *host = (struct s3cmci_host *) data;
462 + disable_irq(host->irq);
464 + if (host->pio_active == XFER_WRITE)
465 + do_pio_write(host);
467 + if (host->pio_active == XFER_READ)
470 + if (host->complete_what == COMPLETION_FINALIZE) {
472 + if (host->pio_active != XFER_NONE) {
473 + dbg(host, dbg_err, "unfinished %s "
474 + "- pio_count:[%u] pio_bytes:[%u]\n",
475 + (host->pio_active == XFER_READ)?"read":"write",
476 + host->pio_count, host->pio_bytes);
478 + host->mrq->data->error = -EIO;
481 + finalize_request(host);
483 + enable_irq(host->irq);
487 + * ISR for SDI Interface IRQ
488 + * Communication between driver and ISR works as follows:
489 + * host->mrq points to current request
490 + * host->complete_what tells ISR when the request is considered done
491 + * COMPLETION_CMDSENT when the command was sent
492 + * COMPLETION_RSPFIN when a response was received
493 + * COMPLETION_XFERFINISH when the data transfer is finished
494 + * COMPLETION_XFERFINISH_RSPFIN both of the above.
495 + * host->complete_request is the completion-object the driver waits for
497 + * 1) Driver sets up host->mrq and host->complete_what
498 + * 2) Driver prepares the transfer
499 + * 3) Driver enables interrupts
500 + * 4) Driver starts transfer
501 + * 5) Driver waits for host->complete_rquest
502 + * 6) ISR checks for request status (errors and success)
503 + * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error
504 + * 7) ISR completes host->complete_request
505 + * 8) ISR disables interrupts
506 + * 9) Driver wakes up and takes care of the request
508 + * Note: "->error"-fields are expected to be set to 0 before the request
509 + * was issued by mmc.c - therefore they are only set, when an error
510 + * contition comes up
513 +static irqreturn_t s3cmci_irq(int irq, void *dev_id)
515 + struct s3cmci_host *host;
516 + struct mmc_command *cmd;
517 + u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;
518 + u32 mci_cclear, mci_dclear;
519 + unsigned long iflags;
522 + host = (struct s3cmci_host *)dev_id;
524 + spin_lock_irqsave(&host->complete_lock, iflags);
526 + mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
527 + mci_dsta = readl(host->base + S3C2410_SDIDSTA);
528 + mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
529 + mci_fsta = readl(host->base + S3C2410_SDIFSTA);
530 + mci_imsk = readl(host->base + host->sdiimsk);
534 + if ((host->complete_what == COMPLETION_NONE) ||
535 + (host->complete_what == COMPLETION_FINALIZE)) {
536 + host->status = "nothing to complete";
542 + host->status = "no active mrq";
547 + cmd = host->cmd_is_stop?host->mrq->stop:host->mrq->cmd;
550 + host->status = "no active cmd";
555 + if (!host->dodma) {
556 + if ((host->pio_active == XFER_WRITE) &&
557 + (mci_fsta & S3C2410_SDIFSTA_TFDET)) {
559 + disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
560 + tasklet_schedule(&host->pio_tasklet);
561 + host->status = "pio tx";
564 + if ((host->pio_active == XFER_READ) &&
565 + (mci_fsta & S3C2410_SDIFSTA_RFDET)) {
567 + disable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF |
568 + S3C2410_SDIIMSK_RXFIFOLAST);
570 + tasklet_schedule(&host->pio_tasklet);
571 + host->status = "pio rx";
575 + if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
576 + cmd->error = -ETIMEDOUT;
577 + host->status = "error: command timeout";
578 + goto fail_transfer;
581 + if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {
582 + if (host->complete_what == COMPLETION_CMDSENT) {
583 + host->status = "ok: command sent";
584 + goto close_transfer;
587 + mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
590 + if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {
591 + if (cmd->flags & MMC_RSP_CRC) {
592 + if (host->mrq->cmd->flags & MMC_RSP_136) {
593 + dbg(host, dbg_irq, "fixup for chip bug: "
594 + "ignore CRC fail with long rsp\n");
596 + cmd->error = -EILSEQ;
597 + host->status = "error: bad command crc";
598 + goto fail_transfer;
602 + mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;
605 + if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) {
606 + if (host->complete_what == COMPLETION_RSPFIN) {
607 + host->status = "ok: command response received";
608 + goto close_transfer;
611 + if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
612 + host->complete_what = COMPLETION_XFERFINISH;
614 + mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;
617 + /* errors handled after this point are only relevant
618 + when a data transfer is in progress */
621 + goto clear_status_bits;
623 + /* Check for FIFO failure */
624 + if (host->is2440) {
625 + if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {
626 + host->mrq->data->error = -EIO;
627 + host->status = "error: 2440 fifo failure";
628 + goto fail_transfer;
631 + if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {
632 + cmd->data->error = -EIO;
633 + host->status = "error: fifo failure";
634 + goto fail_transfer;
638 + if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {
639 + cmd->data->error = -EILSEQ;
640 + host->status = "error: bad data crc (outgoing)";
641 + goto fail_transfer;
644 + if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {
645 + cmd->data->error = -EIO;
646 + host->status = "error: bad data crc (incoming)";
647 + goto fail_transfer;
650 + if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {
651 + cmd->data->error = -ETIMEDOUT;
652 + host->status = "error: data timeout";
653 + goto fail_transfer;
656 + if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {
657 + if (host->complete_what == COMPLETION_XFERFINISH) {
658 + host->status = "ok: data transfer completed";
659 + goto close_transfer;
662 + if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
663 + host->complete_what = COMPLETION_RSPFIN;
665 + mci_dclear |= S3C2410_SDIDSTA_XFERFINISH;
668 + if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {
670 + mci_dclear |= S3C2410_SDIDSTA_SDIOIRQDETECT;
674 + writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);
675 + writel(mci_dclear, host->base + S3C2410_SDIDSTA);
680 + host->pio_active = XFER_NONE;
683 + host->complete_what = COMPLETION_FINALIZE;
686 + tasklet_schedule(&host->pio_tasklet);
691 + dbg(host, dbg_irq, "csta:0x%08x dsta:0x%08x "
692 + "fsta:0x%08x dcnt:0x%08x status:%s.\n",
693 + mci_csta, mci_dsta, mci_fsta,
694 + mci_dcnt, host->status);
696 + spin_unlock_irqrestore(&host->complete_lock, iflags);
698 + /* We have to delay this as it calls back into the driver */
700 + mmc_signal_sdio_irq(host->mmc);
702 + return IRQ_HANDLED;
707 + * ISR for the CardDetect Pin
710 +static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
712 + struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
714 + dbg(host, dbg_irq, "card detect\n");
716 + mmc_detect_change(host->mmc, 500);
718 + return IRQ_HANDLED;
721 +void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, void *buf_id,
722 + int size, enum s3c2410_dma_buffresult result)
724 + unsigned long iflags;
725 + u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;
726 + struct s3cmci_host *host = (struct s3cmci_host *)buf_id;
728 + mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
729 + mci_dsta = readl(host->base + S3C2410_SDIDSTA);
730 + mci_fsta = readl(host->base + S3C2410_SDIFSTA);
731 + mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
733 + if ((!host->mrq) || (!host->mrq) || (!host->mrq->data))
736 + if (!host->dmatogo)
739 + spin_lock_irqsave(&host->complete_lock, iflags);
741 + if (result != S3C2410_RES_OK) {
742 + dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
743 + "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",
744 + mci_csta, mci_dsta, mci_fsta,
745 + mci_dcnt, result, host->dmatogo);
751 + if (host->dmatogo) {
752 + dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "
753 + "DCNT:[%08x] toGo:%u\n",
754 + size, mci_dsta, mci_dcnt, host->dmatogo);
759 + dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
760 + size, mci_dsta, mci_dcnt);
762 + host->complete_what = COMPLETION_FINALIZE;
765 + tasklet_schedule(&host->pio_tasklet);
766 + spin_unlock_irqrestore(&host->complete_lock, iflags);
771 + host->mrq->data->error = -EIO;
772 + host->complete_what = COMPLETION_FINALIZE;
773 + writel(0, host->base + host->sdiimsk);
778 +static void finalize_request(struct s3cmci_host *host)
780 + struct mmc_request *mrq = host->mrq;
781 + struct mmc_command *cmd = host->cmd_is_stop?mrq->stop:mrq->cmd;
782 + int debug_as_failure = 0;
784 + if (host->complete_what != COMPLETION_FINALIZE)
790 + if (cmd->data && (cmd->error == 0) &&
791 + (cmd->data->error == 0)) {
793 + if (host->dodma && (!host->dma_complete)) {
794 + dbg(host, dbg_dma, "DMA Missing!\n");
799 + /* Read response */
800 + cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);
801 + cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);
802 + cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);
803 + cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
805 + /* reset clock speed, as it could still be set low for */
806 + writel(host->prescaler, host->base + S3C2410_SDIPRE);
809 + debug_as_failure = 1;
811 + if (cmd->data && cmd->data->error)
812 + debug_as_failure = 1;
814 +#ifdef CONFIG_MMC_DEBUG
815 + dbg_dumpcmd(host, cmd, debug_as_failure);
817 + /* Cleanup controller */
818 + writel(0, host->base + S3C2410_SDICMDARG);
819 + writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
820 + writel(0, host->base + S3C2410_SDICMDCON);
821 + writel(0, host->base + host->sdiimsk);
823 + if (cmd->data && cmd->error)
824 + cmd->data->error = cmd->error;
826 + if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {
827 + host->cmd_is_stop = 1;
828 + s3cmci_send_request(host->mmc);
832 + /* If we have no data transfer we are finished here */
836 + /* Calulate the amout of bytes transfer, but only if there was
838 + if (mrq->data->error == 0)
839 + mrq->data->bytes_xfered =
840 + (mrq->data->blocks * mrq->data->blksz);
842 + mrq->data->bytes_xfered = 0;
844 + /* If we had an error while transfering data we flush the
845 + * DMA channel and the fifo to clear out any garbage */
846 + if (mrq->data->error) {
848 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
850 + if (host->is2440) {
851 + /* Clear failure register and reset fifo */
852 + writel(S3C2440_SDIFSTA_FIFORESET |
853 + S3C2440_SDIFSTA_FIFOFAIL,
854 + host->base + S3C2410_SDIFSTA);
859 + mci_con = readl(host->base + S3C2410_SDICON);
860 + mci_con |= S3C2410_SDICON_FIFORESET;
862 + writel(mci_con, host->base + S3C2410_SDICON);
867 + host->complete_what = COMPLETION_NONE;
869 + mmc_request_done(host->mmc, mrq);
873 +void s3cmci_dma_setup(struct s3cmci_host *host, enum s3c2410_dmasrc source)
875 + static int setup_ok;
876 + static enum s3c2410_dmasrc last_source = -1;
878 + if (last_source == source)
881 + last_source = source;
883 + s3c2410_dma_devconfig(host->dma, source, 3,
884 + host->mem->start + host->sdidata);
887 + s3c2410_dma_config(host->dma, 4,
888 + (S3C2410_DCON_HWTRIG | S3C2410_DCON_CH0_SDI));
889 + s3c2410_dma_set_buffdone_fn(host->dma,
890 + s3cmci_dma_done_callback);
891 + s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
896 +static void s3cmci_send_command(struct s3cmci_host *host,
897 + struct mmc_command *cmd)
901 + imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |
902 + S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT |
903 + S3C2410_SDIIMSK_RESPONSECRC;
905 + enable_imask(host, imsk);
908 + host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
909 + else if (cmd->flags & MMC_RSP_PRESENT)
910 + host->complete_what = COMPLETION_RSPFIN;
912 + host->complete_what = COMPLETION_CMDSENT;
914 + writel(cmd->arg, host->base + S3C2410_SDICMDARG);
916 + ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX;
917 + ccon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;
919 + if (cmd->flags & MMC_RSP_PRESENT)
920 + ccon |= S3C2410_SDICMDCON_WAITRSP;
922 + if (cmd->flags & MMC_RSP_136)
923 + ccon |= S3C2410_SDICMDCON_LONGRSP;
925 + writel(ccon, host->base + S3C2410_SDICMDCON);
928 +static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
930 + u32 dcon, imsk, stoptries = 3;
932 + /* write DCON register */
935 + writel(0, host->base + S3C2410_SDIDCON);
939 + while (readl(host->base + S3C2410_SDIDSTA) &
940 + (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {
943 + "mci_setup_data() transfer stillin progress.\n");
945 + writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
946 + s3cmci_reset(host);
948 + if (0 == (stoptries--)) {
949 +#ifdef CONFIG_MMC_DEBUG
950 + dbg_dumpregs(host, "DRF");
957 + dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;
960 + dcon |= S3C2410_SDIDCON_DMAEN;
962 + if (host->bus_width == MMC_BUS_WIDTH_4)
963 + dcon |= S3C2410_SDIDCON_WIDEBUS;
965 + if (!(data->flags & MMC_DATA_STREAM))
966 + dcon |= S3C2410_SDIDCON_BLOCKMODE;
968 + if (data->flags & MMC_DATA_WRITE) {
969 + dcon |= S3C2410_SDIDCON_TXAFTERRESP;
970 + dcon |= S3C2410_SDIDCON_XFER_TXSTART;
973 + if (data->flags & MMC_DATA_READ) {
974 + dcon |= S3C2410_SDIDCON_RXAFTERCMD;
975 + dcon |= S3C2410_SDIDCON_XFER_RXSTART;
978 + if (host->is2440) {
979 + dcon |= S3C2440_SDIDCON_DS_WORD;
980 + dcon |= S3C2440_SDIDCON_DATSTART;
983 + writel(dcon, host->base + S3C2410_SDIDCON);
985 + /* write BSIZE register */
987 + writel(data->blksz, host->base + S3C2410_SDIBSIZE);
989 + /* add to IMASK register */
990 + imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
991 + S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;
993 + enable_imask(host, imsk);
995 + /* write TIMER register */
997 + if (host->is2440) {
998 + writel(0x007FFFFF, host->base + S3C2410_SDITIMER);
1000 + writel(0x0000FFFF, host->base + S3C2410_SDITIMER);
1002 + /* FIX: set slow clock to prevent timeouts on read */
1003 + if (data->flags & MMC_DATA_READ)
1004 + writel(0xFF, host->base + S3C2410_SDIPRE);
1010 +static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
1012 + int rw = (data->flags & MMC_DATA_WRITE)?1:0;
1014 + if (rw != ((data->flags & MMC_DATA_READ)?0:1))
1017 + host->pio_sgptr = 0;
1018 + host->pio_bytes = 0;
1019 + host->pio_count = 0;
1020 + host->pio_active = rw?XFER_WRITE:XFER_READ;
1023 + do_pio_write(host);
1024 + enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
1026 + enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF
1027 + | S3C2410_SDIIMSK_RXFIFOLAST);
1033 +static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
1037 + int rw = (data->flags & MMC_DATA_WRITE)?1:0;
1039 + if (rw != ((data->flags & MMC_DATA_READ)?0:1))
1042 + s3cmci_dma_setup(host, rw?S3C2410_DMASRC_MEM:S3C2410_DMASRC_HW);
1043 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
1045 + dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1046 + (rw)?DMA_TO_DEVICE:DMA_FROM_DEVICE);
1052 + host->dma_complete = 0;
1053 + host->dmatogo = dma_len;
1055 + for (i = 0; i < dma_len; i++) {
1058 + dbg(host, dbg_dma, "enqueue %i:%u@%u\n", i,
1059 + sg_dma_address(&data->sg[i]),
1060 + sg_dma_len(&data->sg[i]));
1062 + res = s3c2410_dma_enqueue(host->dma, (void *) host,
1063 + sg_dma_address(&data->sg[i]),
1064 + sg_dma_len(&data->sg[i]));
1067 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
1072 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START);
1077 +static void s3cmci_send_request(struct mmc_host *mmc)
1079 + struct s3cmci_host *host = mmc_priv(mmc);
1080 + struct mmc_request *mrq = host->mrq;
1081 + struct mmc_command *cmd = host->cmd_is_stop?mrq->stop:mrq->cmd;
1084 +#ifdef CONFIG_MMC_DEBUG
1085 + prepare_dbgmsg(host, cmd, host->cmd_is_stop);
1087 + /* clear command, data and fifo status registers;
1088 + * Fifo clear only necessary on 2440, but doesn't hurt on 2410 */
1089 + writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
1090 + writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
1091 + writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);
1095 + res = s3cmci_setup_data(host, cmd->data);
1100 + cmd->error = -EIO;
1101 + cmd->data->error = -EIO;
1103 + mmc_request_done(mmc, mrq);
1109 + res = s3cmci_prepare_dma(host, cmd->data);
1111 + res = s3cmci_prepare_pio(host, cmd->data);
1114 + cmd->error = -EIO;
1115 + cmd->data->error = -EIO;
1117 + mmc_request_done(mmc, mrq);
1123 + s3cmci_send_command(host, cmd);
1124 + enable_irq(host->irq);
1127 +static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1129 + struct s3cmci_host *host = mmc_priv(mmc);
1131 + host->cmd_is_stop = 0;
1134 + s3cmci_send_request(mmc);
1137 +static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1139 + struct s3cmci_host *host = mmc_priv(mmc);
1140 + u32 mci_psc, mci_con;
1143 + mci_con = readl(host->base + S3C2410_SDICON);
1144 + switch (ios->power_mode) {
1145 + case MMC_POWER_ON:
1146 + case MMC_POWER_UP:
1147 + s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK);
1148 + s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD);
1149 + s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0);
1150 + s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
1151 + s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2);
1152 + s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3);
1154 + if (host->pdata->set_power)
1155 + host->pdata->set_power(ios->power_mode, ios->vdd);
1157 + if (!host->is2440)
1158 + mci_con |= S3C2410_SDICON_FIFORESET;
1162 + case MMC_POWER_OFF:
1164 + s3c2410_gpio_setpin(S3C2410_GPE5, 0);
1165 + s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);
1167 + if (host->pdata->set_power)
1168 + host->pdata->set_power(ios->power_mode, ios->vdd);
1171 + mci_con |= S3C2440_SDICON_SDRESET;
1177 + for (mci_psc = 0; mci_psc < 255; mci_psc++) {
1178 + host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
1180 + if (host->real_rate <= ios->clock)
1184 + if (mci_psc > 255)
1186 + host->prescaler = mci_psc;
1188 + writel(host->prescaler, host->base + S3C2410_SDIPRE);
1190 + /* If requested clock is 0, real_rate will be 0, too */
1191 + if (ios->clock == 0)
1192 + host->real_rate = 0;
1194 + /* Set CLOCK_ENABLE */
1196 + mci_con |= S3C2410_SDICON_CLOCKTYPE;
1198 + mci_con &= ~S3C2410_SDICON_CLOCKTYPE;
1200 + writel(mci_con, host->base + S3C2410_SDICON);
1202 + if ((ios->power_mode == MMC_POWER_ON)
1203 + || (ios->power_mode == MMC_POWER_UP)) {
1205 + dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
1206 + host->real_rate/1000, ios->clock/1000);
1208 + dbg(host, dbg_conf, "powered down.\n");
1211 + host->bus_width = ios->bus_width;
1215 +static void s3cmci_reset(struct s3cmci_host *host)
1217 + u32 con = readl(host->base + S3C2410_SDICON);
1219 + con |= S3C2440_SDICON_SDRESET;
1221 + writel(con, host->base + S3C2410_SDICON);
1224 +static int s3cmci_get_ro(struct mmc_host *mmc)
1226 + struct s3cmci_host *host = mmc_priv(mmc);
1228 + if (host->pdata->gpio_wprotect == 0)
1231 + return s3c2410_gpio_getpin(host->pdata->gpio_wprotect);
1234 +static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
1236 + struct s3cmci_host *host = mmc_priv(mmc);
1239 + enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
1241 + disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
1244 +static struct mmc_host_ops s3cmci_ops = {
1245 + .request = s3cmci_request,
1246 + .set_ios = s3cmci_set_ios,
1247 + .get_ro = s3cmci_get_ro,
1248 + .enable_sdio_irq = s3cmci_enable_sdio_irq,
1251 +static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
1254 + .set_power = NULL,
1255 + .ocr_avail = MMC_VDD_32_33,
1258 +static int s3cmci_probe(struct platform_device *pdev, int is2440)
1260 + struct mmc_host *mmc;
1261 + struct s3cmci_host *host;
1265 + mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);
1271 + host = mmc_priv(mmc);
1273 + host->pdev = pdev;
1275 + host->pdata = pdev->dev.platform_data;
1276 + if (!host->pdata) {
1277 + pdev->dev.platform_data = &s3cmci_def_pdata;
1278 + host->pdata = &s3cmci_def_pdata;
1281 + spin_lock_init(&host->complete_lock);
1282 + tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
1285 + host->sdiimsk = S3C2440_SDIIMSK;
1286 + host->sdidata = S3C2440_SDIDATA;
1287 + host->sdidata_b = S3C2440_SDIDATA_BYTE;
1288 + host->clk_div = 1;
1291 + host->sdiimsk = S3C2410_SDIIMSK;
1292 + host->sdidata = S3C2410_SDIDATA;
1293 + host->sdidata_b = S3C2410_SDIDATA_BYTE;
1294 + host->clk_div = 2;
1296 + host->dodma = host->pdata->do_dma;
1297 + host->complete_what = COMPLETION_NONE;
1298 + host->pio_active = XFER_NONE;
1300 + host->dma = DMACH_SDI;
1301 + host->irq_cd = s3c2410_gpio_getirq(host->pdata->gpio_detect);
1302 + s3c2410_gpio_cfgpin(host->pdata->gpio_detect, S3C2410_GPIO_IRQ);
1304 + host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1306 + dev_err(&pdev->dev,
1307 + "failed to get io memory region resouce.\n");
1310 + goto probe_free_host;
1313 + host->mem = request_mem_region(host->mem->start,
1314 + RESSIZE(host->mem), pdev->name);
1317 + dev_err(&pdev->dev, "failed to request io memory region.\n");
1319 + goto probe_free_host;
1322 + host->base = ioremap(host->mem->start, RESSIZE(host->mem));
1323 + if (host->base == 0) {
1324 + dev_err(&pdev->dev, "failed to ioremap() io memory region.\n");
1326 + goto probe_free_mem_region;
1329 + host->irq = platform_get_irq(pdev, 0);
1330 + if (host->irq == 0) {
1331 + dev_err(&pdev->dev, "failed to get interrupt resouce.\n");
1333 + goto probe_iounmap;
1336 + if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
1337 + dev_err(&pdev->dev, "failed to request mci interrupt.\n");
1339 + goto probe_iounmap;
1342 + disable_irq(host->irq);
1344 + s3c2410_gpio_cfgpin(host->pdata->gpio_detect, S3C2410_GPIO_IRQ);
1345 + set_irq_type(host->irq_cd, IRQT_BOTHEDGE);
1347 + if (request_irq(host->irq_cd, s3cmci_irq_cd, 0, DRIVER_NAME, host)) {
1348 + dev_err(&pdev->dev,
1349 + "failed to request card detect interrupt.\n");
1352 + goto probe_free_irq;
1355 + if (host->pdata->gpio_wprotect)
1356 + s3c2410_gpio_cfgpin(host->pdata->gpio_wprotect,
1357 + S3C2410_GPIO_INPUT);
1359 + if (s3c2410_dma_request(host->dma, &s3cmci_dma_client, NULL)) {
1360 + dev_err(&pdev->dev, "unable to get DMA channel.\n");
1362 + goto probe_free_irq_cd;
1365 + host->clk = clk_get(&pdev->dev, "sdi");
1366 + if (IS_ERR(host->clk)) {
1367 + dev_err(&pdev->dev, "failed to find clock source.\n");
1368 + ret = PTR_ERR(host->clk);
1370 + goto probe_free_host;
1373 + ret = clk_enable(host->clk);
1375 + dev_err(&pdev->dev, "failed to enable clock source.\n");
1379 + host->clk_rate = clk_get_rate(host->clk);
1381 + mmc->ops = &s3cmci_ops;
1382 + mmc->ocr_avail = host->pdata->ocr_avail;
1383 + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
1384 + mmc->f_min = host->clk_rate / (host->clk_div * 256);
1385 + mmc->f_max = host->clk_rate / host->clk_div;
1387 + mmc->max_blk_count = 4095;
1388 + mmc->max_blk_size = 4095;
1389 + mmc->max_req_size = 4095 * 512;
1390 + mmc->max_seg_size = mmc->max_req_size;
1392 + mmc->max_phys_segs = 128;
1393 + mmc->max_hw_segs = 128;
1395 + dbg(host, dbg_debug, "probe: mode:%s mapped mci_base:%p irq:%u "
1396 + "irq_cd:%u dma:%u.\n", (host->is2440?"2440":""),
1397 + host->base, host->irq, host->irq_cd, host->dma);
1399 + ret = mmc_add_host(mmc);
1401 + dev_err(&pdev->dev, "failed to add mmc host.\n");
1405 + platform_set_drvdata(pdev, mmc);
1407 + dev_info(&pdev->dev, "initialisation done.\n");
1411 + clk_disable(host->clk);
1414 + clk_put(host->clk);
1416 + probe_free_irq_cd:
1417 + free_irq(host->irq_cd, host);
1420 + free_irq(host->irq, host);
1423 + iounmap(host->base);
1425 + probe_free_mem_region:
1426 + release_mem_region(host->mem->start, RESSIZE(host->mem));
1429 + mmc_free_host(mmc);
1434 +static int s3cmci_remove(struct platform_device *pdev)
1436 + struct mmc_host *mmc = platform_get_drvdata(pdev);
1437 + struct s3cmci_host *host = mmc_priv(mmc);
1439 + mmc_remove_host(mmc);
1440 + clk_disable(host->clk);
1441 + clk_put(host->clk);
1442 + s3c2410_dma_free(host->dma, &s3cmci_dma_client);
1443 + free_irq(host->irq_cd, host);
1444 + free_irq(host->irq, host);
1445 + iounmap(host->base);
1446 + release_mem_region(host->mem->start, RESSIZE(host->mem));
1447 + mmc_free_host(mmc);
1452 +static int s3cmci_probe_2410(struct platform_device *dev)
1454 + return s3cmci_probe(dev, 0);
1457 +static int s3cmci_probe_2412(struct platform_device *dev)
1459 + return s3cmci_probe(dev, 1);
1462 +static int s3cmci_probe_2440(struct platform_device *dev)
1464 + return s3cmci_probe(dev, 1);
1469 +static int s3cmci_suspend(struct platform_device *dev, pm_message_t state)
1471 + struct mmc_host *mmc = platform_get_drvdata(dev);
1473 + return mmc_suspend_host(mmc, state);
1476 +static int s3cmci_resume(struct platform_device *dev)
1478 + struct mmc_host *mmc = platform_get_drvdata(dev);
1480 + return mmc_resume_host(mmc);
1483 +#else /* CONFIG_PM */
1484 +#define s3cmci_suspend NULL
1485 +#define s3cmci_resume NULL
1486 +#endif /* CONFIG_PM */
1489 +static struct platform_driver s3cmci_driver_2410 = {
1490 + .driver.name = "s3c2410-sdi",
1491 + .probe = s3cmci_probe_2410,
1492 + .remove = s3cmci_remove,
1493 + .suspend = s3cmci_suspend,
1494 + .resume = s3cmci_resume,
1497 +static struct platform_driver s3cmci_driver_2412 = {
1498 + .driver.name = "s3c2412-sdi",
1499 + .probe = s3cmci_probe_2412,
1500 + .remove = s3cmci_remove,
1501 + .suspend = s3cmci_suspend,
1502 + .resume = s3cmci_resume,
1505 +static struct platform_driver s3cmci_driver_2440 = {
1506 + .driver.name = "s3c2440-sdi",
1507 + .probe = s3cmci_probe_2440,
1508 + .remove = s3cmci_remove,
1509 + .suspend = s3cmci_suspend,
1510 + .resume = s3cmci_resume,
1514 +static int __init s3cmci_init(void)
1516 + platform_driver_register(&s3cmci_driver_2410);
1517 + platform_driver_register(&s3cmci_driver_2412);
1518 + platform_driver_register(&s3cmci_driver_2440);
1522 +static void __exit s3cmci_exit(void)
1524 + platform_driver_unregister(&s3cmci_driver_2410);
1525 + platform_driver_unregister(&s3cmci_driver_2412);
1526 + platform_driver_unregister(&s3cmci_driver_2440);
1529 +module_init(s3cmci_init);
1530 +module_exit(s3cmci_exit);
1532 +MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
1533 +MODULE_LICENSE("GPL");
1534 +MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>");
1535 diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
1536 new file mode 100644
1537 index 0000000..9644b45
1539 +++ b/drivers/mmc/host/s3cmci.h
1542 + * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
1544 + * Copyright (C) 2004-2006 Thomas Kleffel, All Rights Reserved.
1546 + * This program is free software; you can redistribute it and/or modify
1547 + * it under the terms of the GNU General Public License version 2 as
1548 + * published by the Free Software Foundation.
1551 +enum s3cmci_waitfor {
1553 + COMPLETION_FINALIZE,
1554 + COMPLETION_CMDSENT,
1555 + COMPLETION_RSPFIN,
1556 + COMPLETION_XFERFINISH,
1557 + COMPLETION_XFERFINISH_RSPFIN,
1560 +struct s3cmci_host {
1561 + struct platform_device *pdev;
1562 + struct s3c24xx_mci_pdata *pdata;
1563 + struct mmc_host *mmc;
1564 + struct resource *mem;
1566 + void __iomem *base;
1571 + unsigned long clk_rate;
1572 + unsigned long clk_div;
1573 + unsigned long real_rate;
1579 + unsigned sdidata_b;
1584 + struct mmc_request *mrq;
1587 + spinlock_t complete_lock;
1588 + enum s3cmci_waitfor complete_what;
1596 +#define XFER_NONE 0
1597 +#define XFER_READ 1
1598 +#define XFER_WRITE 2
1603 + char dbgmsg_cmd[301];
1604 + char dbgmsg_dat[301];
1607 + unsigned int ccnt, dcnt;
1608 + struct tasklet_struct pio_tasklet;
1610 diff --git a/include/asm-arm/arch-s3c2410/mci.h b/include/asm-arm/arch-s3c2410/mci.h
1611 new file mode 100644
1612 index 0000000..24e6cd1
1614 +++ b/include/asm-arm/arch-s3c2410/mci.h
1616 +#ifndef _ARCH_MCI_H
1617 +#define _ARCH_MCI_H
1619 +struct s3c24xx_mci_pdata {
1620 + unsigned int gpio_detect;
1621 + unsigned int gpio_wprotect;
1622 + unsigned long ocr_avail;
1623 + unsigned int do_dma;
1624 + void (*set_power)(unsigned char power_mode,
1625 + unsigned short vdd);
1628 +#endif /* _ARCH_NCI_H */
1629 diff --git a/include/asm-arm/arch-s3c2410/regs-sdi.h b/include/asm-arm/arch-s3c2410/regs-sdi.h
1630 index bb9d30b..4bb1ec5 100644
1631 --- a/include/asm-arm/arch-s3c2410/regs-sdi.h
1632 +++ b/include/asm-arm/arch-s3c2410/regs-sdi.h
1634 #define S3C2410_SDIDCNT (0x30)
1635 #define S3C2410_SDIDSTA (0x34)
1636 #define S3C2410_SDIFSTA (0x38)
1638 #define S3C2410_SDIDATA (0x3C)
1639 +#define S3C2410_SDIDATA_BYTE (0x3C)
1640 #define S3C2410_SDIIMSK (0x40)
1642 +#define S3C2440_SDIDATA (0x40)
1643 +#define S3C2440_SDIDATA_BYTE (0x48)
1644 +#define S3C2440_SDIIMSK (0x3C)
1646 +#define S3C2440_SDICON_SDRESET (1<<8)
1647 +#define S3C2440_SDICON_MMCCLOCK (1<<5)
1648 #define S3C2410_SDICON_BYTEORDER (1<<4)
1649 #define S3C2410_SDICON_SDIOIRQ (1<<3)
1650 #define S3C2410_SDICON_RWAITEN (1<<2)
1652 #define S3C2410_SDICMDCON_LONGRSP (1<<10)
1653 #define S3C2410_SDICMDCON_WAITRSP (1<<9)
1654 #define S3C2410_SDICMDCON_CMDSTART (1<<8)
1655 -#define S3C2410_SDICMDCON_INDEX (0xff)
1656 +#define S3C2410_SDICMDCON_SENDERHOST (1<<6)
1657 +#define S3C2410_SDICMDCON_INDEX (0x3f)
1659 #define S3C2410_SDICMDSTAT_CRCFAIL (1<<12)
1660 #define S3C2410_SDICMDSTAT_CMDSENT (1<<11)
1662 #define S3C2410_SDICMDSTAT_XFERING (1<<8)
1663 #define S3C2410_SDICMDSTAT_INDEX (0xff)
1665 +#define S3C2440_SDIDCON_DS_BYTE (0<<22)
1666 +#define S3C2440_SDIDCON_DS_HALFWORD (1<<22)
1667 +#define S3C2440_SDIDCON_DS_WORD (2<<22)
1668 #define S3C2410_SDIDCON_IRQPERIOD (1<<21)
1669 #define S3C2410_SDIDCON_TXAFTERRESP (1<<20)
1670 #define S3C2410_SDIDCON_RXAFTERCMD (1<<19)
1672 #define S3C2410_SDIDCON_WIDEBUS (1<<16)
1673 #define S3C2410_SDIDCON_DMAEN (1<<15)
1674 #define S3C2410_SDIDCON_STOP (1<<14)
1675 +#define S3C2440_SDIDCON_DATSTART (1<<14)
1676 #define S3C2410_SDIDCON_DATMODE (3<<12)
1677 #define S3C2410_SDIDCON_BLKNUM (0x7ff)
1680 #define S3C2410_SDIDCON_XFER_RXSTART (2<<12)
1681 #define S3C2410_SDIDCON_XFER_TXSTART (3<<12)
1683 +#define S3C2410_SDIDCON_BLKNUM_MASK (0xFFF)
1684 #define S3C2410_SDIDCNT_BLKNUM_SHIFT (12)
1686 #define S3C2410_SDIDSTA_RDYWAITREQ (1<<10)
1688 #define S3C2410_SDIDSTA_TXDATAON (1<<1)
1689 #define S3C2410_SDIDSTA_RXDATAON (1<<0)
1691 +#define S3C2440_SDIFSTA_FIFORESET (1<<16)
1692 +#define S3C2440_SDIFSTA_FIFOFAIL (3<<14) /* 3 is correct (2 bits) */
1693 #define S3C2410_SDIFSTA_TFDET (1<<13)
1694 #define S3C2410_SDIFSTA_RFDET (1<<12)
1695 -#define S3C2410_SDIFSTA_TXHALF (1<<11)
1696 -#define S3C2410_SDIFSTA_TXEMPTY (1<<10)
1697 +#define S3C2410_SDIFSTA_TFHALF (1<<11)
1698 +#define S3C2410_SDIFSTA_TFEMPTY (1<<10)
1699 #define S3C2410_SDIFSTA_RFLAST (1<<9)
1700 #define S3C2410_SDIFSTA_RFFULL (1<<8)
1701 #define S3C2410_SDIFSTA_RFHALF (1<<7)