diff options
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 5 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.c | 6 | ||||
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/omap.c | 24 | ||||
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 102 | ||||
-rw-r--r-- | drivers/mmc/host/s3cmci.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 12 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 5 |
9 files changed, 101 insertions, 63 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 76bfe16c09b1..2b1196e6142c 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1548,9 +1548,10 @@ static bool filter(struct dma_chan *chan, void *slave) { struct dw_dma_slave *dws = slave; - if (dws->dma_dev == chan->device->dev) + if (dws->dma_dev == chan->device->dev) { + chan->private = dws; return true; - else + } else return false; } #endif diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2909bbc8ad00..a663429b3d55 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -490,7 +490,7 @@ static void mmci_check_status(unsigned long data) mod_timer(&host->timer, jiffies + HZ); } -static int mmci_probe(struct amba_device *dev, void *id) +static int __devinit mmci_probe(struct amba_device *dev, void *id) { struct mmc_platform_data *plat = dev->dev.platform_data; struct mmci_host *host; @@ -633,7 +633,7 @@ static int mmci_probe(struct amba_device *dev, void *id) return ret; } -static int mmci_remove(struct amba_device *dev) +static int __devexit mmci_remove(struct amba_device *dev) { struct mmc_host *mmc = amba_get_drvdata(dev); @@ -730,7 +730,7 @@ static struct amba_driver mmci_driver = { .name = DRIVER_NAME, }, .probe = mmci_probe, - .remove = mmci_remove, + .remove = __devexit_p(mmci_remove), .suspend = mmci_suspend, .resume = mmci_resume, .id_table = mmci_ids, diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index dda0be4e25dc..b4a615c55f28 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -42,7 +42,7 @@ #define HAS_DMA #endif -#define DRIVER_NAME "imx-mmc" +#define DRIVER_NAME "mxc-mmc" #define MMC_REG_STR_STP_CLK 0x00 #define MMC_REG_STATUS 0x04 @@ -707,7 +707,7 @@ static int mxcmci_probe(struct platform_device *pdev) host->res = r; host->irq = irq; - host->clk = clk_get(&pdev->dev, "sdhc_clk"); + host->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); goto out_iounmap; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 67d7b7fef084..5570849188cc 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1460,18 +1460,12 @@ static int __init mmc_omap_probe(struct platform_device *pdev) if (!host->virt_base) goto err_ioremap; - if (cpu_is_omap24xx()) { - host->iclk = clk_get(&pdev->dev, "mmc_ick"); - if (IS_ERR(host->iclk)) - goto err_free_mmc_host; - clk_enable(host->iclk); - } - - if (!cpu_is_omap24xx()) - host->fclk = clk_get(&pdev->dev, "mmc_ck"); - else - host->fclk = clk_get(&pdev->dev, "mmc_fck"); + host->iclk = clk_get(&pdev->dev, "ick"); + if (IS_ERR(host->iclk)) + goto err_free_mmc_host; + clk_enable(host->iclk); + host->fclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); goto err_free_iclk; @@ -1536,10 +1530,10 @@ static int mmc_omap_remove(struct platform_device *pdev) if (host->pdata->cleanup) host->pdata->cleanup(&pdev->dev); - if (host->iclk && !IS_ERR(host->iclk)) - clk_put(host->iclk); - if (host->fclk && !IS_ERR(host->fclk)) - clk_put(host->fclk); + mmc_omap_fclk_enable(host, 0); + clk_put(host->fclk); + clk_disable(host->iclk); + clk_put(host->iclk); iounmap(host->virt_base); release_mem_region(pdev->resource[0].start, diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index db37490f67ec..3916a5618e28 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -55,6 +55,7 @@ #define VS30 (1 << 25) #define SDVS18 (0x5 << 9) #define SDVS30 (0x6 << 9) +#define SDVS33 (0x7 << 9) #define SDVSCLR 0xFFFFF1FF #define SDVSDET 0x00000400 #define AUTOIDLE 0x1 @@ -375,6 +376,32 @@ static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status) } #endif /* CONFIG_MMC_DEBUG */ +/* + * MMC controller internal state machines reset + * + * Used to reset command or data internal state machines, using respectively + * SRC or SRD bit of SYSCTL register + * Can be called from interrupt context + */ +static inline void mmc_omap_reset_controller_fsm(struct mmc_omap_host *host, + unsigned long bit) +{ + unsigned long i = 0; + unsigned long limit = (loops_per_jiffy * + msecs_to_jiffies(MMC_TIMEOUT_MS)); + + OMAP_HSMMC_WRITE(host->base, SYSCTL, + OMAP_HSMMC_READ(host->base, SYSCTL) | bit); + + while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) && + (i++ < limit)) + cpu_relax(); + + if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit) + dev_err(mmc_dev(host->mmc), + "Timeout waiting on controller reset in %s\n", + __func__); +} /* * MMC controller IRQ handler @@ -403,21 +430,17 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) (status & CMD_CRC)) { if (host->cmd) { if (status & CMD_TIMEOUT) { - OMAP_HSMMC_WRITE(host->base, SYSCTL, - OMAP_HSMMC_READ(host->base, - SYSCTL) | SRC); - while (OMAP_HSMMC_READ(host->base, - SYSCTL) & SRC) - ; - + mmc_omap_reset_controller_fsm(host, SRC); host->cmd->error = -ETIMEDOUT; } else { host->cmd->error = -EILSEQ; } end_cmd = 1; } - if (host->data) + if (host->data) { mmc_dma_cleanup(host); + mmc_omap_reset_controller_fsm(host, SRD); + } } if ((status & DATA_TIMEOUT) || (status & DATA_CRC)) { @@ -426,12 +449,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) mmc_dma_cleanup(host); else host->data->error = -EILSEQ; - OMAP_HSMMC_WRITE(host->base, SYSCTL, - OMAP_HSMMC_READ(host->base, - SYSCTL) | SRD); - while (OMAP_HSMMC_READ(host->base, - SYSCTL) & SRD) - ; + mmc_omap_reset_controller_fsm(host, SRD); end_trans = 1; } } @@ -456,13 +474,20 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) } /* - * Switch MMC operating voltage + * Switch MMC interface voltage ... only relevant for MMC1. + * + * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver. + * The MMC2 transceiver controls are used instead of DAT4..DAT7. + * Some chips, like eMMC ones, use internal transceivers. */ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) { u32 reg_val = 0; int ret; + if (host->id != OMAP_MMC1_DEVID) + return 0; + /* Disable the clocks */ clk_disable(host->fclk); clk_disable(host->iclk); @@ -485,19 +510,26 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); reg_val = OMAP_HSMMC_READ(host->base, HCTL); + /* * If a MMC dual voltage card is detected, the set_ios fn calls * this fn with VDD bit set for 1.8V. Upon card removal from the * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF. * - * Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is - * set in HCTL. + * Cope with a bit of slop in the range ... per data sheets: + * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max, + * but recommended values are 1.71V to 1.89V + * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max, + * but recommended values are 2.7V to 3.3V + * + * Board setup code shouldn't permit anything very out-of-range. + * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the + * middle range) but VSIM can't power DAT4..DAT7 at more than 3V. */ - if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) || - ((1 << vdd) == MMC_VDD_33_34))) - reg_val |= SDVS30; - if ((1 << vdd) == MMC_VDD_165_195) + if ((1 << vdd) <= MMC_VDD_23_24) reg_val |= SDVS18; + else + reg_val |= SDVS30; OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); @@ -517,16 +549,15 @@ static void mmc_omap_detect(struct work_struct *work) { struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, mmc_carddetect_work); + struct omap_mmc_slot_data *slot = &mmc_slot(host); + + host->carddetect = slot->card_detect(slot->card_detect_irq); sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); if (host->carddetect) { mmc_detect_change(host->mmc, (HZ * 200) / 1000); } else { - OMAP_HSMMC_WRITE(host->base, SYSCTL, - OMAP_HSMMC_READ(host->base, SYSCTL) | SRD); - while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD) - ; - + mmc_omap_reset_controller_fsm(host, SRD); mmc_detect_change(host->mmc, (HZ * 50) / 1000); } } @@ -538,7 +569,6 @@ static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id) { struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id; - host->carddetect = mmc_slot(host).card_detect(irq); schedule_work(&host->mmc_carddetect_work); return IRQ_HANDLED; @@ -757,10 +787,14 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_OFF: mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); /* - * Reset bus voltage to 3V if it got set to 1.8V earlier. + * Reset interface voltage to 3V if it's 1.8V now; + * only relevant on MMC-1, the others always use 1.8V. + * * REVISIT: If we are able to detect cards after unplugging * a 1.8V card, this code should not be needed. */ + if (host->id != OMAP_MMC1_DEVID) + break; if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { int vdd = fls(host->mmc->ocr_avail) - 1; if (omap_mmc_switch_opcond(host, vdd) != 0) @@ -784,7 +818,9 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } if (host->id == OMAP_MMC1_DEVID) { - /* Only MMC1 can operate at 3V/1.8V */ + /* Only MMC1 can interface at 3V without some flavor + * of external transceiver; but they all handle 1.8V. + */ if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && (ios->vdd == DUAL_VOLT_OCR_BIT)) { /* @@ -920,13 +956,13 @@ static int __init omap_mmc_probe(struct platform_device *pdev) sema_init(&host->sem, 1); - host->iclk = clk_get(&pdev->dev, "mmchs_ick"); + host->iclk = clk_get(&pdev->dev, "ick"); if (IS_ERR(host->iclk)) { ret = PTR_ERR(host->iclk); host->iclk = NULL; goto err1; } - host->fclk = clk_get(&pdev->dev, "mmchs_fck"); + host->fclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); host->fclk = NULL; @@ -1137,7 +1173,9 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state) " level suspend\n"); } - if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { + if (host->id == OMAP_MMC1_DEVID + && !(OMAP_HSMMC_READ(host->base, HCTL) + & SDVSDET)) { OMAP_HSMMC_WRITE(host->base, HCTL, OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 35a98eec7414..f4a67c65d301 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -329,7 +329,7 @@ static void do_pio_write(struct s3cmci_host *host) to_ptr = host->base + host->sdidata; - while ((fifo = fifo_free(host))) { + while ((fifo = fifo_free(host)) > 3) { if (!host->pio_bytes) { res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index f07255cb17ee..406da9a8d453 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -107,6 +107,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = { static const struct sdhci_pci_fixes sdhci_cafe = { .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | + SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, }; @@ -144,8 +145,7 @@ static int jmicron_probe(struct sdhci_pci_chip *chip) SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE | SDHCI_QUIRK_RESET_AFTER_REQUEST | - SDHCI_QUIRK_BROKEN_SMALL_PIO | - SDHCI_QUIRK_FORCE_HIGHSPEED; + SDHCI_QUIRK_BROKEN_SMALL_PIO; } /* diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6b2d1f99af67..accb592764ed 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1291,8 +1291,11 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) if (host->cmd->data) DBG("Cannot wait for busy signal when also " "doing a data transfer"); - else + else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)) return; + + /* The controller does not support the end-of-busy IRQ, + * fall through and take the SDHCI_INT_RESPONSE */ } if (intmask & SDHCI_INT_RESPONSE) @@ -1636,8 +1639,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc->f_max = host->max_clk; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; - if ((caps & SDHCI_CAN_DO_HISPD) || - (host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED)) + if (caps & SDHCI_CAN_DO_HISPD) mmc->caps |= MMC_CAP_SD_HIGHSPEED; mmc->ocr_avail = 0; @@ -1723,7 +1725,9 @@ int sdhci_add_host(struct sdhci_host *host) #endif #ifdef SDHCI_USE_LEDS_CLASS - host->led.name = mmc_hostname(mmc); + snprintf(host->led_name, sizeof(host->led_name), + "%s::", mmc_hostname(mmc)); + host->led.name = host->led_name; host->led.brightness = LED_OFF; host->led.default_trigger = mmc_hostname(mmc); host->led.brightness_set = sdhci_led_control; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 3efba2363941..43c37c68d07a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -208,8 +208,8 @@ struct sdhci_host { #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12) /* Controller has an issue with buffer bits for small transfers */ #define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) -/* Controller supports high speed but doesn't have the caps bit set */ -#define SDHCI_QUIRK_FORCE_HIGHSPEED (1<<14) +/* Controller does not provide transfer-complete interrupt when not busy */ +#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14) int irq; /* Device IRQ */ void __iomem * ioaddr; /* Mapped address */ @@ -222,6 +222,7 @@ struct sdhci_host { #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) struct led_classdev led; /* LED control */ + char led_name[32]; #endif spinlock_t lock; /* Mutex */ |