sdhci: don't check block count for progress
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / mmc / host / sdhci.c
index 785bbdcf4a58212e4371fbdc024a1ef1919ffc88..9b06c6042d971aa1f0264a74eda0924f1cb0de85 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
  *
- *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 
+#include <linux/leds.h>
+
 #include <linux/mmc/host.h>
 
 #include "sdhci.h"
@@ -39,7 +41,7 @@ static unsigned int debug_quirks = 0;
 #define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
 /* Controller has bad caps bits, but really supports DMA */
 #define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
-/* Controller doesn't like some resets when there is no card inserted. */
+/* Controller doesn't like to be reset when there is no card inserted. */
 #define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
 /* Controller doesn't like clearing the power reg before a change */
 #define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
@@ -53,6 +55,10 @@ static unsigned int debug_quirks = 0;
 #define SDHCI_QUIRK_32BIT_DMA_SIZE                     (1<<7)
 /* Controller needs to be reset after each request to stay stable */
 #define SDHCI_QUIRK_RESET_AFTER_REQUEST                        (1<<8)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER            (1<<9)
+/* Controller has an off-by-one issue with timeout value */
+#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL               (1<<10)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
        {
@@ -67,12 +73,20 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
        {
                .vendor         = PCI_VENDOR_ID_RICOH,
                .device         = PCI_DEVICE_ID_RICOH_R5C822,
-               .subvendor      = PCI_ANY_ID,
+               .subvendor      = PCI_VENDOR_ID_SAMSUNG,
                .subdevice      = PCI_ANY_ID,
                .driver_data    = SDHCI_QUIRK_FORCE_DMA |
                                  SDHCI_QUIRK_NO_CARD_NO_RESET,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_RICOH,
+               .device         = PCI_DEVICE_ID_RICOH_R5C822,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_FORCE_DMA,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_TI,
                .device         = PCI_DEVICE_ID_TI_XX21_XX11_SD,
@@ -105,7 +119,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
                .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-                                 SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+                                 SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+                                 SDHCI_QUIRK_BROKEN_DMA,
        },
 
        {
@@ -114,7 +129,17 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
                .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-                                 SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+                                 SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+                                 SDHCI_QUIRK_BROKEN_DMA,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_MARVELL,
+               .device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+                                 SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
        },
 
        {
@@ -252,6 +277,24 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
        writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
 }
 
+#ifdef CONFIG_LEDS_CLASS
+static void sdhci_led_control(struct led_classdev *led,
+       enum led_brightness brightness)
+{
+       struct sdhci_host *host = container_of(led, struct sdhci_host, led);
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (brightness == LED_OFF)
+               sdhci_deactivate_led(host);
+       else
+               sdhci_activate_led(host);
+
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+#endif
+
 /*****************************************************************************\
  *                                                                           *
  * Core functions                                                            *
@@ -441,6 +484,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
                        break;
        }
 
+       /*
+        * Compensate for an off-by-one error in the CaFe hardware; otherwise,
+        * a too-small count gives us interrupt timeouts.
+        */
+       if ((host->chip->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
+               count++;
+
        if (count >= 0xF) {
                printk(KERN_WARNING "%s: Too large timeout requested!\n",
                        mmc_hostname(host->mmc));
@@ -517,7 +567,6 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
 static void sdhci_finish_data(struct sdhci_host *host)
 {
        struct mmc_data *data;
-       u16 blocks;
 
        BUG_ON(!host->data);
 
@@ -530,20 +579,16 @@ static void sdhci_finish_data(struct sdhci_host *host)
        }
 
        /*
-        * Controller doesn't count down when in single block mode.
+        * The specification states that the block count register must
+        * be updated, but it does not specify at what point in the
+        * data flow. That makes the register entirely useless to read
+        * back so we have to assume that nothing made it to the card
+        * in the event of an error.
         */
-       if (data->blocks == 1)
-               blocks = (data->error == 0) ? 0 : 1;
+       if (data->error)
+               data->bytes_xfered = 0;
        else
-               blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
-       data->bytes_xfered = data->blksz * (data->blocks - blocks);
-
-       if (!data->error && blocks) {
-               printk(KERN_ERR "%s: Controller signalled completion even "
-                       "though there were blocks left.\n",
-                       mmc_hostname(host->mmc));
-               data->error = -EIO;
-       }
+               data->bytes_xfered = data->blksz * data->blocks;
 
        if (data->stop) {
                /*
@@ -746,6 +791,14 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
                BUG();
        }
 
+       /*
+        * At least the CaFe chip gets confused if we set the voltage
+        * and set turn on power at the same time, so set the voltage first.
+        */
+       if ((host->chip->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
+               writeb(pwr & ~SDHCI_POWER_ON,
+                               host->ioaddr + SDHCI_POWER_CONTROL);
+
        writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
 
 out:
@@ -769,7 +822,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        WARN_ON(host->mrq != NULL);
 
+#ifndef CONFIG_LEDS_CLASS
        sdhci_activate_led(host);
+#endif
 
        host->mrq = mrq;
 
@@ -961,7 +1016,9 @@ static void sdhci_tasklet_finish(unsigned long param)
        host->cmd = NULL;
        host->data = NULL;
 
+#ifndef CONFIG_LEDS_CLASS
        sdhci_deactivate_led(host);
+#endif
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
@@ -1101,7 +1158,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                goto out;
        }
 
-       DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
+       DBG("*** %s got interrupt: 0x%08x\n",
+               mmc_hostname(host->mmc), intmask);
 
        if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
                writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
@@ -1231,7 +1289,7 @@ static int sdhci_resume (struct pci_dev *pdev)
                if (chip->hosts[i]->flags & SDHCI_USE_DMA)
                        pci_set_master(pdev);
                ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
-                       IRQF_SHARED, chip->hosts[i]->slot_descr,
+                       IRQF_SHARED, mmc_hostname(chip->hosts[i]->mmc),
                        chip->hosts[i]);
                if (ret)
                        return ret;
@@ -1320,9 +1378,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
        DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
 
-       snprintf(host->slot_descr, 20, "sdhci:slot%d", slot);
-
-       ret = pci_request_region(pdev, host->bar, host->slot_descr);
+       ret = pci_request_region(pdev, host->bar, mmc_hostname(mmc));
        if (ret)
                goto free;
 
@@ -1339,7 +1395,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
        if (version > 1) {
                printk(KERN_ERR "%s: Unknown controller version (%d). "
-                       "You may experience problems.\n", host->slot_descr,
+                       "You may experience problems.\n", mmc_hostname(mmc),
                        version);
        }
 
@@ -1362,13 +1418,13 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
                (host->flags & SDHCI_USE_DMA)) {
                printk(KERN_WARNING "%s: Will use DMA "
                        "mode even though HW doesn't fully "
-                       "claim to support it.\n", host->slot_descr);
+                       "claim to support it.\n", mmc_hostname(mmc));
        }
 
        if (host->flags & SDHCI_USE_DMA) {
                if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                        printk(KERN_WARNING "%s: No suitable DMA available. "
-                               "Falling back to PIO.\n", host->slot_descr);
+                               "Falling back to PIO.\n", mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_DMA;
                }
        }
@@ -1382,7 +1438,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
                (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
        if (host->max_clk == 0) {
                printk(KERN_ERR "%s: Hardware doesn't specify base clock "
-                       "frequency.\n", host->slot_descr);
+                       "frequency.\n", mmc_hostname(mmc));
                ret = -ENODEV;
                goto unmap;
        }
@@ -1392,7 +1448,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
                (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
        if (host->timeout_clk == 0) {
                printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
-                       "frequency.\n", host->slot_descr);
+                       "frequency.\n", mmc_hostname(mmc));
                ret = -ENODEV;
                goto unmap;
        }
@@ -1405,7 +1461,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        mmc->ops = &sdhci_ops;
        mmc->f_min = host->max_clk / 256;
        mmc->f_max = host->max_clk;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
        if (caps & SDHCI_CAN_DO_HISPD)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED;
@@ -1420,7 +1476,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
        if (mmc->ocr_avail == 0) {
                printk(KERN_ERR "%s: Hardware doesn't report any "
-                       "support voltages.\n", host->slot_descr);
+                       "support voltages.\n", mmc_hostname(mmc));
                ret = -ENODEV;
                goto unmap;
        }
@@ -1454,8 +1510,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
         */
        mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
        if (mmc->max_blk_size >= 3) {
-               printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n",
-                       host->slot_descr);
+               printk(KERN_WARNING "%s: Invalid maximum block size, "
+                       "assuming 512 bytes\n", mmc_hostname(mmc));
                mmc->max_blk_size = 512;
        } else
                mmc->max_blk_size = 512 << mmc->max_blk_size;
@@ -1476,7 +1532,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
 
        ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-               host->slot_descr, host);
+               mmc_hostname(mmc), host);
        if (ret)
                goto untasklet;
 
@@ -1486,16 +1542,32 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        sdhci_dumpregs(host);
 #endif
 
+#ifdef CONFIG_LEDS_CLASS
+       host->led.name = mmc_hostname(mmc);
+       host->led.brightness = LED_OFF;
+       host->led.default_trigger = mmc_hostname(mmc);
+       host->led.brightness_set = sdhci_led_control;
+
+       ret = led_classdev_register(&pdev->dev, &host->led);
+       if (ret)
+               goto reset;
+#endif
+
        mmiowb();
 
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n", mmc_hostname(mmc),
-               host->addr, host->irq,
+       printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n",
+               mmc_hostname(mmc), host->addr, host->irq,
                (host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
 
        return 0;
 
+#ifdef CONFIG_LEDS_CLASS
+reset:
+       sdhci_reset(host, SDHCI_RESET_ALL);
+       free_irq(host->irq, host);
+#endif
 untasklet:
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
@@ -1523,6 +1595,10 @@ static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
 
        mmc_remove_host(mmc);
 
+#ifdef CONFIG_LEDS_CLASS
+       led_classdev_unregister(&host->led);
+#endif
+
        sdhci_reset(host, SDHCI_RESET_ALL);
 
        free_irq(host->irq, host);