--- drivers/mmc/host/s3cmci.c | 156 +++++++++++++++++++++++++++++++--------------- drivers/mmc/host/s3cmci.h | 6 + 2 files changed, 112 insertions(+), 50 deletions(-) Index: linux-2.6.22-atheros-ng/drivers/mmc/host/s3cmci.c =================================================================== --- linux-2.6.22-atheros-ng.orig/drivers/mmc/host/s3cmci.c 2007-12-21 16:24:25.000000000 +0100 +++ linux-2.6.22-atheros-ng/drivers/mmc/host/s3cmci.c 2007-12-21 16:25:44.000000000 +0100 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,7 @@ static const int dbgmap_err = dbg_err | dbg_fail; static const int dbgmap_info = dbg_info | dbg_conf; -static const int dbgmap_debug = dbg_debug; +static const int dbgmap_debug = dbg_debug | dbg_pio; #define dbg(host, channels, args...) \ if (dbgmap_err & channels) \ @@ -159,7 +160,7 @@ u32 newmask; newmask = readl(host->base + host->sdiimsk); - newmask|= imask; + newmask |= imask; writel(newmask, host->base + host->sdiimsk); @@ -180,11 +181,14 @@ static inline void clear_imask(struct s3cmci_host *host) { - writel(0, host->base + host->sdiimsk); + if (host->sdio_int) + writel(S3C2410_SDIIMSK_SDIOIRQ, host->base + host->sdiimsk); + else + writel(0, host->base + host->sdiimsk); } static inline int get_data_buffer(struct s3cmci_host *host, - volatile u32 *words, volatile u32 **pointer) + volatile u32 *bytes, volatile u8 **pointer) { struct scatterlist *sg; @@ -201,7 +205,7 @@ } sg = &host->mrq->data->sg[host->pio_sgptr]; - *words = sg->length >> 2; + *bytes = sg->length; *pointer= page_address(sg->page) + sg->offset; host->pio_sgptr++; @@ -212,8 +216,8 @@ return 0; } -#define FIFO_FILL(host) ((readl(host->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK) >> 2) -#define FIFO_FREE(host) ((63 - (readl(host->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK)) >> 2) +#define FIFO_FILL(host) ((readl(host->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK)) +#define FIFO_FREE(host) ((63 - (readl(host->base + S3C2410_SDIFSTA) & S3C2410_SDIFSTA_COUNTMASK))) static inline void do_pio_read(struct s3cmci_host *host) { @@ -227,9 +231,9 @@ from_ptr = host->base + host->sdidata; while ((fifo = FIFO_FILL(host))) { - if (!host->pio_words) { - res = get_data_buffer(host, &host->pio_words, - &host->pio_ptr); + if (!host->pio_bytes) { + res = get_data_buffer(host, &host->pio_bytes, + &host->pio_ptr); if (res) { host->pio_active = XFER_NONE; host->complete_what = COMPLETION_FINALIZE; @@ -240,27 +244,26 @@ } dbg(host, dbg_pio, "pio_read(): new target: [%i]@[%p]\n", - host->pio_words, host->pio_ptr); + host->pio_bytes, host->pio_ptr); } dbg(host, dbg_pio, "pio_read(): fifo:[%02i] " "buffer:[%03i] dcnt:[%08X]\n", - fifo, host->pio_words, + fifo, host->pio_bytes, readl(host->base + S3C2410_SDIDCNT)); - if (fifo > host->pio_words) - fifo = host->pio_words; + if (fifo > host->pio_bytes) + fifo = host->pio_bytes; - host->pio_words-= fifo; - host->pio_count+= fifo; + host->pio_bytes -= fifo; + host->pio_count += fifo; - while(fifo--) { - *(host->pio_ptr++) = readl(from_ptr); - } + while(fifo--) + *(host->pio_ptr++) = readb(from_ptr); } - if (!host->pio_words) { - res = get_data_buffer(host, &host->pio_words, &host->pio_ptr); + if (!host->pio_bytes) { + res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr); if (res) { dbg(host, dbg_pio, "pio_read(): " "complete (no more buffers).\n"); @@ -284,9 +287,9 @@ to_ptr = host->base + host->sdidata; while ((fifo = FIFO_FREE(host))) { - if (!host->pio_words) { - res = get_data_buffer(host, &host->pio_words, - &host->pio_ptr); + if (!host->pio_bytes) { + res = get_data_buffer(host, &host->pio_bytes, + &host->pio_ptr); if (res) { dbg(host, dbg_pio, "pio_write(): " "complete (no more data).\n"); @@ -297,18 +300,18 @@ dbg(host, dbg_pio, "pio_write(): " "new source: [%i]@[%p]\n", - host->pio_words, host->pio_ptr); + host->pio_bytes, host->pio_ptr); } - if (fifo > host->pio_words) - fifo = host->pio_words; + if (fifo > host->pio_bytes) + fifo = host->pio_bytes; - host->pio_words-= fifo; - host->pio_count+= fifo; + host->pio_bytes -= fifo; + host->pio_count += fifo; while(fifo--) { - writel(*(host->pio_ptr++), to_ptr); + writeb(*(host->pio_ptr++), to_ptr); } } @@ -331,9 +334,9 @@ clear_imask(host); if (host->pio_active != XFER_NONE) { dbg(host, dbg_err, "unfinished %s " - "- pio_count:[%u] pio_words:[%u]\n", + "- pio_count:[%u] pio_bytes:[%u]\n", (host->pio_active == XFER_READ)?"read":"write", - host->pio_count, host->pio_words); + host->pio_count, host->pio_bytes); host->mrq->data->error = -EIO; } @@ -376,6 +379,7 @@ struct mmc_command *cmd; u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; u32 mci_cclear, mci_dclear; + int cardint = 0; unsigned long iflags; host = (struct s3cmci_host *)dev_id; @@ -390,8 +394,19 @@ mci_cclear = 0; mci_dclear = 0; + if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) { + if (host->sdio_int) { + disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ); + cardint = 1; + host->sdio_pending_int = 0; + } else { + host->sdio_pending_int = 1; + } + mci_dclear |= S3C2410_SDIDSTA_SDIOIRQDETECT; + } + if ((host->complete_what == COMPLETION_NONE) || - (host->complete_what == COMPLETION_FINALIZE)) { + (host->complete_what == COMPLETION_FINALIZE)) { host->status = "nothing to complete"; clear_imask(host); goto irq_out; @@ -413,7 +428,7 @@ if (!host->dodma) { if ((host->pio_active == XFER_WRITE) && - (mci_fsta & S3C2410_SDIFSTA_TFDET)) { + (mci_fsta & S3C2410_SDIFSTA_TFDET)) { disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); tasklet_schedule(&host->pio_tasklet); @@ -468,8 +483,10 @@ goto close_transfer; } - if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) + if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) { host->complete_what = COMPLETION_XFERFINISH; + host->status = "ok: command response received, xfer to be done"; + } mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN; } @@ -550,6 +567,10 @@ mci_dcnt, host->status); spin_unlock_irqrestore(&host->complete_lock, iflags); + + /* We have to delay this as it calls back into the driver */ + if (cardint) + mmc_signal_sdio_irq(host->mmc); return IRQ_HANDLED; } @@ -671,7 +692,7 @@ writel(0, host->base + S3C2410_SDICMDARG); writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); writel(0, host->base + S3C2410_SDICMDCON); - writel(0, host->base + host->sdiimsk); + clear_imask(host); if (cmd->data && cmd->error) cmd->data->error = cmd->error; @@ -711,7 +732,7 @@ //reset fifo mci_con = readl(host->base + S3C2410_SDICON); - mci_con|= S3C2410_SDICON_FIFORESET; + mci_con |= S3C2410_SDICON_FIFORESET; writel(mci_con, host->base + S3C2410_SDICON); } @@ -776,6 +797,9 @@ if (cmd->flags & MMC_RSP_136) ccon|= S3C2410_SDICMDCON_LONGRSP; + if (cmd->data) + ccon |= S3C2410_SDICMDCON_WITHDATA; + writel(ccon, host->base + S3C2410_SDICMDCON); } @@ -833,7 +857,8 @@ } if (host->is2440) { - dcon |= S3C2440_SDIDCON_DS_WORD; + dcon |= S3C2440_SDIDCON_DS_BYTE; +// dcon |= S3C2440_SDIDCON_DS_WORD; dcon |= S3C2440_SDIDCON_DATSTART; } @@ -858,12 +883,11 @@ //FIX: set slow clock to prevent timeouts on read if (data->flags & MMC_DATA_READ) { + printk("######## FIX ########## \n"); writel(0xFF, host->base + S3C2410_SDIPRE); } } - //debug_dump_registers(host, "Data setup:"); - return 0; } @@ -875,7 +899,7 @@ return -EINVAL; host->pio_sgptr = 0; - host->pio_words = 0; + host->pio_bytes = 0; host->pio_count = 0; host->pio_active = rw?XFER_WRITE:XFER_READ; @@ -1019,7 +1043,7 @@ host->pdata->set_power(ios->power_mode, ios->vdd); if (!host->is2440) - mci_con|=S3C2410_SDICON_FIFORESET; + mci_con |= S3C2410_SDICON_FIFORESET; break; @@ -1032,7 +1056,7 @@ host->pdata->set_power(ios->power_mode, ios->vdd); if (host->is2440) - mci_con|=S3C2440_SDICON_SDRESET; + mci_con |= S3C2440_SDICON_SDRESET; break; } @@ -1060,9 +1084,11 @@ else mci_con &=~S3C2410_SDICON_CLOCKTYPE; + mci_con |= S3C2410_SDICON_SDIOIRQ; + writel(mci_con, host->base + S3C2410_SDICON); - if ((ios->power_mode==MMC_POWER_ON) + if ((ios->power_mode == MMC_POWER_ON) || (ios->power_mode==MMC_POWER_UP)) { dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n", @@ -1094,10 +1120,39 @@ return s3c2410_gpio_getpin(host->pdata->gpio_wprotect); } +void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct s3cmci_host *host = mmc_priv(mmc); + u32 con, imask; + + con = readl(host->base + S3C2410_SDICON); + imask = readl(host->base + host->sdiimsk); + + if (enable) { + host->sdio_int = 1; + con |= S3C2410_SDICON_SDIOIRQ; + imask |= S3C2410_SDIIMSK_SDIOIRQ; + if (host->sdio_pending_int) { + printk("We have a pending INT\n"); + mmc_signal_sdio_irq(host->mmc); + host->sdio_pending_int = 0; + } + } else { + + host->sdio_int = 0; + con &= ~S3C2410_SDICON_SDIOIRQ; + imask &= ~S3C2410_SDIIMSK_SDIOIRQ; + } + + writel(imask, host->base + host->sdiimsk); + writel(con, host->base + S3C2410_SDICON); +} + static struct mmc_host_ops s3cmci_ops = { - .request = s3cmci_request, - .set_ios = s3cmci_set_ios, - .get_ro = s3cmci_get_ro, + .request = s3cmci_request, + .set_ios = s3cmci_set_ios, + .get_ro = s3cmci_get_ro, + .enable_sdio_irq = s3cmci_enable_sdio_irq, }; static struct s3c24xx_mci_pdata s3cmci_def_pdata = { @@ -1143,6 +1198,7 @@ host->sdidata = S3C2410_SDIDATA; host->clk_div = 2; } + host->sdio_int = 0; host->dodma = 0; host->complete_what = COMPLETION_NONE; host->pio_active = XFER_NONE; @@ -1229,7 +1285,7 @@ mmc->ops = &s3cmci_ops; mmc->ocr_avail = host->pdata->ocr_avail; - mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; mmc->f_min = host->clk_rate / (host->clk_div * 256); mmc->f_max = host->clk_rate / host->clk_div; @@ -1250,6 +1306,10 @@ goto free_dmabuf; } + +// mdelay(1000); + mmc_detect_change(host->mmc, 500); + platform_set_drvdata(pdev, mmc); dev_info(&pdev->dev,"initialisation done.\n"); Index: linux-2.6.22-atheros-ng/drivers/mmc/host/s3cmci.h =================================================================== --- linux-2.6.22-atheros-ng.orig/drivers/mmc/host/s3cmci.h 2007-12-21 16:24:29.000000000 +0100 +++ linux-2.6.22-atheros-ng/drivers/mmc/host/s3cmci.h 2007-12-21 16:24:32.000000000 +0100 @@ -40,6 +40,8 @@ unsigned sdiimsk; unsigned sdidata; int dodma; + int sdio_int; + int sdio_pending_int; volatile int dmatogo; @@ -53,9 +55,9 @@ volatile int dma_complete; volatile u32 pio_sgptr; - volatile u32 pio_words; + volatile u32 pio_bytes; volatile u32 pio_count; - volatile u32 *pio_ptr; + volatile u8 *pio_ptr; #define XFER_NONE 0 #define XFER_READ 1 #define XFER_WRITE 2