aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Kleffel <tk@maintech.de>2008-06-30 17:40:24 -0400
committerPierre Ossman <drzeus@drzeus.cx>2008-07-15 08:14:46 -0400
commitbe518018c6b9224c02284fb243207ef741c31ec6 (patch)
tree6fc450ca96ff05dc8904f015000be03a5a2ff2ac
parent8f1934ce784bd8f2eaf06f190526500f7f3f9c74 (diff)
MMC: S3C24XX MMC/SD driver.
This is the latest S3C MMC/SD driver by Thomas Kleffel with cleanups as suggested by AKPM done by Ben Dooks. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Thomas Kleffel <tk@maintech.de> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
-rw-r--r--drivers/mmc/host/Kconfig11
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/s3cmci.c1343
-rw-r--r--drivers/mmc/host/s3cmci.h69
-rw-r--r--include/asm-arm/arch-s3c2410/regs-sdi.h20
5 files changed, 1441 insertions, 4 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f9cbcb891e9..dc88c03662a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -143,3 +143,14 @@ config MMC_SPI
143 143
144 If unsure, or if your system has no SPI master driver, say N. 144 If unsure, or if your system has no SPI master driver, say N.
145 145
146config MMC_S3C
147 tristate "Samsung S3C SD/MMC Card Interface support"
148 depends on ARCH_S3C2410 && MMC
149 help
150 This selects a driver for the MCI interface found in
151 Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
152 If you have a board based on one of those and a MMC/SD
153 slot, say Y or M here.
154
155 If unsure, say N.
156
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 3027250b855..b3e023bf8c7 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -18,4 +18,4 @@ obj-$(CONFIG_MMC_OMAP) += omap.o
18obj-$(CONFIG_MMC_AT91) += at91_mci.o 18obj-$(CONFIG_MMC_AT91) += at91_mci.o
19obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o 19obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
20obj-$(CONFIG_MMC_SPI) += mmc_spi.o 20obj-$(CONFIG_MMC_SPI) += mmc_spi.o
21 21obj-$(CONFIG_MMC_S3C) += s3cmci.o
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
new file mode 100644
index 00000000000..c6a4d3cadf2
--- /dev/null
+++ b/drivers/mmc/host/s3cmci.c
@@ -0,0 +1,1343 @@
1/*
2 * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
3 *
4 * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
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/module.h>
12#include <linux/dma-mapping.h>
13#include <linux/clk.h>
14#include <linux/mmc/host.h>
15#include <linux/platform_device.h>
16#include <linux/irq.h>
17#include <linux/io.h>
18
19#include <asm/dma.h>
20
21#include <asm/arch/regs-sdi.h>
22#include <asm/arch/regs-gpio.h>
23
24#include "s3cmci.h"
25
26#define DRIVER_NAME "s3c-mci"
27
28enum dbg_channels {
29 dbg_err = (1 << 0),
30 dbg_debug = (1 << 1),
31 dbg_info = (1 << 2),
32 dbg_irq = (1 << 3),
33 dbg_sg = (1 << 4),
34 dbg_dma = (1 << 5),
35 dbg_pio = (1 << 6),
36 dbg_fail = (1 << 7),
37 dbg_conf = (1 << 8),
38};
39
40static const int dbgmap_err = dbg_err | dbg_fail;
41static const int dbgmap_info = dbg_info | dbg_conf;
42static const int dbgmap_debug = dbg_debug;
43
44#define dbg(host, channels, args...) \
45 do { \
46 if (dbgmap_err & channels) \
47 dev_err(&host->pdev->dev, args); \
48 else if (dbgmap_info & channels) \
49 dev_info(&host->pdev->dev, args); \
50 else if (dbgmap_debug & channels) \
51 dev_dbg(&host->pdev->dev, args); \
52 } while (0)
53
54#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
55
56static struct s3c2410_dma_client s3cmci_dma_client = {
57 .name = "s3c-mci",
58};
59
60static void finalize_request(struct s3cmci_host *host);
61static void s3cmci_send_request(struct mmc_host *mmc);
62static void s3cmci_reset(struct s3cmci_host *host);
63
64#ifdef CONFIG_MMC_DEBUG
65
66static void dbg_dumpregs(struct s3cmci_host *host, char *prefix)
67{
68 u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize;
69 u32 datcon, datcnt, datsta, fsta, imask;
70
71 con = readl(host->base + S3C2410_SDICON);
72 pre = readl(host->base + S3C2410_SDIPRE);
73 cmdarg = readl(host->base + S3C2410_SDICMDARG);
74 cmdcon = readl(host->base + S3C2410_SDICMDCON);
75 cmdsta = readl(host->base + S3C2410_SDICMDSTAT);
76 r0 = readl(host->base + S3C2410_SDIRSP0);
77 r1 = readl(host->base + S3C2410_SDIRSP1);
78 r2 = readl(host->base + S3C2410_SDIRSP2);
79 r3 = readl(host->base + S3C2410_SDIRSP3);
80 timer = readl(host->base + S3C2410_SDITIMER);
81 bsize = readl(host->base + S3C2410_SDIBSIZE);
82 datcon = readl(host->base + S3C2410_SDIDCON);
83 datcnt = readl(host->base + S3C2410_SDIDCNT);
84 datsta = readl(host->base + S3C2410_SDIDSTA);
85 fsta = readl(host->base + S3C2410_SDIFSTA);
86 imask = readl(host->base + host->sdiimsk);
87
88 dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n",
89 prefix, con, pre, timer);
90
91 dbg(host, dbg_debug, "%s CCON:[%08x] CARG:[%08x] CSTA:[%08x]\n",
92 prefix, cmdcon, cmdarg, cmdsta);
93
94 dbg(host, dbg_debug, "%s DCON:[%08x] FSTA:[%08x]"
95 " DSTA:[%08x] DCNT:[%08x]\n",
96 prefix, datcon, fsta, datsta, datcnt);
97
98 dbg(host, dbg_debug, "%s R0:[%08x] R1:[%08x]"
99 " R2:[%08x] R3:[%08x]\n",
100 prefix, r0, r1, r2, r3);
101}
102
103static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd,
104 int stop)
105{
106 snprintf(host->dbgmsg_cmd, 300,
107 "#%u%s op:%i arg:0x%08x flags:0x08%x retries:%u",
108 host->ccnt, (stop ? " (STOP)" : ""),
109 cmd->opcode, cmd->arg, cmd->flags, cmd->retries);
110
111 if (cmd->data) {
112 snprintf(host->dbgmsg_dat, 300,
113 "#%u bsize:%u blocks:%u bytes:%u",
114 host->dcnt, cmd->data->blksz,
115 cmd->data->blocks,
116 cmd->data->blocks * cmd->data->blksz);
117 } else {
118 host->dbgmsg_dat[0] = '\0';
119 }
120}
121
122static void dbg_dumpcmd(struct s3cmci_host *host, struct mmc_command *cmd,
123 int fail)
124{
125 unsigned int dbglvl = fail ? dbg_fail : dbg_debug;
126
127 if (!cmd)
128 return;
129
130 if (cmd->error == 0) {
131 dbg(host, dbglvl, "CMD[OK] %s R0:0x%08x\n",
132 host->dbgmsg_cmd, cmd->resp[0]);
133 } else {
134 dbg(host, dbglvl, "CMD[ERR %i] %s Status:%s\n",
135 cmd->error, host->dbgmsg_cmd, host->status);
136 }
137
138 if (!cmd->data)
139 return;
140
141 if (cmd->data->error == 0) {
142 dbg(host, dbglvl, "DAT[OK] %s\n", host->dbgmsg_dat);
143 } else {
144 dbg(host, dbglvl, "DAT[ERR %i] %s DCNT:0x%08x\n",
145 cmd->data->error, host->dbgmsg_dat,
146 readl(host->base + S3C2410_SDIDCNT));
147 }
148}
149#else
150static void dbg_dumpcmd(struct s3cmci_host *host,
151 struct mmc_command *cmd, int fail) { }
152
153static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd,
154 int stop) { }
155
156static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) { }
157
158#endif /* CONFIG_MMC_DEBUG */
159
160static inline u32 enable_imask(struct s3cmci_host *host, u32 imask)
161{
162 u32 newmask;
163
164 newmask = readl(host->base + host->sdiimsk);
165 newmask |= imask;
166
167 writel(newmask, host->base + host->sdiimsk);
168
169 return newmask;
170}
171
172static inline u32 disable_imask(struct s3cmci_host *host, u32 imask)
173{
174 u32 newmask;
175
176 newmask = readl(host->base + host->sdiimsk);
177 newmask &= ~imask;
178
179 writel(newmask, host->base + host->sdiimsk);
180
181 return newmask;
182}
183
184static inline void clear_imask(struct s3cmci_host *host)
185{
186 writel(0, host->base + host->sdiimsk);
187}
188
189static inline int get_data_buffer(struct s3cmci_host *host,
190 u32 *words, u32 **pointer)
191{
192 struct scatterlist *sg;
193
194 if (host->pio_active == XFER_NONE)
195 return -EINVAL;
196
197 if ((!host->mrq) || (!host->mrq->data))
198 return -EINVAL;
199
200 if (host->pio_sgptr >= host->mrq->data->sg_len) {
201 dbg(host, dbg_debug, "no more buffers (%i/%i)\n",
202 host->pio_sgptr, host->mrq->data->sg_len);
203 return -EBUSY;
204 }
205 sg = &host->mrq->data->sg[host->pio_sgptr];
206
207 *words = sg->length >> 2;
208 *pointer = sg_virt(sg);
209
210 host->pio_sgptr++;
211
212 dbg(host, dbg_sg, "new buffer (%i/%i)\n",
213 host->pio_sgptr, host->mrq->data->sg_len);
214
215 return 0;
216}
217
218static inline u32 fifo_count(struct s3cmci_host *host)
219{
220 u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
221
222 fifostat &= S3C2410_SDIFSTA_COUNTMASK;
223 return fifostat >> 2;
224}
225
226static inline u32 fifo_free(struct s3cmci_host *host)
227{
228 u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
229
230 fifostat &= S3C2410_SDIFSTA_COUNTMASK;
231 return (63 - fifostat) >> 2;
232}
233
234static void do_pio_read(struct s3cmci_host *host)
235{
236 int res;
237 u32 fifo;
238 void __iomem *from_ptr;
239
240 /* write real prescaler to host, it might be set slow to fix */
241 writel(host->prescaler, host->base + S3C2410_SDIPRE);
242
243 from_ptr = host->base + host->sdidata;
244
245 while ((fifo = fifo_count(host))) {
246 if (!host->pio_words) {
247 res = get_data_buffer(host, &host->pio_words,
248 &host->pio_ptr);
249 if (res) {
250 host->pio_active = XFER_NONE;
251 host->complete_what = COMPLETION_FINALIZE;
252
253 dbg(host, dbg_pio, "pio_read(): "
254 "complete (no more data).\n");
255 return;
256 }
257
258 dbg(host, dbg_pio,
259 "pio_read(): new target: [%i]@[%p]\n",
260 host->pio_words, host->pio_ptr);
261 }
262
263 dbg(host, dbg_pio,
264 "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n",
265 fifo, host->pio_words,
266 readl(host->base + S3C2410_SDIDCNT));
267
268 if (fifo > host->pio_words)
269 fifo = host->pio_words;
270
271 host->pio_words -= fifo;
272 host->pio_count += fifo;
273
274 while (fifo--)
275 *(host->pio_ptr++) = readl(from_ptr);
276 }
277
278 if (!host->pio_words) {
279 res = get_data_buffer(host, &host->pio_words, &host->pio_ptr);
280 if (res) {
281 dbg(host, dbg_pio,
282 "pio_read(): complete (no more buffers).\n");
283 host->pio_active = XFER_NONE;
284 host->complete_what = COMPLETION_FINALIZE;
285
286 return;
287 }
288 }
289
290 enable_imask(host,
291 S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST);
292}
293
294static void do_pio_write(struct s3cmci_host *host)
295{
296 void __iomem *to_ptr;
297 int res;
298 u32 fifo;
299
300 to_ptr = host->base + host->sdidata;
301
302 while ((fifo = fifo_free(host))) {
303 if (!host->pio_words) {
304 res = get_data_buffer(host, &host->pio_words,
305 &host->pio_ptr);
306 if (res) {
307 dbg(host, dbg_pio,
308 "pio_write(): complete (no more data).\n");
309 host->pio_active = XFER_NONE;
310
311 return;
312 }
313
314 dbg(host, dbg_pio,
315 "pio_write(): new source: [%i]@[%p]\n",
316 host->pio_words, host->pio_ptr);
317
318 }
319
320 if (fifo > host->pio_words)
321 fifo = host->pio_words;
322
323 host->pio_words -= fifo;
324 host->pio_count += fifo;
325
326 while (fifo--)
327 writel(*(host->pio_ptr++), to_ptr);
328 }
329
330 enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
331}
332
333static void pio_tasklet(unsigned long data)
334{
335 struct s3cmci_host *host = (struct s3cmci_host *) data;
336
337
338 if (host->pio_active == XFER_WRITE)
339 do_pio_write(host);
340
341 if (host->pio_active == XFER_READ)
342 do_pio_read(host);
343
344 if (host->complete_what == COMPLETION_FINALIZE) {
345 clear_imask(host);
346 if (host->pio_active != XFER_NONE) {
347 dbg(host, dbg_err, "unfinished %s "
348 "- pio_count:[%u] pio_words:[%u]\n",
349 (host->pio_active == XFER_READ) ? "read" : "write",
350 host->pio_count, host->pio_words);
351
352 host->mrq->data->error = -EINVAL;
353 }
354
355 disable_irq(host->irq);
356 finalize_request(host);
357 }
358}
359
360/*
361 * ISR for SDI Interface IRQ
362 * Communication between driver and ISR works as follows:
363 * host->mrq points to current request
364 * host->complete_what Indicates when the request is considered done
365 * COMPLETION_CMDSENT when the command was sent
366 * COMPLETION_RSPFIN when a response was received
367 * COMPLETION_XFERFINISH when the data transfer is finished
368 * COMPLETION_XFERFINISH_RSPFIN both of the above.
369 * host->complete_request is the completion-object the driver waits for
370 *
371 * 1) Driver sets up host->mrq and host->complete_what
372 * 2) Driver prepares the transfer
373 * 3) Driver enables interrupts
374 * 4) Driver starts transfer
375 * 5) Driver waits for host->complete_rquest
376 * 6) ISR checks for request status (errors and success)
377 * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error
378 * 7) ISR completes host->complete_request
379 * 8) ISR disables interrupts
380 * 9) Driver wakes up and takes care of the request
381 *
382 * Note: "->error"-fields are expected to be set to 0 before the request
383 * was issued by mmc.c - therefore they are only set, when an error
384 * contition comes up
385 */
386
387static irqreturn_t s3cmci_irq(int irq, void *dev_id)
388{
389 struct s3cmci_host *host = dev_id;
390 struct mmc_command *cmd;
391 u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;
392 u32 mci_cclear, mci_dclear;
393 unsigned long iflags;
394
395 spin_lock_irqsave(&host->complete_lock, iflags);
396
397 mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
398 mci_dsta = readl(host->base + S3C2410_SDIDSTA);
399 mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
400 mci_fsta = readl(host->base + S3C2410_SDIFSTA);
401 mci_imsk = readl(host->base + host->sdiimsk);
402 mci_cclear = 0;
403 mci_dclear = 0;
404
405 if ((host->complete_what == COMPLETION_NONE) ||
406 (host->complete_what == COMPLETION_FINALIZE)) {
407 host->status = "nothing to complete";
408 clear_imask(host);
409 goto irq_out;
410 }
411
412 if (!host->mrq) {
413 host->status = "no active mrq";
414 clear_imask(host);
415 goto irq_out;
416 }
417
418 cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd;
419
420 if (!cmd) {
421 host->status = "no active cmd";
422 clear_imask(host);
423 goto irq_out;
424 }
425
426 if (!host->dodma) {
427 if ((host->pio_active == XFER_WRITE) &&
428 (mci_fsta & S3C2410_SDIFSTA_TFDET)) {
429
430 disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
431 tasklet_schedule(&host->pio_tasklet);
432 host->status = "pio tx";
433 }
434
435 if ((host->pio_active == XFER_READ) &&
436 (mci_fsta & S3C2410_SDIFSTA_RFDET)) {
437
438 disable_imask(host,
439 S3C2410_SDIIMSK_RXFIFOHALF |
440 S3C2410_SDIIMSK_RXFIFOLAST);
441
442 tasklet_schedule(&host->pio_tasklet);
443 host->status = "pio rx";
444 }
445 }
446
447 if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
448 cmd->error = -ETIMEDOUT;
449 host->status = "error: command timeout";
450 goto fail_transfer;
451 }
452
453 if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {
454 if (host->complete_what == COMPLETION_CMDSENT) {
455 host->status = "ok: command sent";
456 goto close_transfer;
457 }
458
459 mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
460 }
461
462 if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {
463 if (cmd->flags & MMC_RSP_CRC) {
464 cmd->error = -EILSEQ;
465 host->status = "error: bad command crc";
466 goto fail_transfer;
467 }
468
469 mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;
470 }
471
472 if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) {
473 if (host->complete_what == COMPLETION_RSPFIN) {
474 host->status = "ok: command response received";
475 goto close_transfer;
476 }
477
478 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
479 host->complete_what = COMPLETION_XFERFINISH;
480
481 mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;
482 }
483
484 /* errors handled after this point are only relevant
485 when a data transfer is in progress */
486
487 if (!cmd->data)
488 goto clear_status_bits;
489
490 /* Check for FIFO failure */
491 if (host->is2440) {
492 if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {
493 host->mrq->data->error = -EILSEQ;
494 host->status = "error: 2440 fifo failure";
495 goto fail_transfer;
496 }
497 } else {
498 if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {
499 cmd->data->error = -EILSEQ;
500 host->status = "error: fifo failure";
501 goto fail_transfer;
502 }
503 }
504
505 if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {
506 cmd->data->error = -EILSEQ;
507 host->status = "error: bad data crc (outgoing)";
508 goto fail_transfer;
509 }
510
511 if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {
512 cmd->data->error = -EILSEQ;
513 host->status = "error: bad data crc (incoming)";
514 goto fail_transfer;
515 }
516
517 if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {
518 cmd->data->error = -ETIMEDOUT;
519 host->status = "error: data timeout";
520 goto fail_transfer;
521 }
522
523 if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {
524 if (host->complete_what == COMPLETION_XFERFINISH) {
525 host->status = "ok: data transfer completed";
526 goto close_transfer;
527 }
528
529 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
530 host->complete_what = COMPLETION_RSPFIN;
531
532 mci_dclear |= S3C2410_SDIDSTA_XFERFINISH;
533 }
534
535clear_status_bits:
536 writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);
537 writel(mci_dclear, host->base + S3C2410_SDIDSTA);
538
539 goto irq_out;
540
541fail_transfer:
542 host->pio_active = XFER_NONE;
543
544close_transfer:
545 host->complete_what = COMPLETION_FINALIZE;
546
547 clear_imask(host);
548 tasklet_schedule(&host->pio_tasklet);
549
550 goto irq_out;
551
552irq_out:
553 dbg(host, dbg_irq,
554 "csta:0x%08x dsta:0x%08x fsta:0x%08x dcnt:0x%08x status:%s.\n",
555 mci_csta, mci_dsta, mci_fsta, mci_dcnt, host->status);
556
557 spin_unlock_irqrestore(&host->complete_lock, iflags);
558 return IRQ_HANDLED;
559
560}
561
562/*
563 * ISR for the CardDetect Pin
564*/
565
566static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
567{
568 struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
569
570 dbg(host, dbg_irq, "card detect\n");
571
572 mmc_detect_change(host->mmc, 500);
573
574 return IRQ_HANDLED;
575}
576
577void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, void *buf_id,
578 int size, enum s3c2410_dma_buffresult result)
579{
580 struct s3cmci_host *host = buf_id;
581 unsigned long iflags;
582 u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;
583
584 mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
585 mci_dsta = readl(host->base + S3C2410_SDIDSTA);
586 mci_fsta = readl(host->base + S3C2410_SDIFSTA);
587 mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
588
589 BUG_ON(!host->mrq);
590 BUG_ON(!host->mrq->data);
591 BUG_ON(!host->dmatogo);
592
593 spin_lock_irqsave(&host->complete_lock, iflags);
594
595 if (result != S3C2410_RES_OK) {
596 dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
597 "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",
598 mci_csta, mci_dsta, mci_fsta,
599 mci_dcnt, result, host->dmatogo);
600
601 goto fail_request;
602 }
603
604 host->dmatogo--;
605 if (host->dmatogo) {
606 dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "
607 "DCNT:[%08x] toGo:%u\n",
608 size, mci_dsta, mci_dcnt, host->dmatogo);
609
610 goto out;
611 }
612
613 dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
614 size, mci_dsta, mci_dcnt);
615
616 host->complete_what = COMPLETION_FINALIZE;
617
618out:
619 tasklet_schedule(&host->pio_tasklet);
620 spin_unlock_irqrestore(&host->complete_lock, iflags);
621 return;
622
623
624fail_request:
625 host->mrq->data->error = -EINVAL;
626 host->complete_what = COMPLETION_FINALIZE;
627 writel(0, host->base + host->sdiimsk);
628 goto out;
629
630}
631
632static void finalize_request(struct s3cmci_host *host)
633{
634 struct mmc_request *mrq = host->mrq;
635 struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
636 int debug_as_failure = 0;
637
638 if (host->complete_what != COMPLETION_FINALIZE)
639 return;
640
641 if (!mrq)
642 return;
643
644 if (cmd->data && (cmd->error == 0) &&
645 (cmd->data->error == 0)) {
646 if (host->dodma && (!host->dma_complete)) {
647 dbg(host, dbg_dma, "DMA Missing!\n");
648 return;
649 }
650 }
651
652 /* Read response from controller. */
653 cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);
654 cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);
655 cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);
656 cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
657
658 writel(host->prescaler, host->base + S3C2410_SDIPRE);
659
660 if (cmd->error)
661 debug_as_failure = 1;
662
663 if (cmd->data && cmd->data->error)
664 debug_as_failure = 1;
665
666 dbg_dumpcmd(host, cmd, debug_as_failure);
667
668 /* Cleanup controller */
669 writel(0, host->base + S3C2410_SDICMDARG);
670 writel(0, host->base + S3C2410_SDIDCON);
671 writel(0, host->base + S3C2410_SDICMDCON);
672 writel(0, host->base + host->sdiimsk);
673
674 if (cmd->data && cmd->error)
675 cmd->data->error = cmd->error;
676
677 if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {
678 host->cmd_is_stop = 1;
679 s3cmci_send_request(host->mmc);
680 return;
681 }
682
683 /* If we have no data transfer we are finished here */
684 if (!mrq->data)
685 goto request_done;
686
687 /* Calulate the amout of bytes transfer if there was no error */
688 if (mrq->data->error == 0) {
689 mrq->data->bytes_xfered =
690 (mrq->data->blocks * mrq->data->blksz);
691 } else {
692 mrq->data->bytes_xfered = 0;
693 }
694
695 /* If we had an error while transfering data we flush the
696 * DMA channel and the fifo to clear out any garbage. */
697 if (mrq->data->error != 0) {
698 if (host->dodma)
699 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
700
701 if (host->is2440) {
702 /* Clear failure register and reset fifo. */
703 writel(S3C2440_SDIFSTA_FIFORESET |
704 S3C2440_SDIFSTA_FIFOFAIL,
705 host->base + S3C2410_SDIFSTA);
706 } else {
707 u32 mci_con;
708
709 /* reset fifo */
710 mci_con = readl(host->base + S3C2410_SDICON);
711 mci_con |= S3C2410_SDICON_FIFORESET;
712
713 writel(mci_con, host->base + S3C2410_SDICON);
714 }
715 }
716
717request_done:
718 host->complete_what = COMPLETION_NONE;
719 host->mrq = NULL;
720 mmc_request_done(host->mmc, mrq);
721}
722
723
724void s3cmci_dma_setup(struct s3cmci_host *host, enum s3c2410_dmasrc source)
725{
726 static enum s3c2410_dmasrc last_source = -1;
727 static int setup_ok;
728
729 if (last_source == source)
730 return;
731
732 last_source = source;
733
734 s3c2410_dma_devconfig(host->dma, source, 3,
735 host->mem->start + host->sdidata);
736
737 if (!setup_ok) {
738 s3c2410_dma_config(host->dma, 4,
739 (S3C2410_DCON_HWTRIG | S3C2410_DCON_CH0_SDI));
740 s3c2410_dma_set_buffdone_fn(host->dma,
741 s3cmci_dma_done_callback);
742 s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
743 setup_ok = 1;
744 }
745}
746
747static void s3cmci_send_command(struct s3cmci_host *host,
748 struct mmc_command *cmd)
749{
750 u32 ccon, imsk;
751
752 imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |
753 S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT |
754 S3C2410_SDIIMSK_RESPONSECRC;
755
756 enable_imask(host, imsk);
757
758 if (cmd->data)
759 host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
760 else if (cmd->flags & MMC_RSP_PRESENT)
761 host->complete_what = COMPLETION_RSPFIN;
762 else
763 host->complete_what = COMPLETION_CMDSENT;
764
765 writel(cmd->arg, host->base + S3C2410_SDICMDARG);
766
767 ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX;
768 ccon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;
769
770 if (cmd->flags & MMC_RSP_PRESENT)
771 ccon |= S3C2410_SDICMDCON_WAITRSP;
772
773 if (cmd->flags & MMC_RSP_136)
774 ccon |= S3C2410_SDICMDCON_LONGRSP;
775
776 writel(ccon, host->base + S3C2410_SDICMDCON);
777}
778
779static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
780{
781 u32 dcon, imsk, stoptries = 3;
782
783 /* write DCON register */
784
785 if (!data) {
786 writel(0, host->base + S3C2410_SDIDCON);
787 return 0;
788 }
789
790 while (readl(host->base + S3C2410_SDIDSTA) &
791 (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {
792
793 dbg(host, dbg_err,
794 "mci_setup_data() transfer stillin progress.\n");
795
796 writel(0, host->base + S3C2410_SDIDCON);
797 s3cmci_reset(host);
798
799 if ((stoptries--) == 0) {
800 dbg_dumpregs(host, "DRF");
801 return -EINVAL;
802 }
803 }
804
805 dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;
806
807 if (host->dodma)
808 dcon |= S3C2410_SDIDCON_DMAEN;
809
810 if (host->bus_width == MMC_BUS_WIDTH_4)
811 dcon |= S3C2410_SDIDCON_WIDEBUS;
812
813 if (!(data->flags & MMC_DATA_STREAM))
814 dcon |= S3C2410_SDIDCON_BLOCKMODE;
815
816 if (data->flags & MMC_DATA_WRITE) {
817 dcon |= S3C2410_SDIDCON_TXAFTERRESP;
818 dcon |= S3C2410_SDIDCON_XFER_TXSTART;
819 }
820
821 if (data->flags & MMC_DATA_READ) {
822 dcon |= S3C2410_SDIDCON_RXAFTERCMD;
823 dcon |= S3C2410_SDIDCON_XFER_RXSTART;
824 }
825
826 if (host->is2440) {
827 dcon |= S3C2440_SDIDCON_DS_WORD;
828 dcon |= S3C2440_SDIDCON_DATSTART;
829 }
830
831 writel(dcon, host->base + S3C2410_SDIDCON);
832
833 /* write BSIZE register */
834
835 writel(data->blksz, host->base + S3C2410_SDIBSIZE);
836
837 /* add to IMASK register */
838 imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
839 S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;
840
841 enable_imask(host, imsk);
842
843 /* write TIMER register */
844
845 if (host->is2440) {
846 writel(0x007FFFFF, host->base + S3C2410_SDITIMER);
847 } else {
848 writel(0x0000FFFF, host->base + S3C2410_SDITIMER);
849
850 /* FIX: set slow clock to prevent timeouts on read */
851 if (data->flags & MMC_DATA_READ)
852 writel(0xFF, host->base + S3C2410_SDIPRE);
853 }
854
855 return 0;
856}
857
858#define BOTH_DIR (MMC_DATA_WRITE | MMC_DATA_READ)
859
860static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
861{
862 int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
863
864 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
865
866 host->pio_sgptr = 0;
867 host->pio_words = 0;
868 host->pio_count = 0;
869 host->pio_active = rw ? XFER_WRITE : XFER_READ;
870
871 if (rw) {
872 do_pio_write(host);
873 enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
874 } else {
875 enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF
876 | S3C2410_SDIIMSK_RXFIFOLAST);
877 }
878
879 return 0;
880}
881
882static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
883{
884 int dma_len, i;
885 int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
886
887 BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
888
889 s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW);
890 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
891
892 dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
893 (rw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
894
895 if (dma_len == 0)
896 return -ENOMEM;
897
898 host->dma_complete = 0;
899 host->dmatogo = dma_len;
900
901 for (i = 0; i < dma_len; i++) {
902 int res;
903
904 dbg(host, dbg_dma, "enqueue %i:%u@%u\n", i,
905 sg_dma_address(&data->sg[i]),
906 sg_dma_len(&data->sg[i]));
907
908 res = s3c2410_dma_enqueue(host->dma, (void *) host,
909 sg_dma_address(&data->sg[i]),
910 sg_dma_len(&data->sg[i]));
911
912 if (res) {
913 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
914 return -EBUSY;
915 }
916 }
917
918 s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START);
919
920 return 0;
921}
922
923static void s3cmci_send_request(struct mmc_host *mmc)
924{
925 struct s3cmci_host *host = mmc_priv(mmc);
926 struct mmc_request *mrq = host->mrq;
927 struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
928
929 host->ccnt++;
930 prepare_dbgmsg(host, cmd, host->cmd_is_stop);
931
932 /* Clear command, data and fifo status registers
933 Fifo clear only necessary on 2440, but doesn't hurt on 2410
934 */
935 writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
936 writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
937 writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);
938
939 if (cmd->data) {
940 int res = s3cmci_setup_data(host, cmd->data);
941
942 host->dcnt++;
943
944 if (res) {
945 cmd->error = -EINVAL;
946 cmd->data->error = -EINVAL;
947
948 mmc_request_done(mmc, mrq);
949 return;
950 }
951
952 if (host->dodma)
953 res = s3cmci_prepare_dma(host, cmd->data);
954 else
955 res = s3cmci_prepare_pio(host, cmd->data);
956
957 if (res) {
958 cmd->error = res;
959 cmd->data->error = res;
960
961 mmc_request_done(mmc, mrq);
962 return;
963 }
964 }
965
966 /* Send command */
967 s3cmci_send_command(host, cmd);
968
969 /* Enable Interrupt */
970 enable_irq(host->irq);
971}
972
973static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
974{
975 struct s3cmci_host *host = mmc_priv(mmc);
976
977 host->status = "mmc request";
978 host->cmd_is_stop = 0;
979 host->mrq = mrq;
980
981 s3cmci_send_request(mmc);
982}
983
984static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
985{
986 struct s3cmci_host *host = mmc_priv(mmc);
987 u32 mci_psc, mci_con;
988
989 /* Set the power state */
990
991 mci_con = readl(host->base + S3C2410_SDICON);
992
993 switch (ios->power_mode) {
994 case MMC_POWER_ON:
995 case MMC_POWER_UP:
996 s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK);
997 s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD);
998 s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0);
999 s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
1000 s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2);
1001 s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3);
1002
1003 if (!host->is2440)
1004 mci_con |= S3C2410_SDICON_FIFORESET;
1005
1006 break;
1007
1008 case MMC_POWER_OFF:
1009 default:
1010 s3c2410_gpio_setpin(S3C2410_GPE5, 0);
1011 s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);
1012
1013 if (host->is2440)
1014 mci_con |= S3C2440_SDICON_SDRESET;
1015
1016 break;
1017 }
1018
1019 /* Set clock */
1020 for (mci_psc = 0; mci_psc < 255; mci_psc++) {
1021 host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
1022
1023 if (host->real_rate <= ios->clock)
1024 break;
1025 }
1026
1027 if (mci_psc > 255)
1028 mci_psc = 255;
1029
1030 host->prescaler = mci_psc;
1031 writel(host->prescaler, host->base + S3C2410_SDIPRE);
1032
1033 /* If requested clock is 0, real_rate will be 0, too */
1034 if (ios->clock == 0)
1035 host->real_rate = 0;
1036
1037 /* Set CLOCK_ENABLE */
1038 if (ios->clock)
1039 mci_con |= S3C2410_SDICON_CLOCKTYPE;
1040 else
1041 mci_con &= ~S3C2410_SDICON_CLOCKTYPE;
1042
1043 writel(mci_con, host->base + S3C2410_SDICON);
1044
1045 if ((ios->power_mode == MMC_POWER_ON) ||
1046 (ios->power_mode == MMC_POWER_UP)) {
1047 dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
1048 host->real_rate/1000, ios->clock/1000);
1049 } else {
1050 dbg(host, dbg_conf, "powered down.\n");
1051 }
1052
1053 host->bus_width = ios->bus_width;
1054}
1055
1056static void s3cmci_reset(struct s3cmci_host *host)
1057{
1058 u32 con = readl(host->base + S3C2410_SDICON);
1059
1060 con |= S3C2440_SDICON_SDRESET;
1061 writel(con, host->base + S3C2410_SDICON);
1062}
1063
1064static struct mmc_host_ops s3cmci_ops = {
1065 .request = s3cmci_request,
1066 .set_ios = s3cmci_set_ios,
1067};
1068
1069static int __devinit s3cmci_probe(struct platform_device *pdev, int is2440)
1070{
1071 struct s3cmci_host *host;
1072 struct mmc_host *mmc;
1073 int ret;
1074
1075 mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);
1076 if (!mmc) {
1077 ret = -ENOMEM;
1078 goto probe_out;
1079 }
1080
1081 host = mmc_priv(mmc);
1082 host->mmc = mmc;
1083 host->pdev = pdev;
1084 host->is2440 = is2440;
1085
1086 spin_lock_init(&host->complete_lock);
1087 tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
1088
1089 if (is2440) {
1090 host->sdiimsk = S3C2440_SDIIMSK;
1091 host->sdidata = S3C2440_SDIDATA;
1092 host->clk_div = 1;
1093 } else {
1094 host->sdiimsk = S3C2410_SDIIMSK;
1095 host->sdidata = S3C2410_SDIDATA;
1096 host->clk_div = 2;
1097 }
1098
1099 host->dodma = 0;
1100 host->complete_what = COMPLETION_NONE;
1101 host->pio_active = XFER_NONE;
1102
1103 host->dma = S3CMCI_DMA;
1104 host->irq_cd = IRQ_EINT2;
1105
1106 host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1107 if (!host->mem) {
1108 dev_err(&pdev->dev,
1109 "failed to get io memory region resouce.\n");
1110
1111 ret = -ENOENT;
1112 goto probe_free_host;
1113 }
1114
1115 host->mem = request_mem_region(host->mem->start,
1116 RESSIZE(host->mem), pdev->name);
1117
1118 if (!host->mem) {
1119 dev_err(&pdev->dev, "failed to request io memory region.\n");
1120 ret = -ENOENT;
1121 goto probe_free_host;
1122 }
1123
1124 host->base = ioremap(host->mem->start, RESSIZE(host->mem));
1125 if (host->base == 0) {
1126 dev_err(&pdev->dev, "failed to ioremap() io memory region.\n");
1127 ret = -EINVAL;
1128 goto probe_free_mem_region;
1129 }
1130
1131 host->irq = platform_get_irq(pdev, 0);
1132 if (host->irq == 0) {
1133 dev_err(&pdev->dev, "failed to get interrupt resouce.\n");
1134 ret = -EINVAL;
1135 goto probe_iounmap;
1136 }
1137
1138 if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
1139 dev_err(&pdev->dev, "failed to request mci interrupt.\n");
1140 ret = -ENOENT;
1141 goto probe_iounmap;
1142 }
1143
1144 /* We get spurious interrupts even when we have set the IMSK
1145 * register to ignore everything, so use disable_irq() to make
1146 * ensure we don't lock the system with un-serviceable requests. */
1147
1148 disable_irq(host->irq);
1149
1150 s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
1151 set_irq_type(host->irq_cd, IRQT_BOTHEDGE);
1152
1153 if (request_irq(host->irq_cd, s3cmci_irq_cd, 0, DRIVER_NAME, host)) {
1154 dev_err(&pdev->dev,
1155 "failed to request card detect interrupt.\n");
1156 ret = -ENOENT;
1157 goto probe_free_irq;
1158 }
1159
1160 if (s3c2410_dma_request(S3CMCI_DMA, &s3cmci_dma_client, NULL)) {
1161 dev_err(&pdev->dev, "unable to get DMA channel.\n");
1162 ret = -EBUSY;
1163 goto probe_free_irq_cd;
1164 }
1165
1166 host->clk = clk_get(&pdev->dev, "sdi");
1167 if (IS_ERR(host->clk)) {
1168 dev_err(&pdev->dev, "failed to find clock source.\n");
1169 ret = PTR_ERR(host->clk);
1170 host->clk = NULL;
1171 goto probe_free_host;
1172 }
1173
1174 ret = clk_enable(host->clk);
1175 if (ret) {
1176 dev_err(&pdev->dev, "failed to enable clock source.\n");
1177 goto clk_free;
1178 }
1179
1180 host->clk_rate = clk_get_rate(host->clk);
1181
1182 mmc->ops = &s3cmci_ops;
1183 mmc->ocr_avail = MMC_VDD_32_33;
1184 mmc->caps = MMC_CAP_4_BIT_DATA;
1185 mmc->f_min = host->clk_rate / (host->clk_div * 256);
1186 mmc->f_max = host->clk_rate / host->clk_div;
1187
1188 mmc->max_blk_count = 4095;
1189 mmc->max_blk_size = 4095;
1190 mmc->max_req_size = 4095 * 512;
1191 mmc->max_seg_size = mmc->max_req_size;
1192
1193 mmc->max_phys_segs = 128;
1194 mmc->max_hw_segs = 128;
1195
1196 dbg(host, dbg_debug,
1197 "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",
1198 (host->is2440?"2440":""),
1199 host->base, host->irq, host->irq_cd, host->dma);
1200
1201 ret = mmc_add_host(mmc);
1202 if (ret) {
1203 dev_err(&pdev->dev, "failed to add mmc host.\n");
1204 goto free_dmabuf;
1205 }
1206
1207 platform_set_drvdata(pdev, mmc);
1208 dev_info(&pdev->dev, "initialisation done.\n");
1209
1210 return 0;
1211
1212 free_dmabuf:
1213 clk_disable(host->clk);
1214
1215 clk_free:
1216 clk_put(host->clk);
1217
1218 probe_free_irq_cd:
1219 free_irq(host->irq_cd, host);
1220
1221 probe_free_irq:
1222 free_irq(host->irq, host);
1223
1224 probe_iounmap:
1225 iounmap(host->base);
1226
1227 probe_free_mem_region:
1228 release_mem_region(host->mem->start, RESSIZE(host->mem));
1229
1230 probe_free_host:
1231 mmc_free_host(mmc);
1232 probe_out:
1233 return ret;
1234}
1235
1236static int __devexit s3cmci_remove(struct platform_device *pdev)
1237{
1238 struct mmc_host *mmc = platform_get_drvdata(pdev);
1239 struct s3cmci_host *host = mmc_priv(mmc);
1240
1241 mmc_remove_host(mmc);
1242
1243 clk_disable(host->clk);
1244 clk_put(host->clk);
1245
1246 tasklet_disable(&host->pio_tasklet);
1247
1248 free_irq(host->irq_cd, host);
1249 free_irq(host->irq, host);
1250
1251 iounmap(host->base);
1252 release_mem_region(host->mem->start, RESSIZE(host->mem));
1253
1254 mmc_free_host(mmc);
1255 return 0;
1256}
1257
1258static int __devinit s3cmci_probe_2410(struct platform_device *dev)
1259{
1260 return s3cmci_probe(dev, 0);
1261}
1262
1263static int __devinit s3cmci_probe_2412(struct platform_device *dev)
1264{
1265 return s3cmci_probe(dev, 1);
1266}
1267
1268static int __devinit s3cmci_probe_2440(struct platform_device *dev)
1269{
1270 return s3cmci_probe(dev, 1);
1271}
1272
1273#ifdef CONFIG_PM
1274
1275static int s3cmci_suspend(struct platform_device *dev, pm_message_t state)
1276{
1277 struct mmc_host *mmc = platform_get_drvdata(dev);
1278
1279 return mmc_suspend_host(mmc, state);
1280}
1281
1282static int s3cmci_resume(struct platform_device *dev)
1283{
1284 struct mmc_host *mmc = platform_get_drvdata(dev);
1285
1286 return mmc_resume_host(mmc);
1287}
1288
1289#else /* CONFIG_PM */
1290#define s3cmci_suspend NULL
1291#define s3cmci_resume NULL
1292#endif /* CONFIG_PM */
1293
1294
1295static struct platform_driver s3cmci_driver_2410 = {
1296 .driver.name = "s3c2410-sdi",
1297 .driver.owner = THIS_MODULE,
1298 .probe = s3cmci_probe_2410,
1299 .remove = __devexit_p(s3cmci_remove),
1300 .suspend = s3cmci_suspend,
1301 .resume = s3cmci_resume,
1302};
1303
1304static struct platform_driver s3cmci_driver_2412 = {
1305 .driver.name = "s3c2412-sdi",
1306 .driver.owner = THIS_MODULE,
1307 .probe = s3cmci_probe_2412,
1308 .remove = __devexit_p(s3cmci_remove),
1309 .suspend = s3cmci_suspend,
1310 .resume = s3cmci_resume,
1311};
1312
1313static struct platform_driver s3cmci_driver_2440 = {
1314 .driver.name = "s3c2440-sdi",
1315 .driver.owner = THIS_MODULE,
1316 .probe = s3cmci_probe_2440,
1317 .remove = __devexit_p(s3cmci_remove),
1318 .suspend = s3cmci_suspend,
1319 .resume = s3cmci_resume,
1320};
1321
1322
1323static int __init s3cmci_init(void)
1324{
1325 platform_driver_register(&s3cmci_driver_2410);
1326 platform_driver_register(&s3cmci_driver_2412);
1327 platform_driver_register(&s3cmci_driver_2440);
1328 return 0;
1329}
1330
1331static void __exit s3cmci_exit(void)
1332{
1333 platform_driver_unregister(&s3cmci_driver_2410);
1334 platform_driver_unregister(&s3cmci_driver_2412);
1335 platform_driver_unregister(&s3cmci_driver_2440);
1336}
1337
1338module_init(s3cmci_init);
1339module_exit(s3cmci_exit);
1340
1341MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
1342MODULE_LICENSE("GPL v2");
1343MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>");
diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
new file mode 100644
index 00000000000..90b8af7d8a4
--- /dev/null
+++ b/drivers/mmc/host/s3cmci.h
@@ -0,0 +1,69 @@
1/*
2 * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
3 *
4 * Copyright (C) 2004-2006 Thomas Kleffel, 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/* FIXME: DMA Resource management ?! */
12#define S3CMCI_DMA 0
13
14enum s3cmci_waitfor {
15 COMPLETION_NONE,
16 COMPLETION_FINALIZE,
17 COMPLETION_CMDSENT,
18 COMPLETION_RSPFIN,
19 COMPLETION_XFERFINISH,
20 COMPLETION_XFERFINISH_RSPFIN,
21};
22
23struct s3cmci_host {
24 struct platform_device *pdev;
25 struct mmc_host *mmc;
26 struct resource *mem;
27 struct clk *clk;
28 void __iomem *base;
29 int irq;
30 int irq_cd;
31 int dma;
32
33 unsigned long clk_rate;
34 unsigned long clk_div;
35 unsigned long real_rate;
36 u8 prescaler;
37
38 int is2440;
39 unsigned sdiimsk;
40 unsigned sdidata;
41 int dodma;
42 int dmatogo;
43
44 struct mmc_request *mrq;
45 int cmd_is_stop;
46
47 spinlock_t complete_lock;
48 enum s3cmci_waitfor complete_what;
49
50 int dma_complete;
51
52 u32 pio_sgptr;
53 u32 pio_words;
54 u32 pio_count;
55 u32 *pio_ptr;
56#define XFER_NONE 0
57#define XFER_READ 1
58#define XFER_WRITE 2
59 u32 pio_active;
60
61 int bus_width;
62
63 char dbgmsg_cmd[301];
64 char dbgmsg_dat[301];
65 char *status;
66
67 unsigned int ccnt, dcnt;
68 struct tasklet_struct pio_tasklet;
69};
diff --git a/include/asm-arm/arch-s3c2410/regs-sdi.h b/include/asm-arm/arch-s3c2410/regs-sdi.h
index bb9d30b7295..bfb222fa4ab 100644
--- a/include/asm-arm/arch-s3c2410/regs-sdi.h
+++ b/include/asm-arm/arch-s3c2410/regs-sdi.h
@@ -28,9 +28,15 @@
28#define S3C2410_SDIDCNT (0x30) 28#define S3C2410_SDIDCNT (0x30)
29#define S3C2410_SDIDSTA (0x34) 29#define S3C2410_SDIDSTA (0x34)
30#define S3C2410_SDIFSTA (0x38) 30#define S3C2410_SDIFSTA (0x38)
31
31#define S3C2410_SDIDATA (0x3C) 32#define S3C2410_SDIDATA (0x3C)
32#define S3C2410_SDIIMSK (0x40) 33#define S3C2410_SDIIMSK (0x40)
33 34
35#define S3C2440_SDIDATA (0x40)
36#define S3C2440_SDIIMSK (0x3C)
37
38#define S3C2440_SDICON_SDRESET (1<<8)
39#define S3C2440_SDICON_MMCCLOCK (1<<5)
34#define S3C2410_SDICON_BYTEORDER (1<<4) 40#define S3C2410_SDICON_BYTEORDER (1<<4)
35#define S3C2410_SDICON_SDIOIRQ (1<<3) 41#define S3C2410_SDICON_SDIOIRQ (1<<3)
36#define S3C2410_SDICON_RWAITEN (1<<2) 42#define S3C2410_SDICON_RWAITEN (1<<2)
@@ -42,7 +48,8 @@
42#define S3C2410_SDICMDCON_LONGRSP (1<<10) 48#define S3C2410_SDICMDCON_LONGRSP (1<<10)
43#define S3C2410_SDICMDCON_WAITRSP (1<<9) 49#define S3C2410_SDICMDCON_WAITRSP (1<<9)
44#define S3C2410_SDICMDCON_CMDSTART (1<<8) 50#define S3C2410_SDICMDCON_CMDSTART (1<<8)
45#define S3C2410_SDICMDCON_INDEX (0xff) 51#define S3C2410_SDICMDCON_SENDERHOST (1<<6)
52#define S3C2410_SDICMDCON_INDEX (0x3f)
46 53
47#define S3C2410_SDICMDSTAT_CRCFAIL (1<<12) 54#define S3C2410_SDICMDSTAT_CRCFAIL (1<<12)
48#define S3C2410_SDICMDSTAT_CMDSENT (1<<11) 55#define S3C2410_SDICMDSTAT_CMDSENT (1<<11)
@@ -51,6 +58,9 @@
51#define S3C2410_SDICMDSTAT_XFERING (1<<8) 58#define S3C2410_SDICMDSTAT_XFERING (1<<8)
52#define S3C2410_SDICMDSTAT_INDEX (0xff) 59#define S3C2410_SDICMDSTAT_INDEX (0xff)
53 60
61#define S3C2440_SDIDCON_DS_BYTE (0<<22)
62#define S3C2440_SDIDCON_DS_HALFWORD (1<<22)
63#define S3C2440_SDIDCON_DS_WORD (2<<22)
54#define S3C2410_SDIDCON_IRQPERIOD (1<<21) 64#define S3C2410_SDIDCON_IRQPERIOD (1<<21)
55#define S3C2410_SDIDCON_TXAFTERRESP (1<<20) 65#define S3C2410_SDIDCON_TXAFTERRESP (1<<20)
56#define S3C2410_SDIDCON_RXAFTERCMD (1<<19) 66#define S3C2410_SDIDCON_RXAFTERCMD (1<<19)
@@ -59,6 +69,7 @@
59#define S3C2410_SDIDCON_WIDEBUS (1<<16) 69#define S3C2410_SDIDCON_WIDEBUS (1<<16)
60#define S3C2410_SDIDCON_DMAEN (1<<15) 70#define S3C2410_SDIDCON_DMAEN (1<<15)
61#define S3C2410_SDIDCON_STOP (1<<14) 71#define S3C2410_SDIDCON_STOP (1<<14)
72#define S3C2440_SDIDCON_DATSTART (1<<14)
62#define S3C2410_SDIDCON_DATMODE (3<<12) 73#define S3C2410_SDIDCON_DATMODE (3<<12)
63#define S3C2410_SDIDCON_BLKNUM (0x7ff) 74#define S3C2410_SDIDCON_BLKNUM (0x7ff)
64 75
@@ -68,6 +79,7 @@
68#define S3C2410_SDIDCON_XFER_RXSTART (2<<12) 79#define S3C2410_SDIDCON_XFER_RXSTART (2<<12)
69#define S3C2410_SDIDCON_XFER_TXSTART (3<<12) 80#define S3C2410_SDIDCON_XFER_TXSTART (3<<12)
70 81
82#define S3C2410_SDIDCON_BLKNUM_MASK (0xFFF)
71#define S3C2410_SDIDCNT_BLKNUM_SHIFT (12) 83#define S3C2410_SDIDCNT_BLKNUM_SHIFT (12)
72 84
73#define S3C2410_SDIDSTA_RDYWAITREQ (1<<10) 85#define S3C2410_SDIDSTA_RDYWAITREQ (1<<10)
@@ -82,10 +94,12 @@
82#define S3C2410_SDIDSTA_TXDATAON (1<<1) 94#define S3C2410_SDIDSTA_TXDATAON (1<<1)
83#define S3C2410_SDIDSTA_RXDATAON (1<<0) 95#define S3C2410_SDIDSTA_RXDATAON (1<<0)
84 96
97#define S3C2440_SDIFSTA_FIFORESET (1<<16)
98#define S3C2440_SDIFSTA_FIFOFAIL (3<<14) /* 3 is correct (2 bits) */
85#define S3C2410_SDIFSTA_TFDET (1<<13) 99#define S3C2410_SDIFSTA_TFDET (1<<13)
86#define S3C2410_SDIFSTA_RFDET (1<<12) 100#define S3C2410_SDIFSTA_RFDET (1<<12)
87#define S3C2410_SDIFSTA_TXHALF (1<<11) 101#define S3C2410_SDIFSTA_TFHALF (1<<11)
88#define S3C2410_SDIFSTA_TXEMPTY (1<<10) 102#define S3C2410_SDIFSTA_TFEMPTY (1<<10)
89#define S3C2410_SDIFSTA_RFLAST (1<<9) 103#define S3C2410_SDIFSTA_RFLAST (1<<9)
90#define S3C2410_SDIFSTA_RFFULL (1<<8) 104#define S3C2410_SDIFSTA_RFFULL (1<<8)
91#define S3C2410_SDIFSTA_RFHALF (1<<7) 105#define S3C2410_SDIFSTA_RFHALF (1<<7)