]> err.no Git - linux-2.6/blobdiff - drivers/mmc/tifm_sd.c
tifm_sd: remove wait for power off on remove
[linux-2.6] / drivers / mmc / tifm_sd.c
index 37fe0c3ecb854c06f72fce7d03f8949ebcf97c12..bf00e8cf670c068e2ebb5a778ef486eda0b0b4ac 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/io.h>
 
 #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,14 +105,9 @@ 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,
@@ -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++) {
@@ -163,7 +155,6 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
                                }
                        }
                }
-               tifm_sd_kunmap_atomic(buffer, host->req->data);
        }
        return 0;
 }
@@ -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,10 +353,7 @@ 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))
@@ -387,15 +389,12 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
                        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 *host, struct mmc_command *cmd)
@@ -664,32 +663,13 @@ static void tifm_sd_end_cmd_nodma(unsigned long data)
        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);
 }
 
@@ -756,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);
 }
@@ -872,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);
@@ -886,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)
@@ -906,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);
 
-       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 = {
@@ -933,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)