summaryrefslogtreecommitdiff
path: root/drivers/mmc/host/sdhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rwxr-xr-xdrivers/mmc/host/sdhci.c69
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);