diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2012-02-09 22:57:09 +0100 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-03-27 12:20:15 -0400 |
commit | c8be24c2afd3ed2445bbf8f542af35a9787fc0e8 (patch) | |
tree | e0e757bb3b6a45f55eef145484ca5707d9e45fa8 /drivers/mmc/host/tmio_mmc_pio.c | |
parent | 2b1ac5c2caccbfd43bd616321cbbe21eb33c7879 (diff) |
mmc: tmio_mmc: support the generic MMC GPIO card hotplug helper
If the platform specifies the TMIO_MMC_HAS_COLD_CD flag, use the generic
MMC GPIO card hotplug helper.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/tmio_mmc_pio.c')
-rw-r--r-- | drivers/mmc/host/tmio_mmc_pio.c | 69 |
1 files changed, 31 insertions, 38 deletions
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 49f7f218cee1..42970ab6e803 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -34,6 +34,7 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/mfd/tmio.h> +#include <linux/mmc/cd-gpio.h> #include <linux/mmc/host.h> #include <linux/mmc/tmio.h> #include <linux/module.h> @@ -791,8 +792,10 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_unlock_irqrestore(&host->lock, flags); /* - * pdata->power == false only if COLD_CD is available, otherwise only - * in short time intervals during probing or resuming + * pdata->power toggles between false and true in both cases - either + * or not the controller can be runtime-suspended during inactivity. + * But if the controller has to be kept on, the runtime-pm usage_count + * is kept positive, so no suspending actually takes place. */ if (ios->power_mode == MMC_POWER_ON && ios->clock) { if (!pdata->power) { @@ -916,7 +919,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, else mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - _host->native_hotplug = !(pdata->flags & TMIO_MMC_HAS_COLD_CD || + _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || mmc->caps & MMC_CAP_NEEDS_POLL || mmc->caps & MMC_CAP_NONREMOVABLE); @@ -933,8 +936,9 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE * - * While we increment the rtpm counter for all scenarios when the mmc - * core activates us by calling an appropriate set_ios(), we must + * While we increment the runtime PM counter for all scenarios when + * the mmc core activates us by calling an appropriate set_ios(), we + * must additionally ensure that in case 2) the tmio mmc hardware stays * additionally ensure that in case 2) the tmio mmc hardware stays * powered on during runtime for the card detection to work. */ @@ -973,6 +977,14 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, tmio_mmc_enable_mmc_irqs(_host, irq_mask); + if (pdata->flags & TMIO_MMC_USE_GPIO_CD) { + ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio); + if (ret < 0) { + tmio_mmc_host_remove(_host); + return ret; + } + } + *host = _host; return 0; @@ -990,20 +1002,22 @@ EXPORT_SYMBOL(tmio_mmc_host_probe); void tmio_mmc_host_remove(struct tmio_mmc_host *host) { struct platform_device *pdev = host->pdev; + struct tmio_mmc_data *pdata = host->pdata; + struct mmc_host *mmc = host->mmc; + + if (pdata->flags & TMIO_MMC_USE_GPIO_CD) + /* + * This means we can miss a card-eject, but this is anyway + * possible, because of delayed processing of hotplug events. + */ + mmc_cd_gpio_free(mmc); - /* - * We don't have to manipulate pdata->power here: if there is a card in - * the slot, the runtime PM is active and our .runtime_resume() will not - * be run. If there is no card in the slot and the platform can suspend - * the controller, the runtime PM is suspended and pdata->power == false, - * so, our .runtime_resume() will not try to detect a card in the slot. - */ if (!host->native_hotplug) pm_runtime_get_sync(&pdev->dev); dev_pm_qos_hide_latency_limit(&pdev->dev); - mmc_remove_host(host->mmc); + mmc_remove_host(mmc); cancel_work_sync(&host->done); cancel_delayed_work_sync(&host->delayed_reset_work); tmio_mmc_release_dma(host); @@ -1012,7 +1026,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) pm_runtime_disable(&pdev->dev); iounmap(host->ctl); - mmc_free_host(host->mmc); + mmc_free_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_remove); @@ -1026,8 +1040,6 @@ int tmio_mmc_host_suspend(struct device *dev) if (!ret) tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); - host->pm_error = pm_runtime_put_sync(dev); - return ret; } EXPORT_SYMBOL(tmio_mmc_host_suspend); @@ -1037,20 +1049,10 @@ int tmio_mmc_host_resume(struct device *dev) struct mmc_host *mmc = dev_get_drvdata(dev); struct tmio_mmc_host *host = mmc_priv(mmc); - /* The MMC core will perform the complete set up */ - host->pdata->power = false; - - host->pm_global = true; - if (!host->pm_error) - pm_runtime_get_sync(dev); - - if (host->pm_global) { - /* Runtime PM resume callback didn't run */ - tmio_mmc_reset(host); - tmio_mmc_enable_dma(host, true); - host->pm_global = false; - } + tmio_mmc_reset(host); + tmio_mmc_enable_dma(host, true); + /* The MMC core will perform the complete set up */ return mmc_resume_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_resume); @@ -1067,19 +1069,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev) { struct mmc_host *mmc = dev_get_drvdata(dev); struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = host->pdata; tmio_mmc_reset(host); tmio_mmc_enable_dma(host, true); - if (pdata->power) { - /* Only entered after a card-insert interrupt */ - if (!mmc->card) - tmio_mmc_set_ios(mmc, &mmc->ios); - mmc_detect_change(mmc, msecs_to_jiffies(100)); - } - host->pm_global = false; - return 0; } EXPORT_SYMBOL(tmio_mmc_host_runtime_resume); |