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