diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rwxr-xr-x | drivers/mmc/host/sdhci.c | 69 |
1 files changed, 35 insertions, 34 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index d34486e8c9f4..1653d53a2744 100755 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -73,6 +73,15 @@ static inline bool sdhci_is_sdio_attached(struct sdhci_host *host) return false; } +static bool sdhci_can_gate_clk(struct sdhci_host *host) +{ + if (!sdhci_is_sdio_attached(host)) + return true; + if (host->power_mode == MMC_POWER_OFF) + return true; + return false; +} + static void sdhci_enable_clk(struct sdhci_host *host) { if (host->clk_mgr_en) { @@ -84,7 +93,7 @@ static void sdhci_enable_clk(struct sdhci_host *host) static void sdhci_disable_clk(struct sdhci_host *host, int delay) { - if (host->clk_mgr_en) { + if (host->clk_mgr_en && sdhci_can_gate_clk(host)) { if (delay == 0 && !in_interrupt()) { if (host->ops->platform_clk_ctrl && host->clk_status) host->ops->platform_clk_ctrl(host, false); @@ -282,7 +291,7 @@ static void sdhci_deactivate_led(struct sdhci_host *host) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } -#ifdef SDHCI_USE_LEDS_CLASS +#ifdef CONFIG_SDHCI_USE_LEDS_CLASS static void sdhci_led_control(struct led_classdev *led, enum led_brightness brightness) { @@ -298,8 +307,7 @@ static void sdhci_led_control(struct led_classdev *led, sdhci_activate_led(host); spin_unlock_irqrestore(&host->lock, flags); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, CLK_TIMEOUT); + sdhci_disable_clk(host, CLK_TIMEOUT); } #endif @@ -1089,7 +1097,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) u16 clk = 0; unsigned long timeout; - if (clock == host->clock) + if (clock && clock == host->clock) return; if (host->ops->set_clock) { @@ -1257,7 +1265,7 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); -#ifndef SDHCI_USE_LEDS_CLASS +#ifndef CONFIG_SDHCI_USE_LEDS_CLASS sdhci_activate_led(host); #endif @@ -1322,6 +1330,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host = mmc_priv(mmc); + host->power_mode = ios->power_mode; + sdhci_enable_clk(host); spin_lock_irqsave(&host->lock, flags); @@ -1491,8 +1501,7 @@ static int check_ro(struct sdhci_host *host) & SDHCI_WRITE_PROTECT); spin_unlock_irqrestore(&host->lock, flags); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, CLK_TIMEOUT); + sdhci_disable_clk(host, CLK_TIMEOUT); /* This quirk needs to be replaced by a callback-function later */ return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ? @@ -2033,14 +2042,13 @@ static void sdhci_tasklet_finish(unsigned long param) host->cmd = NULL; host->data = NULL; -#ifndef SDHCI_USE_LEDS_CLASS +#ifndef CONFIG_SDHCI_USE_LEDS_CLASS sdhci_deactivate_led(host); #endif mmiowb(); spin_unlock_irqrestore(&host->lock, flags); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, CLK_TIMEOUT); + sdhci_disable_clk(host, CLK_TIMEOUT); mmc_request_done(host->mmc, mrq); } @@ -2386,8 +2394,7 @@ out: * mmc_suspend_host may disable the clk */ sdhci_enable_clk(host); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, 0); + sdhci_disable_clk(host, 0); return ret; } @@ -2409,12 +2416,13 @@ int sdhci_resume_host(struct sdhci_host *host) host->ops->enable_dma(host); } + sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); + ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, mmc_hostname(host->mmc), host); if (ret) goto out; - sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); mmiowb(); ret = mmc_resume_host(host->mmc); @@ -2425,8 +2433,7 @@ int sdhci_resume_host(struct sdhci_host *host) out: /* sync worker */ - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, 0); + sdhci_disable_clk(host, 0); /* Set the re-tuning expiration flag */ if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && @@ -2446,8 +2453,7 @@ void sdhci_enable_irq_wakeups(struct sdhci_host *host) val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); val |= SDHCI_WAKE_ON_INT; sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, CLK_TIMEOUT); + sdhci_disable_clk(host, CLK_TIMEOUT); } EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); @@ -2595,8 +2601,7 @@ int sdhci_add_host(struct sdhci_host *host) printk(KERN_ERR "%s: Hardware doesn't specify base clock " "frequency.\n", mmc_hostname(mmc)); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, 0); + sdhci_disable_clk(host, 0); return -ENODEV; } host->max_clk = host->ops->get_max_clock(host); @@ -2612,8 +2617,7 @@ int sdhci_add_host(struct sdhci_host *host) printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " "frequency.\n", mmc_hostname(mmc)); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, 0); + sdhci_disable_clk(host, 0); return -ENODEV; } } @@ -2653,7 +2657,7 @@ int sdhci_add_host(struct sdhci_host *host) } else mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; + mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE; if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) host->flags |= SDHCI_AUTO_CMD12; @@ -2664,6 +2668,7 @@ int sdhci_add_host(struct sdhci_host *host) ((host->flags & SDHCI_USE_ADMA) || !(host->flags & SDHCI_USE_SDMA))) { host->flags |= SDHCI_AUTO_CMD23; + mmc->caps |= MMC_CAP_CMD23; DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc)); } else { DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc)); @@ -2802,8 +2807,7 @@ int sdhci_add_host(struct sdhci_host *host) if (mmc->ocr_avail == 0) { printk(KERN_ERR "%s: Hardware doesn't report any " "support voltages.\n", mmc_hostname(mmc)); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, 0); + sdhci_disable_clk(host, 0); return -ENODEV; } @@ -2904,7 +2908,7 @@ int sdhci_add_host(struct sdhci_host *host) sdhci_dumpregs(host); #endif -#ifdef SDHCI_USE_LEDS_CLASS +#ifdef CONFIG_SDHCI_USE_LEDS_CLASS snprintf(host->led_name, sizeof(host->led_name), "%s::", mmc_hostname(mmc)); host->led.name = host->led_name; @@ -2927,11 +2931,10 @@ int sdhci_add_host(struct sdhci_host *host) (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); sdhci_enable_card_detection(host); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, CLK_TIMEOUT); + sdhci_disable_clk(host, CLK_TIMEOUT); return 0; -#ifdef SDHCI_USE_LEDS_CLASS +#ifdef CONFIG_SDHCI_USE_LEDS_CLASS reset: sdhci_reset(host, SDHCI_RESET_ALL); free_irq(host->irq, host); @@ -2939,8 +2942,7 @@ reset: untasklet: tasklet_kill(&host->card_tasklet); tasklet_kill(&host->finish_tasklet); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, 0); + sdhci_disable_clk(host, 0); return ret; } @@ -2973,15 +2975,14 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) mmc_remove_host(host->mmc); -#ifdef SDHCI_USE_LEDS_CLASS +#ifdef CONFIG_SDHCI_USE_LEDS_CLASS led_classdev_unregister(&host->led); #endif sdhci_enable_clk(host); if (!dead) sdhci_reset(host, SDHCI_RESET_ALL); - if (!sdhci_is_sdio_attached(host)) - sdhci_disable_clk(host, 0); + sdhci_disable_clk(host, 0); free_irq(host->irq, host); |