diff options
author | Lee Jones <lee.jones@linaro.org> | 2011-07-26 17:31:06 +0100 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2011-07-26 17:35:08 +0100 |
commit | 6f914cb1efe4aba81bb841ec8f4f5636163c0586 (patch) | |
tree | 7ef04a88618a05c53faa2fd4ccd03e90c06a89bd /drivers/mmc/core/core.c | |
parent | 232bdfad970ce35177ca12c5527d1c96f7ce44f1 (diff) |
Apply mega patch to make GLK the ALK
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r-- | drivers/mmc/core/core.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index a5ee4387c4a..644df64c378 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -23,6 +23,7 @@ #include <linux/log2.h> #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> +#include <linux/wakelock.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -389,6 +390,8 @@ int mmc_host_enable(struct mmc_host *host) if (host->ops->enable) { int err; + wake_lock(&host->wakelock); + host->en_dis_recurs = 1; err = host->ops->enable(host); host->en_dis_recurs = 0; @@ -396,6 +399,7 @@ int mmc_host_enable(struct mmc_host *host) if (err) { pr_debug("%s: enable error %d\n", mmc_hostname(host), err); + wake_unlock(&host->wakelock); return err; } } @@ -423,6 +427,8 @@ static int mmc_host_do_disable(struct mmc_host *host, int lazy) mmc_schedule_delayed_work(&host->disable, delay); } + if (err == 0) + wake_unlock(&host->wakelock); } host->enabled = 0; return 0; @@ -1094,6 +1100,36 @@ static inline void mmc_bus_put(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); } +int mmc_resume_bus(struct mmc_host *host) +{ + unsigned long flags; + + if (!mmc_bus_needs_resume(host)) + return -EINVAL; + + printk("%s: Starting deferred resume\n", mmc_hostname(host)); + spin_lock_irqsave(&host->lock, flags); + host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME; + host->rescan_disable = 0; + spin_unlock_irqrestore(&host->lock, flags); + + mmc_bus_get(host); + if (host->bus_ops && !host->bus_dead) { + mmc_power_up(host); + BUG_ON(!host->bus_ops->resume); + host->bus_ops->resume(host); + } + + if (host->bus_ops->detect && !host->bus_dead) + host->bus_ops->detect(host); + + mmc_bus_put(host); + printk("%s: Deferred resume completed\n", mmc_hostname(host)); + return 0; +} + +EXPORT_SYMBOL(mmc_resume_bus); + /* * Assign a mmc bus handler to a host. Only one bus handler may control a * host at any given time. @@ -1565,6 +1601,7 @@ void mmc_rescan(struct work_struct *work) struct mmc_host *host = container_of(work, struct mmc_host, detect.work); int i; + bool extend_wakelock = false; if (host->rescan_disable) return; @@ -1586,6 +1623,12 @@ void mmc_rescan(struct work_struct *work) } } + /* If the card was removed the bus will be marked + * as dead - extend the wakelock so userspace + * can respond */ + if (host->bus_dead) + extend_wakelock = 1; + /* * Let mmc_bus_put() free the bus/bus_ops if we've found that * the card is no longer present. @@ -1610,14 +1653,19 @@ void mmc_rescan(struct work_struct *work) mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { - if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) + if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) { + extend_wakelock = true; break; + } if (freqs[i] <= host->f_min) break; } mmc_release_host(host); out: + if (extend_wakelock) + wake_lock_timeout(&host->wakelock, HZ / 2); + if (host->caps & MMC_CAP_NEEDS_POLL) mmc_schedule_delayed_work(&host->detect, HZ); } @@ -1756,6 +1804,9 @@ int mmc_suspend_host(struct mmc_host *host) { int err = 0; + if (mmc_bus_needs_resume(host)) + return 0; + if (host->caps & MMC_CAP_DISABLE) cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); @@ -1798,6 +1849,12 @@ int mmc_resume_host(struct mmc_host *host) int err = 0; mmc_bus_get(host); + if (mmc_bus_manual_resume(host)) { + host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME; + mmc_bus_put(host); + return 0; + } + if (host->bus_ops && !host->bus_dead) { if (!mmc_card_keep_power(host)) { mmc_power_up(host); @@ -1848,6 +1905,10 @@ int mmc_pm_notify(struct notifier_block *notify_block, case PM_SUSPEND_PREPARE: spin_lock_irqsave(&host->lock, flags); + if (mmc_bus_needs_resume(host)) { + spin_unlock_irqrestore(&host->lock, flags); + break; + } host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); cancel_delayed_work_sync(&host->detect); @@ -1871,6 +1932,10 @@ int mmc_pm_notify(struct notifier_block *notify_block, case PM_POST_RESTORE: spin_lock_irqsave(&host->lock, flags); + if (mmc_bus_manual_resume(host)) { + spin_unlock_irqrestore(&host->lock, flags); + break; + } host->rescan_disable = 0; spin_unlock_irqrestore(&host->lock, flags); mmc_detect_change(host, 0); @@ -1881,6 +1946,22 @@ int mmc_pm_notify(struct notifier_block *notify_block, } #endif +#ifdef CONFIG_MMC_EMBEDDED_SDIO +void mmc_set_embedded_sdio_data(struct mmc_host *host, + struct sdio_cis *cis, + struct sdio_cccr *cccr, + struct sdio_embedded_func *funcs, + int num_funcs) +{ + host->embedded_sdio_data.cis = cis; + host->embedded_sdio_data.cccr = cccr; + host->embedded_sdio_data.funcs = funcs; + host->embedded_sdio_data.num_funcs = num_funcs; +} + +EXPORT_SYMBOL(mmc_set_embedded_sdio_data); +#endif + static int __init mmc_init(void) { int ret; |