#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;
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)
* *
\*****************************************************************************/
+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;
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;
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);
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);