X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fmmc%2Ftifm_sd.c;h=bf00e8cf670c068e2ebb5a778ef486eda0b0b4ac;hb=592d372ae89dd5b43117cf5113a910f67f6e6a7e;hp=85a5974318b43299cc4e663bec66c7e3f6d98397;hpb=8e02f8581cd2f9c12a03be7641d5c2c427170feb;p=linux-2.6 diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 85a5974318..bf00e8cf67 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -17,7 +17,7 @@ #include #define DRIVER_NAME "tifm_sd" -#define DRIVER_VERSION "0.7" +#define DRIVER_VERSION "0.8" static int no_dma = 0; static int fixed_timeout = 0; @@ -36,8 +36,8 @@ module_param(fixed_timeout, bool, 0644); #define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */ #define TIFM_MMCSD_READ 0x8000 -#define TIFM_MMCSD_DATAMASK 0x001d /* set bits: EOFB, BRS, CB, EOC */ -#define TIFM_MMCSD_ERRMASK 0x41e0 /* set bits: CERR, CCRC, CTO, DCRC, DTO */ +#define TIFM_MMCSD_DATAMASK 0x401d /* set bits: CERR, EOFB, BRS, CB, EOC */ +#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */ #define TIFM_MMCSD_EOC 0x0001 /* end of command phase */ #define TIFM_MMCSD_CB 0x0004 /* card enter busy state */ #define TIFM_MMCSD_BRS 0x0008 /* block received/sent */ @@ -80,7 +80,6 @@ typedef enum { enum { FIFO_RDY = 0x0001, /* hardware dependent value */ EJECT = 0x0004, - EJECT_DONE = 0x0008, CARD_BUSY = 0x0010, OPENDRAIN = 0x0040, /* hardware dependent value */ CARD_EVENT = 0x0100, /* hardware dependent value */ @@ -99,7 +98,6 @@ struct tifm_sd { struct tasklet_struct finish_tasklet; struct timer_list timer; struct mmc_request *req; - wait_queue_head_t notify; size_t written_blocks; size_t buffer_size; @@ -107,18 +105,13 @@ struct tifm_sd { }; -static char* tifm_sd_kmap_atomic(struct mmc_data *data) +static char* tifm_sd_data_buffer(struct mmc_data *data) { - return kmap_atomic(data->sg->page, KM_BIO_SRC_IRQ) + data->sg->offset; -} - -static void tifm_sd_kunmap_atomic(char *buffer, struct mmc_data *data) -{ - kunmap_atomic(buffer - data->sg->offset, KM_BIO_SRC_IRQ); + return page_address(data->sg->page) + data->sg->offset; } static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, - unsigned int host_status) + unsigned int host_status) { struct mmc_command *cmd = host->req->cmd; unsigned int t_val = 0, cnt = 0; @@ -127,18 +120,17 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, if (host_status & TIFM_MMCSD_BRS) { /* in non-dma rx mode BRS fires when fifo is still not empty */ if (no_dma && (cmd->data->flags & MMC_DATA_READ)) { - buffer = tifm_sd_kmap_atomic(host->req->data); + buffer = tifm_sd_data_buffer(host->req->data); while (host->buffer_size > host->buffer_pos) { t_val = readl(sock->addr + SOCK_MMCSD_DATA); buffer[host->buffer_pos++] = t_val & 0xff; buffer[host->buffer_pos++] = (t_val >> 8) & 0xff; } - tifm_sd_kunmap_atomic(buffer, host->req->data); } return 1; } else if (no_dma) { - buffer = tifm_sd_kmap_atomic(host->req->data); + buffer = tifm_sd_data_buffer(host->req->data); if ((cmd->data->flags & MMC_DATA_READ) && (host_status & TIFM_MMCSD_AF)) { for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { @@ -159,11 +151,10 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, t_val |= ((buffer[host->buffer_pos++]) << 8) & 0xff00; writel(t_val, - sock->addr + SOCK_MMCSD_DATA); + sock->addr + SOCK_MMCSD_DATA); } } } - tifm_sd_kunmap_atomic(buffer, host->req->data); } return 0; } @@ -220,7 +211,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd) cmd_mask |= TIFM_MMCSD_READ; dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", - cmd->opcode, cmd->arg, cmd_mask); + cmd->opcode, cmd->arg, cmd_mask); writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); @@ -249,7 +240,7 @@ change_state: case IDLE: return; case CMD: - if (host_status & TIFM_MMCSD_EOC) { + if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) { tifm_sd_fetch_resp(cmd, sock); if (cmd->data) { host->state = BRS; @@ -323,24 +314,38 @@ change_state: } /* Called from interrupt handler */ -static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, - unsigned int sock_irq_status) +static void tifm_sd_data_event(struct tifm_dev *sock) { struct tifm_sd *host; - unsigned int host_status = 0, fifo_status = 0; - int error_code = 0; + unsigned int fifo_status = 0; spin_lock(&sock->lock); host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - if (sock_irq_status & FIFO_EVENT) { - fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); - writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); + fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); + writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); + + host->flags |= fifo_status & FIFO_RDY; + + if (host->req) + tifm_sd_process_cmd(sock, host, 0); + + dev_dbg(&sock->dev, "fifo_status %x\n", fifo_status); + spin_unlock(&sock->lock); + +} + +/* Called from interrupt handler */ +static void tifm_sd_card_event(struct tifm_dev *sock) +{ + struct tifm_sd *host; + unsigned int host_status = 0; + int error_code = 0; + + spin_lock(&sock->lock); + host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - host->flags |= fifo_status & FIFO_RDY; - } - if (sock_irq_status & CARD_EVENT) { host_status = readl(sock->addr + SOCK_MMCSD_STATUS); writel(host_status, sock->addr + SOCK_MMCSD_STATUS); @@ -348,13 +353,10 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, goto done; if (host_status & TIFM_MMCSD_ERRMASK) { - if (host_status & TIFM_MMCSD_CERR) - error_code = MMC_ERR_FAILED; - else if (host_status & - (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) + if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) error_code = MMC_ERR_TIMEOUT; - else if (host_status & - (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) + else if (host_status + & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) error_code = MMC_ERR_BADCRC; writel(TIFM_FIFO_INT_SETALL, @@ -382,33 +384,31 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, if (host_status & TIFM_MMCSD_CB) host->flags |= CARD_BUSY; - if ((host_status & TIFM_MMCSD_EOFB) && - (host->flags & CARD_BUSY)) { + if ((host_status & TIFM_MMCSD_EOFB) + && (host->flags & CARD_BUSY)) { host->written_blocks++; host->flags &= ~CARD_BUSY; } - } if (host->req) tifm_sd_process_cmd(sock, host, host_status); done: - dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", - host_status, fifo_status); + dev_dbg(&sock->dev, "host_status %x\n", host_status); spin_unlock(&sock->lock); - return sock_irq_status; } -static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) +static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd) { - struct tifm_dev *sock = card->dev; + struct tifm_dev *sock = host->dev; unsigned int dest_cnt; /* DMA style IO */ - + dev_dbg(&sock->dev, "setting dma for %d blocks\n", + cmd->data->blocks); writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); writel(ilog2(cmd->data->blksz) - 2, - sock->addr + SOCK_FIFO_PAGE_SIZE); + sock->addr + SOCK_FIFO_PAGE_SIZE); writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); @@ -422,7 +422,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) if (cmd->data->flags & MMC_DATA_WRITE) { writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); + sock->addr + SOCK_DMA_CONTROL); } else { writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); @@ -430,7 +430,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) } static void tifm_sd_set_data_timeout(struct tifm_sd *host, - struct mmc_data *data) + struct mmc_data *data) { struct tifm_dev *sock = host->dev; unsigned int data_timeout = data->timeout_clks; @@ -448,7 +448,7 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host, sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); } else { data_timeout = (data_timeout >> 10) + 1; - if(data_timeout > 0xffff) + if (data_timeout > 0xffff) data_timeout = 0; /* set to unlimited */ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); writel(TIFM_MMCSD_DPE @@ -499,7 +499,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) mod_timer(&host->timer, jiffies + host->timeout_jiffies); host->state = CMD; writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); tifm_sd_exec(host, mrq->cmd); spin_unlock_irqrestore(&sock->lock, flags); return; @@ -539,8 +539,8 @@ static void tifm_sd_end_cmd(unsigned long data) r_data = mrq->cmd->data; if (r_data) { if (r_data->flags & MMC_DATA_WRITE) { - r_data->bytes_xfered = host->written_blocks * - r_data->blksz; + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; } else { r_data->bytes_xfered = r_data->blocks - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; @@ -554,7 +554,7 @@ static void tifm_sd_end_cmd(unsigned long data) } writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); spin_unlock_irqrestore(&sock->lock, flags); mmc_request_done(mmc, mrq); @@ -582,14 +582,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) if (r_data) { tifm_sd_set_data_timeout(host, r_data); - host->buffer_size = mrq->cmd->data->blocks * - mrq->cmd->data->blksz; + host->buffer_size = mrq->cmd->data->blocks + * mrq->cmd->data->blksz; - writel(TIFM_MMCSD_BUFINT | - readl(sock->addr + SOCK_MMCSD_INT_ENABLE), + writel(TIFM_MMCSD_BUFINT + | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) | - (TIFM_MMCSD_FIFO_SIZE - 1), + writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) + | (TIFM_MMCSD_FIFO_SIZE - 1), sock->addr + SOCK_MMCSD_BUFFER_CONFIG); host->written_blocks = 0; @@ -603,7 +603,7 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) mod_timer(&host->timer, jiffies + host->timeout_jiffies); host->state = CMD; writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); tifm_sd_exec(host, mrq->cmd); spin_unlock_irqrestore(&sock->lock, flags); return; @@ -642,8 +642,8 @@ static void tifm_sd_end_cmd_nodma(unsigned long data) sock->addr + SOCK_MMCSD_INT_ENABLE); if (r_data->flags & MMC_DATA_WRITE) { - r_data->bytes_xfered = host->written_blocks * - r_data->blksz; + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; } else { r_data->bytes_xfered = r_data->blocks - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; @@ -656,39 +656,20 @@ static void tifm_sd_end_cmd_nodma(unsigned long data) } writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); spin_unlock_irqrestore(&sock->lock, flags); mmc_request_done(mmc, mrq); } -static void tifm_sd_terminate(struct tifm_sd *host) -{ - struct tifm_dev *sock = host->dev; - unsigned long flags; - - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - mmiowb(); - spin_lock_irqsave(&sock->lock, flags); - host->flags |= EJECT; - if (host->req) { - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); - tasklet_schedule(&host->finish_tasklet); - } - spin_unlock_irqrestore(&sock->lock, flags); -} - static void tifm_sd_abort(unsigned long data) { struct tifm_sd *host = (struct tifm_sd*)data; printk(KERN_ERR DRIVER_NAME - ": card failed to respond for a long period of time"); + ": card failed to respond for a long period of time\n"); - tifm_sd_terminate(host); tifm_eject(host->dev); } @@ -707,9 +688,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), sock->addr + SOCK_MMCSD_CONFIG); } else { - writel((~TIFM_MMCSD_4BBUS) & - readl(sock->addr + SOCK_MMCSD_CONFIG), - sock->addr + SOCK_MMCSD_CONFIG); + writel((~TIFM_MMCSD_4BBUS) + & readl(sock->addr + SOCK_MMCSD_CONFIG), + sock->addr + SOCK_MMCSD_CONFIG); } if (ios->clock) { @@ -728,23 +709,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) if ((20000000 / clk_div1) > (24000000 / clk_div2)) { host->clk_freq = 20000000; host->clk_div = clk_div1; - writel((~TIFM_CTRL_FAST_CLK) & - readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + writel((~TIFM_CTRL_FAST_CLK) + & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); } else { host->clk_freq = 24000000; host->clk_div = clk_div2; - writel(TIFM_CTRL_FAST_CLK | - readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + writel(TIFM_CTRL_FAST_CLK + | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); } } else { host->clk_div = 0; } host->clk_div &= TIFM_MMCSD_CLKMASK; - writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) & - readl(sock->addr + SOCK_MMCSD_CONFIG)), - sock->addr + SOCK_MMCSD_CONFIG); + writel(host->clk_div + | ((~TIFM_MMCSD_CLKMASK) + & readl(sock->addr + SOCK_MMCSD_CONFIG)), + sock->addr + SOCK_MMCSD_CONFIG); if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) host->flags |= OPENDRAIN; @@ -754,12 +736,6 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* chip_select : maybe later */ //vdd //power is set before probe / after remove - //I believe, power_off when already marked for eject is sufficient to - // allow removal. - if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { - host->flags |= EJECT_DONE; - wake_up_all(&host->notify); - } spin_unlock_irqrestore(&sock->lock, flags); } @@ -855,8 +831,8 @@ static int tifm_sd_probe(struct tifm_dev *sock) struct tifm_sd *host; int rc = -EIO; - if (!(TIFM_SOCK_STATE_OCCUPIED & - readl(sock->addr + SOCK_PRESENT_STATE))) { + if (!(TIFM_SOCK_STATE_OCCUPIED + & readl(sock->addr + SOCK_PRESENT_STATE))) { printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n"); return rc; } @@ -870,7 +846,6 @@ static int tifm_sd_probe(struct tifm_dev *sock) host->dev = sock; host->timeout_jiffies = msecs_to_jiffies(1000); - init_waitqueue_head(&host->notify); tasklet_init(&host->finish_tasklet, no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, (unsigned long)host); @@ -884,9 +859,15 @@ static int tifm_sd_probe(struct tifm_dev *sock) mmc->f_max = 24000000; mmc->max_hw_segs = 1; mmc->max_phys_segs = 1; - mmc->max_sectors = 127; - mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length - sock->signal_irq = tifm_sd_signal_irq; + // limited by DMA counter - it's safer to stick with + // block counter has 11 bits though + mmc->max_blk_count = 256; + // 2k maximum hw block length + mmc->max_blk_size = 2048; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; + sock->card_event = tifm_sd_card_event; + sock->data_event = tifm_sd_data_event; rc = tifm_sd_initialize_host(host); if (!rc) @@ -904,24 +885,74 @@ static void tifm_sd_remove(struct tifm_dev *sock) { struct mmc_host *mmc = tifm_get_drvdata(sock); struct tifm_sd *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&sock->lock, flags); + host->flags |= EJECT; + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + spin_unlock_irqrestore(&sock->lock, flags); - del_timer_sync(&host->timer); - tifm_sd_terminate(host); - wait_event_timeout(host->notify, host->flags & EJECT_DONE, - host->timeout_jiffies); tasklet_kill(&host->finish_tasklet); + + spin_lock_irqsave(&sock->lock, flags); + if (host->req) { + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + host->req->cmd->error = MMC_ERR_TIMEOUT; + if (host->req->stop) + host->req->stop->error = MMC_ERR_TIMEOUT; + tasklet_schedule(&host->finish_tasklet); + } + spin_unlock_irqrestore(&sock->lock, flags); mmc_remove_host(mmc); + dev_dbg(&sock->dev, "after remove\n"); /* The meaning of the bit majority in this constant is unknown. */ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); - tifm_set_drvdata(sock, NULL); mmc_free_host(mmc); } -static tifm_media_id tifm_sd_id_tbl[] = { - FM_SD, 0 +#ifdef CONFIG_PM + +static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + int rc; + + rc = mmc_suspend_host(mmc, state); + /* The meaning of the bit majority in this constant is unknown. */ + writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + return rc; +} + +static int tifm_sd_resume(struct tifm_dev *sock) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct tifm_sd *host = mmc_priv(mmc); + + if (sock->type != TIFM_TYPE_SD + || tifm_sd_initialize_host(host)) { + tifm_eject(sock); + return 0; + } else { + return mmc_resume_host(mmc); + } +} + +#else + +#define tifm_sd_suspend NULL +#define tifm_sd_resume NULL + +#endif /* CONFIG_PM */ + +static struct tifm_device_id tifm_sd_id_tbl[] = { + { TIFM_TYPE_SD }, { } }; static struct tifm_driver tifm_sd_driver = { @@ -931,7 +962,9 @@ static struct tifm_driver tifm_sd_driver = { }, .id_table = tifm_sd_id_tbl, .probe = tifm_sd_probe, - .remove = tifm_sd_remove + .remove = tifm_sd_remove, + .suspend = tifm_sd_suspend, + .resume = tifm_sd_resume }; static int __init tifm_sd_init(void)