From: Aymen Zayet Date: Tue, 22 Nov 2011 13:45:12 +0000 (+0100) Subject: sdhci: attach fixed regulator to sdhci host controller. X-Git-Tag: 2.1b_release~1849 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=64203ece25037c1acdf500a959f8767afb0449f1;p=kernel%2Fkernel-mfld-blackbay.git sdhci: attach fixed regulator to sdhci host controller. BZ: 15061 The WIFI requires a fixed regulator to enable / disable the chip. So in the early device initialization, the regulator shall be requested for the sdhci host controller. Change-Id: I1e2b779c85f7cf14e2d24a3ed1bc651e8b0c8805 Signed-off-by: Aymen Zayet Reviewed-on: http://android.intel.com:8080/25381 Reviewed-by: Champciaux, NicolasX Tested-by: Champciaux, NicolasX Reviewed-by: buildbot Tested-by: buildbot --- diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 33200f2..d58e7c4 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -1343,6 +1343,7 @@ static struct platform_device wl12xx_vwlan_device = { #define ICDK_BOARD_REF_CLK 26000000 #define NCDK_BOARD_REF_CLK 38400000 +extern int sdhci_pci_request_regulators(void); void __init wl12xx_platform_data_init_post_scu(void *info) { struct sd_board_info *sd_info = info; @@ -1401,6 +1402,8 @@ void __init wl12xx_platform_data_init_post_scu(void *info) err = platform_device_register(&wl12xx_vwlan_device); if (err < 0) pr_err("error platform_device_register\n"); + + sdhci_pci_request_regulators(); } void __init *wl12xx_platform_data_init(void *info) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 90b4774..fade9fc 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1019,6 +1019,53 @@ MODULE_DEVICE_TABLE(pci, pci_ids); * * \*****************************************************************************/ +static int try_request_regulator(struct device *dev, void *data) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct sdhci_pci_chip *chip; + struct sdhci_pci_slot *slot; + struct sdhci_host *host; + int i; + + chip = pci_get_drvdata(pdev); + if (!chip) + return 0; + + for (i = 0; i < chip->num_slots; i++) { + slot = chip->slots[i]; + if (!slot) + continue; + host = slot->host; + if (!host) + continue; + if (sdhci_try_get_regulator(host) == 0) + mmc_detect_change(host->mmc, 0); + } + return 0; +} + +static struct pci_driver sdhci_driver; + +/** + * sdhci_pci_request_regulators - retry requesting regulators of + * all sdhci-pci devices + * + * One some platforms, the regulators associated to the mmc are available + * late in the boot. + * sdhci_pci_request_regulators() is called by platform code to retry + * getting the regulators associated to pci sdhcis + */ + +int sdhci_pci_request_regulators(void) +{ + /* driver not yet registered */ + if (!sdhci_driver.driver.p) + return 0; + return driver_for_each_device(&sdhci_driver.driver, + NULL, NULL, try_request_regulator); +} +EXPORT_SYMBOL_GPL(sdhci_pci_request_regulators); + static int sdhci_pci_enable_dma(struct sdhci_host *host) { struct sdhci_pci_slot *slot; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ae22f2c..19bd321 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2770,6 +2770,36 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, EXPORT_SYMBOL_GPL(sdhci_alloc_host); +/** + * sdhci_pci_request_regulators - try requesting regulator of + * a sdhci device + * + * We take care of race conditions here between sdhci_add_host() (probe) + * and platform code that may kick a retry at anytime during boot. + */ +int sdhci_try_get_regulator(struct sdhci_host *host) +{ + struct regulator *vmmc; + unsigned long flags; + if (!host->vmmc) { + vmmc = regulator_get(mmc_dev(host->mmc), "vmmc"); + if (!IS_ERR(vmmc)) { + spin_lock_irqsave(&host->lock, flags); + if (!host->vmmc) { + host->vmmc = vmmc; + spin_unlock_irqrestore(&host->lock, flags); + return 0; + } else { + /* race! we got the regulator twice */ + spin_unlock_irqrestore(&host->lock, flags); + regulator_put(vmmc); + } + } + } + return -EAGAIN; +} +EXPORT_SYMBOL_GPL(sdhci_try_get_regulator); + int sdhci_add_host(struct sdhci_host *host) { struct mmc_host *mmc; @@ -3174,13 +3204,7 @@ int sdhci_add_host(struct sdhci_host *host) if (ret) goto untasklet; - host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); - if (IS_ERR(host->vmmc)) { - printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); - host->vmmc = NULL; - } else { - regulator_enable(host->vmmc); - } + sdhci_try_get_regulator(host); sdhci_do_acquire_ownership(mmc); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0a5b654..46a992f 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -372,6 +372,7 @@ static inline void *sdhci_priv(struct sdhci_host *host) extern void sdhci_card_detect(struct sdhci_host *host); extern int sdhci_add_host(struct sdhci_host *host); extern void sdhci_remove_host(struct sdhci_host *host, int dead); +extern int sdhci_try_get_regulator(struct sdhci_host *host); #ifdef CONFIG_PM extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);