static int sdhci_pltfm_suspend(struct device *device) { struct sdio_dev *dev = platform_get_drvdata(to_platform_device(device)); struct sdhci_host *host = dev->host; int ret = 0; if (!sdhci_pltfm_rpm_enabled(dev)) { ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) { dev_err(dev->dev, "Failed to enable clock during suspend\n"); return -EAGAIN; } } host->mmc->pm_flags |= host->mmc->pm_caps; ret = sdhci_suspend_host(host); if (ret) { dev_err(dev->dev, "Unable to suspend sdhci host err=%d\n", ret); return ret; } if (sdhci_pltfm_rpm_enabled(dev)) { /* * Note that we havent done a get_sync. The * pm core takes care of that. */ pm_runtime_put_sync_suspend(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 0); if (ret) { dev_err(dev->dev, "Failed to disable clock during suspend\n"); /* Not really a big error to cry and return */ } } if(dev->devtype == SDIO_DEV_TYPE_SDMMC) { printk(KERN_ERR "mmc regulator off.. delay 50ms added\n"); mdelay(50);// this is Samsung internal specification. } dev->suspended = 1; return 0; }
static int sdhci_pltfm_runtime_resume(struct device *device) { int ret = 0; unsigned long flags; struct sdio_dev *dev = platform_get_drvdata(to_platform_device(device)); struct sdhci_host *host = dev->host; /* This is never going to happen, but still */ if (!sdhci_pltfm_rpm_enabled(dev)) { dev_err(dev->dev, "Spurious rpm resume call\n"); /* But no menaing in returning error */ return 0; } spin_lock_irqsave(&host->lock, flags); host->runtime_suspended = false; spin_unlock_irqrestore(&host->lock, flags); ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) { dev_err(dev->dev, "Failed to enable clock during run time resume\n"); return -EAGAIN; } return 0; }
/* * Software emulation of the SD card insertion/removal. Set insert=1 for insert * and insert=0 for removal */ static int bcm_kona_sd_card_emulate(struct sdio_dev *dev, int insert) { struct sdhci_host *host = dev->host; uint32_t val; unsigned long flags; /* this function can be called from various contexts including ISR */ spin_lock_irqsave(&host->lock, flags); /* enable clock */ sdhci_pltfm_clk_enable(host, 1); /* Ensure SD bus scanning to detect media change */ host->mmc->rescan_disable = 0; /* Back-to-Back register write needs a delay of min 10uS. * We keep 20uS */ udelay(20); val = sdhci_readl(host, KONA_SDHOST_CORESTAT); if (insert) { if (dev->wp_gpio >= 0) { int wp_status = gpio_get_value(dev->wp_gpio); if (wp_status) val |= KONA_SDHOST_WP; else val &= ~KONA_SDHOST_WP; } val |= KONA_SDHOST_CD_SW; sdhci_writel(host, val, KONA_SDHOST_CORESTAT); } else { val &= ~KONA_SDHOST_CD_SW; sdhci_writel(host, val, KONA_SDHOST_CORESTAT); /* If the device is WiFi then disable clock as it will be * turned on again the next time WiFi is enabled. */ if (dev->devtype == SDIO_DEV_TYPE_WIFI) sdhci_pltfm_clk_enable(host, 0); } spin_unlock_irqrestore(&host->lock, flags); return 0; }
static int sdhci_pltfm_resume(struct device *device) { struct sdio_dev *dev = platform_get_drvdata(to_platform_device(device)); struct sdhci_host *host = dev->host; int ret = 0; if (sdhci_pltfm_rpm_enabled(dev)) { /* * Note that we havent done a put_sync. The * pm core takes care of that. */ pm_runtime_get_sync(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) { dev_err(dev->dev, "Failed to enable clock during resume\n"); return -EAGAIN; } } ret = sdhci_resume_host(host); if (ret) { dev_err(dev->dev, "Unable to resume sdhci host err=%d\n", ret); return ret; } if (!sdhci_pltfm_rpm_enabled(dev)) { ret = sdhci_pltfm_clk_enable(dev, 0); if (ret) { dev_err(dev->dev, "Failed to disable clock during resume\n"); /* Not really a big error to cry and return*/ } } dev->suspended = 0; if (dev->devtype == SDIO_DEV_TYPE_EMMC) host->mmc->pm_flags |= MMC_PM_KEEP_POWER; return 0; }
static int sdhci_clk_enable(struct sdhci_host *host, int enable) { struct sdio_dev *dev = sdhci_priv(host); int ret = 0; ret = sdhci_pltfm_clk_enable(dev, enable); if (ret) dev_err(dev->dev, "clock %s failed\n", enable ? "enable" : "disable"); return ret; }
static int sdhci_pltfm_resume(struct platform_device *pdev) { struct sdio_dev *dev = platform_get_drvdata(pdev); struct sdhci_host *host = dev->host; /* * If the device type is WIFI, and WiFi is enabled, * turn on the clock since currently * the WIFI driver does not support turning on/off the * clock dynamicly. */ if (dev->devtype == SDIO_DEV_TYPE_WIFI && sdhci_test_sdio_enabled(dev)) sdhci_pltfm_clk_enable(host, 1); #if 0 if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) { ret = request_irq(gpio_to_irq(dev->cd_gpio), sdhci_pltfm_cd_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "sdio cd", dev); if (ret) { dev_err(&pdev->dev, "Unable to request card detection " "irq=%d for gpio=%d\n", gpio_to_irq(dev->cd_gpio), dev->cd_gpio); return ret; } } #endif #ifndef CONFIG_MMC_UNSAFE_RESUME /* * card state might have been changed during system suspend. * Need to sync up only if MMC_UNSAFE_RESUME is not enabled */ if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) { if (gpio_get_value_cansleep(dev->cd_gpio) == 0) bcm_kona_sd_card_emulate(dev, 1); else bcm_kona_sd_card_emulate(dev, 0); } #endif dev->suspended = 0; if (dev->devtype == SDIO_DEV_TYPE_WIFI) { printk(KERN_DEBUG "%s: WiFi resume\n", __FUNCTION__); sdhci_resume_host(host); } return 0; }
static void sdhci_pltfm_shutdown(struct platform_device *pdev) { u16 clk; int ret; struct sdio_dev *dev = platform_get_drvdata(pdev); struct sdhci_host *host = dev->host; if (sdhci_pltfm_rpm_enabled(dev)) { pm_runtime_get_sync(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) dev_err(dev->dev, "enable clock during shutdown failed\n"); } /* Certain cards don't like abrupt clock * shutdown, and they go insane if we do so. * When PM runtime autosuspend is enabled, * it takes time for the clock to be cut, * but during this time, the system reboot * can abruptly cut it off. Avoid that by * disabling the clock to the card. */ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); clk &= ~SDHCI_CLOCK_CARD_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); if (sdhci_pltfm_rpm_enabled(dev)) { pm_runtime_put_sync_suspend(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 0); if (ret) dev_err(dev->dev, "disable clock during shutdown failed\n"); } }
int sdio_stop_clk(enum sdio_devtype devtype, int insert) { int rc; struct sdio_dev *dev; struct sdhci_host *host; rc = wifi_sdio_is_initialized(); if (rc <= 0) return -EFAULT; dev = get_wifi_dev(); host = dev->host; sdhci_pltfm_clk_enable(host, insert); return 0; }
static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdio_dev *dev; struct resource *iomem; struct sdio_platform_cfg *hw_cfg = NULL; char devname[MAX_DEV_NAME_SIZE]; int ret = 0; char *emmc_regulator = NULL; #ifdef CONFIG_MACH_BCM_FPGA u32 of_quirks = 0; u32 of_quirks2 = 0; #endif pr_debug("%s: ENTRY\n", __func__); BUG_ON(pdev == NULL); hw_cfg = (struct sdio_platform_cfg *)pdev->dev.platform_data; if (pdev->dev.of_node) { u32 val; const char *prop; if (!pdev->dev.platform_data) hw_cfg = kzalloc(sizeof(struct sdio_platform_cfg), GFP_KERNEL); if (!hw_cfg) { dev_err(&pdev->dev, "unable to allocate mem for private data\n"); ret = -ENOMEM; goto err; } if (of_property_read_u32(pdev->dev.of_node, "id", &val)) { dev_err(&pdev->dev, "id read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->id = val; pdev->id = val; if (of_property_read_u32(pdev->dev.of_node, "data-pullup", &val)) { dev_err(&pdev->dev, "data-pullup read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->data_pullup = val; if (of_property_read_u32(pdev->dev.of_node, "devtype", &val)) { dev_err(&pdev->dev, "devtype read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->devtype = val; if (of_property_read_u32(pdev->dev.of_node, "flags", &val)) { dev_err(&pdev->dev, "flags read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->flags = val; if (of_property_read_string(pdev->dev.of_node, "peri-clk-name", &prop)) { dev_err(&pdev->dev, "peri-clk-name read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->peri_clk_name = (char *)prop; if (of_property_read_string(pdev->dev.of_node, "ahb-clk-name", &prop)) { dev_err(&pdev->dev, "ahb-clk-name read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->ahb_clk_name = (char *)prop; if (of_property_read_string(pdev->dev.of_node, "sleep-clk-name", &prop)) { dev_err(&pdev->dev, "sleep-clk-name read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->sleep_clk_name = (char *)prop; if (of_property_read_u32(pdev->dev.of_node, "peri-clk-rate", &val)) { dev_err(&pdev->dev, "peri-clk-rate read failed in %s\n", __func__); goto err_free_priv_data_mem; } #ifdef CONFIG_MACH_BCM_FPGA if (of_property_read_u32(pdev->dev.of_node, "quirks", &of_quirks)) { pr_info("quirks = 0x%08x foud for the configuration\n", of_quirks); } if (of_property_read_u32(pdev->dev.of_node, "quirks2", &of_quirks2)) { pr_info("quirks2 = 0x%08x foud for the configuration\n", of_quirks2); } #endif hw_cfg->peri_clk_rate = val; if (hw_cfg->devtype == SDIO_DEV_TYPE_SDMMC) { if (of_property_read_string(pdev->dev.of_node, "vddo-regulator-name", &prop)) { dev_err(&pdev->dev, "vddo-regulator-name read "\ "failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->vddo_regulator_name = (char *)prop; if (of_property_read_string(pdev->dev.of_node, "vddsdxc-regulator-name", &prop)) { dev_err(&pdev->dev, "vddsdxc-regulator-name"\ "read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->vddsdxc_regulator_name = (char *)prop; if (of_property_read_u32(pdev->dev.of_node, "cd-gpio", &val)) { dev_err(&pdev->dev, "cd-gpio read failed in %s\n", __func__); hw_cfg->cd_gpio = -1; } hw_cfg->cd_gpio = val; } else if (hw_cfg->devtype == SDIO_DEV_TYPE_EMMC) { if (of_property_read_u32(pdev->dev.of_node, "is-8bit", &val)) { dev_err(&pdev->dev, "is-8bit read failed in %s\n", __func__); goto err_free_priv_data_mem; } hw_cfg->is_8bit = val; if (!(of_property_read_string(pdev->dev.of_node, "vddsdmmc-regulator-name", &prop))) emmc_regulator = (char *)prop; } pdev->dev.platform_data = hw_cfg; } if (!hw_cfg) { dev_err(&pdev->dev, "hw_cfg is NULL\n"); ret = -ENOMEM; goto err; } if (hw_cfg->devtype >= SDIO_DEV_TYPE_MAX) { dev_err(&pdev->dev, "unknown device type\n"); ret = -EFAULT; goto err; } pr_debug("%s: GET PLATFORM RESOURCES\n", __func__); iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { ret = -ENOMEM; goto err; } /* Some PCI-based MFD need the parent here */ if (pdev->dev.parent != &platform_bus) host = sdhci_alloc_host(pdev->dev.parent, sizeof(struct sdio_dev)); else host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdio_dev)); if (IS_ERR(host)) { ret = PTR_ERR(host); goto err; } pr_debug("%s: ALLOC HOST\n", __func__); host->hw_name = "bcm_kona_sd"; host->ops = &sdhci_pltfm_ops; host->irq = platform_get_irq(pdev, 0); host->quirks = SDHCI_QUIRK_NO_CARD_NO_RESET | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE; #ifdef CONFIG_MACH_RHEA_DALTON2_EB30 host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; #endif #ifdef CONFIG_MACH_BCM_FPGA host->quirks |= of_quirks; host->quirks2 |= of_quirks2; #endif pr_debug("%s: GET IRQ\n", __func__); if (hw_cfg->flags & KONA_SDIO_FLAGS_DEVICE_NON_REMOVABLE) host->mmc->caps |= MMC_CAP_NONREMOVABLE; if (!request_mem_region(iomem->start, resource_size(iomem), mmc_hostname(host->mmc))) { dev_err(&pdev->dev, "cannot request region\n"); ret = -EBUSY; goto err_free_host; } host->ioaddr = ioremap(iomem->start, resource_size(iomem)); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); ret = -ENOMEM; goto err_free_mem_region; } pr_debug("%s: MEM and IO REGION OKAY\n", __func__); dev = sdhci_priv(host); dev->dev = &pdev->dev; dev->host = host; dev->devtype = hw_cfg->devtype; dev->cd_gpio = hw_cfg->cd_gpio; host->mmc->parent = dev->dev; if (dev->devtype == SDIO_DEV_TYPE_WIFI) dev->wifi_gpio = &hw_cfg->wifi_gpio; if (dev->devtype == SDIO_DEV_TYPE_EMMC && emmc_regulator) { dev->vdd_sdxc_regulator = regulator_get(NULL, emmc_regulator); if (IS_ERR(dev->vdd_sdxc_regulator)) { dev->vdd_sdxc_regulator = NULL; } } if (dev->devtype == SDIO_DEV_TYPE_EMMC) host->detect_delay = 0; else host->detect_delay = 200; pr_debug("%s: DEV TYPE %x\n", __func__, dev->devtype); gDevs[dev->devtype] = dev; platform_set_drvdata(pdev, dev); snprintf(devname, sizeof(devname), "%s%d", DEV_NAME, pdev->id); /* enable clocks */ #ifdef CONFIG_MACH_BCM2850_FPGA if (clock) { /* clock override */ dev->clk_hz = clock; } else { dev->clk_hz = gClock[dev->devtype]; } #elif defined(CONFIG_MACH_BCM_FPGA) dev->clk_hz = hw_cfg->peri_clk_rate; #else /* peripheral clock */ dev->peri_clk = clk_get(&pdev->dev, hw_cfg->peri_clk_name); if (IS_ERR_OR_NULL(dev->peri_clk)) { ret = -EINVAL; goto err_unset_pltfm; } ret = clk_set_rate(dev->peri_clk, hw_cfg->peri_clk_rate); if (ret) goto err_peri_clk_put; /* sleep clock */ dev->sleep_clk = clk_get(&pdev->dev, hw_cfg->sleep_clk_name); if (IS_ERR_OR_NULL(dev->sleep_clk)) { ret = -EINVAL; goto err_peri_clk_put; } ret = clk_enable(dev->sleep_clk); if (ret) { dev_err(&pdev->dev, "failed to enable sleep clock for %s\n", devname); goto err_sleep_clk_put; } ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) { dev_err(&pdev->dev, "failed to initialize core clock for %s\n", devname); goto err_sleep_clk_disable; } dev->clk_hz = clk_get_rate(dev->peri_clk); #endif #if 0 /*** NANI To check mmc base clock ***/ printk( "[NANI] %s, %d : %s[%s], dev->clk_hz(%d)\n", __FUNCTION__, __LINE__, mmc_hostname(host->mmc), dev_name(mmc_dev(host->mmc)), dev->clk_hz ); if( !strcmp( mmc_hostname(host->mmc), "mmc0" ) ) { // KONA_MST_CLK_SDIO2_CLKGATE(0x3F00135C) // KONA_MST_CLK_SDIO2_DIV(0x3F001A2C) // clock.c - struct bus_clk CLK_NAME(sdio2_ahb) // KONA_MST_CLK_BASE_ADDR : 0x3F001000 // KPM_CLK_MGR_REG_SDIO2_CLKGATE_OFFSET : 0x0000035C // KPM_CLK_MGR_REG_SDIO2_DIV_OFFSET : 0x00000A2C printk( "[NANI] %s, %d : KONA_MST_CLK_SDIO2_CLKGATE == %#x, KONA_MST_CLK_SDIO2_DIV == %#x\n", __FUNCTION__, __LINE__, readl( IO_PHYS_TO_VIRT(0x3F001000) + 0x0000035C ), readl( IO_PHYS_TO_VIRT(0x3F001000) + 0x00000A2C ) ); } else if( !strcmp( mmc_hostname(host->mmc), "mmc2" ) ) { // KONA_MST_CLK_SDIO1_CLKGATE(0x3F001358) // KONA_MST_CLK_SDIO1_DIV(0x3F001A28) // clock.c - struct bus_clk CLK_NAME(sdio1_ahb) // KONA_MST_CLK_BASE_ADDR : 0x3F001000 // KPM_CLK_MGR_REG_SDIO1_CLKGATE_OFFSET : 0x00000358 // KPM_CLK_MGR_REG_SDIO1_DIV_OFFSET : 0x00000A28 printk( "[NANI] %s, %d : KONA_MST_CLK_SDIO1_CLKGATE == %#x, KONA_MST_CLK_SDIO1_DIV == %#x\n", __FUNCTION__, __LINE__, readl( IO_PHYS_TO_VIRT(0x3F001000) + 0x00000358 ), readl( IO_PHYS_TO_VIRT(0x3F001000) + 0x00000A28 ) ); } else { } #endif dev->suspended = 0; if (hw_cfg->vddo_regulator_name) { ret = sdhci_pltfm_regulator_init(dev, hw_cfg->vddo_regulator_name); #ifndef BCM_REGULATOR_SKIP_QUIRK if (ret < 0) goto err_term_clk; #endif } if (hw_cfg->vddsdxc_regulator_name && dev->devtype == SDIO_DEV_TYPE_SDMMC) { ret = sdhci_pltfm_regulator_sdxc_init(dev, hw_cfg->vddsdxc_regulator_name); #ifndef BCM_REGULATOR_SKIP_QUIRK if (ret < 0) goto err_term_clk; #endif } if (sd_detection_cmd_dev == NULL){ sd_detection_cmd_dev = device_create(sec_class, NULL, 0, NULL, "sdcard"); if (IS_ERR(sd_detection_cmd_dev)) pr_err("Fail to create sysfs dev\n"); if (device_create_file(sd_detection_cmd_dev, &dev_attr_status) < 0) pr_err("Fail to create sysfs file\n"); } mutex_init(&dev->regulator_lock); kona_sdio_regulator_power(dev, 1); ret = bcm_kona_sd_reset(dev); if (ret) goto err_term_clk; ret = bcm_kona_sd_init(dev); if (ret) goto err_reset; if (hw_cfg->is_8bit) host->mmc->caps |= MMC_CAP_8_BIT_DATA; /* Note that sdhci_add_host calls --> mmc_add_host, which in turn * checks for the flag MMC_PM_IGNORE_PM_NOTIFY before registering a PM * notifier for the specific instance of SDIO host controller. For * WiFi case, we don't want to get notified, becuase then from there * mmc_power_off is called which will reset the Host registers that * needs to be re-programmed by starting SDIO handsake again. We want * to prevent this in case of WiFi. So enable MMC_PM_IGNORE_PM_NOTIFY * flag, so that notifier never gets registered. */ if (dev->devtype == SDIO_DEV_TYPE_WIFI) { /* The Wireless LAN drivers call the API sdio_get_host_pm_caps * to know the PM capabilities of the driver, which would * return pm_caps. While the internal code decides based on * pm_flags, the pm_caps also should reflect the same. */ host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY; host->mmc->pm_flags = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY; } #if !defined(CONFIG_MACH_BCM_FPGA_E) /* Enable 1.8V DDR operation for e.MMC */ if (dev->devtype == SDIO_DEV_TYPE_EMMC) host->mmc->caps |= MMC_CAP_1_8V_DDR; #endif /* Don't issue SLEEP command to e.MMC device */ if (dev->devtype == SDIO_DEV_TYPE_EMMC) /*host->mmc->caps2 |= MMC_CAP2_NO_SLEEP_CMD;*/ host->mmc->pm_flags = MMC_PM_KEEP_POWER; /* * This has to be done before sdhci_add_host. * As soon as we add the host, request * starts. If we dont enable this here, the * runtime get and put of sdhci will fallback to * clk_enable and clk_disable which will conflict * with the PM runtime when it gets enabled just * after sdhci_add_host. Now with this, the RPM * calls will fail until RPM is enabled, but things * will work well, as we have clocks enabled till the * probe ends. */ dev->runtime_pm_enabled = 1; ret = sdhci_add_host(host); if (ret) goto err_reset; ret = proc_init(pdev); if (ret) goto err_rm_host; /* Should be done only after sdhci_add_host */ sdhci_pltfm_runtime_pm_init(dev->dev); if (dev->devtype == SDIO_DEV_TYPE_SDMMC) { /* support SD card detect interrupts for insert/removal */ host->mmc->card_detect_cap = true; } /* if device is eMMC, emulate card insert right here */ if (dev->devtype == SDIO_DEV_TYPE_EMMC) { ret = bcm_kona_sd_card_emulate(dev, 1); if (ret) { dev_err(&pdev->dev, "unable to emulate card insertion\n"); goto err_proc_term; } pr_info("%s: card insert emulated!\n", devname); } else if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) { dev->cd_int_wake_lock_name = kasprintf(GFP_KERNEL, "%s_cd_int", devname); if (!dev->cd_int_wake_lock_name) { dev_err(&pdev->dev, "error allocating mem for wake_lock_name\n"); goto err_proc_term; } wake_lock_init(&dev->cd_int_wake_lock, WAKE_LOCK_SUSPEND, dev->cd_int_wake_lock_name); ret = gpio_request(dev->cd_gpio, "sdio cd"); if (ret < 0) { dev_err(&pdev->dev, "Unable to request GPIO pin %d\n", dev->cd_gpio); goto err_proc_term; } gpio_direction_input(dev->cd_gpio); ret = request_threaded_irq(gpio_to_irq(dev->cd_gpio), NULL, sdhci_pltfm_cd_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "sdio cd", dev); if (ret) { dev_err(&pdev->dev, "Unable to request card detection irq=%d" " for gpio=%d\n", gpio_to_irq(dev->cd_gpio), dev->cd_gpio); goto err_free_cd_gpio; } /* Set debounce for SD Card detect to maximum value (128ms) * * NOTE-1: If gpio_set_debounce() returns error we still * continue with the default debounce value set. Another reason * for doing this is that on rhea-ray boards the SD Detect GPIO * is on GPIO Expander and gpio_set_debounce() will return error * and if we return error from here, then probe() would fail and * SD detection would always fail. * * NOTE-2: We also give a msleep() of the "debounce" time here * so that we give enough time for the debounce to stabilize * before we read the gpio value in gpio_get_value_cansleep(). */ ret = gpio_set_debounce(dev->cd_gpio, (SD_DETECT_GPIO_DEBOUNCE_128MS * 1000)); if (ret < 0) { dev_err(&pdev->dev, "%s: gpio set debounce failed." "default debounce value assumed\n", __func__); } /* Sleep for 128ms to allow debounce to stabilize */ msleep(SD_DETECT_GPIO_DEBOUNCE_128MS); /* * Since the card detection GPIO interrupt is configured to be * edge sensitive, check the initial GPIO value here, emulate * only if the card is present */ if (gpio_get_value_cansleep(dev->cd_gpio) == 0) { printk("%s - external SD Card is detected by GPIO\n",__func__); bcm_kona_sd_card_emulate(dev, 1); } else { printk("%s - SD Card is Not detected by GPIO-->Disable SDXLDO\n",__func__); /* If card is not present disable the regulator */ kona_sdio_regulator_power(dev, 0); } } /* Force insertion interrupt, in case of no card detect registered. */ if (dev->cd_gpio < 0) bcm_kona_sd_card_emulate(dev, 1); #ifdef CONFIG_BRCM_UNIFIED_DHD_SUPPORT if ((dev->devtype == SDIO_DEV_TYPE_WIFI) && (hw_cfg->register_status_notify != NULL)) { hw_cfg->register_status_notify(kona_sdio_status_notify_cb, host); } pr_debug("%s: CALL BACK IS REGISTERED\n", __func__); #endif atomic_set(&dev->initialized, 1); sdhci_pltfm_clk_enable(dev, 0); pr_info("%s: initialized properly\n", devname); return 0; err_free_cd_gpio: if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) gpio_free(dev->cd_gpio); err_proc_term: proc_term(pdev); err_rm_host: sdhci_remove_host(host, 0); err_reset: bcm_kona_sd_reset(dev); err_term_clk: sdhci_pltfm_clk_enable(dev, 0); #if !defined(CONFIG_MACH_BCM2850_FPGA) && !defined(CONFIG_MACH_BCM_FPGA) err_sleep_clk_disable: clk_disable(dev->sleep_clk); err_sleep_clk_put: clk_put(dev->sleep_clk); err_peri_clk_put: clk_put(dev->peri_clk); err_unset_pltfm: platform_set_drvdata(pdev, NULL); iounmap(host->ioaddr); #endif err_free_mem_region: release_mem_region(iomem->start, resource_size(iomem)); err_free_host: sdhci_free_host(host); err_free_priv_data_mem: if (pdev->dev.of_node) { ret = -EFAULT; kfree(hw_cfg); } err: pr_err("Probing of sdhci-pltfm %d failed: %d\n", pdev->id, ret); return ret; }
/* * Software emulation of the SD card insertion/removal. Set insert=1 for insert * and insert=0 for removal */ static int bcm_kona_sd_card_emulate(struct sdio_dev *dev, int insert) { struct sdhci_host *host = dev->host; uint32_t val; unsigned long flags; int ret = 0; if(strcmp("mmc2", mmc_hostname(host->mmc)) == 0) printk ("PNN: [%s]sd_card_emulate : %s\n",mmc_hostname(host->mmc), insert ? "insert" : "removal"); #ifndef CONFIG_ARCH_ISLAND /* * The clock enabled here will be disabled in * sdhci_tasklet_card */ if (sdhci_pltfm_rpm_enabled(dev)) { /* * The code below can be executed just * after a device resume. pm core * enables the runtime pm for the device * when the resume callback returns. * It is possible that we reach here before * that. One option is to wait for the RPM * to be enabled, but this can create an * obvious issue when we perform card * insert/removal during the probe. We cant * remove the pm_runtime_get_sync with a * direct clock enable here, because the * sdhci_irq will complain about "interrupt * while runtime suspened". We cant even check * for pm_runtime status and take an appropriate * action, because if the status changes by the * time the clcok disable is done in card tasklet, * it will result in unbalanced RPM usage. Moreover * why to wait for something in an ISR when we have * an option. * So a better option is to do both. */ pm_runtime_get_sync(dev->dev); } /* Enable clock once irrespective of RPM state */ ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) { dev_err(dev->dev, "enable clock during card emulate failed\n"); return -EAGAIN; } #endif /* this function can be called from various contexts including ISR */ spin_lock_irqsave(&host->lock, flags); /* Ensure SD bus scanning to detect media change */ host->mmc->rescan_disable = 0; /* Back-to-Back register write needs a delay of min 10uS. * We keep 20uS */ udelay(20); val = sdhci_readl(host, KONA_SDHOST_CORESTAT); if (insert) { val |= KONA_SDHOST_CD_SW; sdhci_writel(host, val, KONA_SDHOST_CORESTAT); } else { val &= ~KONA_SDHOST_CD_SW; sdhci_writel(host, val, KONA_SDHOST_CORESTAT); } spin_unlock_irqrestore(&host->lock, flags); return 0; }
static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) { struct sdio_dev *dev = platform_get_drvdata(pdev); struct sdhci_host *host = dev->host; struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int dead; u32 scratch; int ret = 0; atomic_set(&dev->initialized, 0); gDevs[dev->devtype] = NULL; printk("%s",__func__); if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) { free_irq(gpio_to_irq(dev->cd_gpio), dev); gpio_free(dev->cd_gpio); } if (dev->vdd_sdxc_regulator && dev->devtype == SDIO_DEV_TYPE_SDMMC) { /* Playing safe- if regulator is enabled, disable it first */ if (regulator_is_enabled(dev->vdd_sdxc_regulator) > 0) regulator_disable(dev->vdd_sdxc_regulator); regulator_put(dev->vdd_sdxc_regulator); } proc_term(pdev); if (sdhci_pltfm_rpm_enabled(dev)) { pm_runtime_get_sync(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 1); if (ret) dev_err(dev->dev, "enable clock during pltfm remove failed\n"); } dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) dead = 1; sdhci_remove_host(host, dead); if (sdhci_pltfm_rpm_enabled(dev)) { pm_runtime_put_sync_suspend(dev->dev); } else { ret = sdhci_pltfm_clk_enable(dev, 0); if (ret) dev_err(dev->dev, "disable clock during pltfm remove failed\n"); } #if !defined(CONFIG_MACH_BCM2850_FPGA) && !defined(CONFIG_MACH_BCM_FPGA) clk_disable(dev->sleep_clk); clk_put(dev->sleep_clk); clk_put(dev->peri_clk); #endif sdhci_pltfm_runtime_pm_forbid(dev->dev); kfree(dev->cd_int_wake_lock_name); wake_lock_destroy(&dev->cd_int_wake_lock); platform_set_drvdata(pdev, NULL); if (dev->devtype == SDIO_DEV_TYPE_EMMC || dev->devtype == SDIO_DEV_TYPE_SDMMC) { kfree(pdev->dev.platform_data); pdev->dev.platform_data = NULL; } kfree(dev); iounmap(host->ioaddr); release_mem_region(iomem->start, resource_size(iomem)); sdhci_free_host(host); return 0; }
static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdio_dev *dev; struct resource *iomem; struct sdio_platform_cfg *hw_cfg; char devname[MAX_DEV_NAME_SIZE]; int ret; pr_debug("%s: ENTRY\n", __func__); BUG_ON(pdev == NULL); if (pdev->dev.platform_data == NULL) { dev_err(&pdev->dev, "platform_data missing\n"); ret = -EFAULT; goto err; } pr_debug("%s: GET PLATFORM DATA\n", __func__); hw_cfg = (struct sdio_platform_cfg *)pdev->dev.platform_data; if (hw_cfg->devtype >= SDIO_DEV_TYPE_MAX) { dev_err(&pdev->dev, "unknown device type\n"); ret = -EFAULT; goto err; } pr_debug("%s: GET PLATFORM RESOURCES\n", __func__); iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { ret = -ENOMEM; goto err; } /* Some PCI-based MFD need the parent here */ if (pdev->dev.parent != &platform_bus) host = sdhci_alloc_host(pdev->dev.parent, sizeof(struct sdio_dev)); else host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdio_dev)); if (IS_ERR(host)) { ret = PTR_ERR(host); goto err; } pr_debug("%s: ALLOC HOST\n", __func__); host->hw_name = "bcm_kona_sd"; host->ops = &sdhci_pltfm_ops; host->irq = platform_get_irq(pdev, 0); host->quirks = SDHCI_QUIRK_NO_CARD_NO_RESET | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE; pr_debug("%s: GET IRQ\n", __func__); if (hw_cfg->flags & KONA_SDIO_FLAGS_DEVICE_NON_REMOVABLE) host->mmc->caps |= MMC_CAP_NONREMOVABLE; if (!request_mem_region(iomem->start, resource_size(iomem), mmc_hostname(host->mmc))) { dev_err(&pdev->dev, "cannot request region\n"); ret = -EBUSY; goto err_free_host; } host->ioaddr = ioremap(iomem->start, resource_size(iomem)); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); ret = -ENOMEM; goto err_free_mem_region; } pr_debug("%s: MEM and IO REGION OKAY\n", __func__); dev = sdhci_priv(host); dev->dev = &pdev->dev; dev->host = host; dev->devtype = hw_cfg->devtype; dev->cd_gpio = hw_cfg->cd_gpio; dev->wp_gpio = hw_cfg->wp_gpio; if (dev->devtype == SDIO_DEV_TYPE_WIFI) dev->wifi_gpio = &hw_cfg->wifi_gpio; /* * In the corresponding mmc_host->caps filed, need to * expose the MMC_CAP_DISABLE capability only for SD Card interface. * Note that for now we are exposing Dynamic Power Management * capability on the interface that suppors SD Card. * * When we finally decide to do away with managing clocks from sdhci.c * and when we enable the DISABLED state management, we need to * enable this capability for ALL SDIO interfaces. For WLAN interface * we should ensure that the regulator is NOT turned OFF so that the * handshakes need not happen again. */ if (dev->devtype == SDIO_DEV_TYPE_SDMMC) { host->mmc->caps |= MMC_CAP_DISABLE; /* * There are multiple paths that can trigger disable work. * One common path is from * mmc/card/block.c function, mmc_blk_issue_rq after the * transfer is done. * mmc_release_host-->mmc_host_lazy_disable, this starts the * mmc disable work only if host->disable_delay is non zero. * So we need to set disable_delay otherwise the work will never * get scheduled. */ mmc_set_disable_delay(host->mmc, KONA_SDMMC_DISABLE_DELAY); } pr_debug("%s: DEV TYPE %x\n", __func__, dev->devtype); gDevs[pdev->id] = dev; platform_set_drvdata(pdev, dev); snprintf(devname, sizeof(devname), "%s%d", DEV_NAME, pdev->id); /* enable clocks */ #if defined(CONFIG_MACH_BCM2850_FPGA) || defined(CONFIG_MACH_CAPRI_FPGA) if (clock) { /* clock override */ dev->clk_hz = clock; } else { dev->clk_hz = gClock[dev->devtype]; } #else /* peripheral clock */ dev->peri_clk = clk_get(&pdev->dev, "peri_clk"); if (IS_ERR_OR_NULL(dev->peri_clk)) { ret = -EINVAL; goto err_unset_pltfm; } ret = clk_set_rate(dev->peri_clk, hw_cfg->peri_clk_rate); if (ret) goto err_peri_clk_put; /* sleep clock */ dev->sleep_clk = clk_get(&pdev->dev, "sleep_clk"); if (IS_ERR_OR_NULL(dev->sleep_clk)) { ret = -EINVAL; goto err_peri_clk_put; } ret = clk_enable(dev->sleep_clk); if (ret) { dev_err(&pdev->dev, "failed to enable sleep clock for %s\n", devname); goto err_sleep_clk_put; } ret = sdhci_pltfm_clk_enable(host, 1); if (ret) { dev_err(&pdev->dev, "failed to initialize core clock for %s\n", devname); goto err_sleep_clk_disable; } dev->clk_hz = clk_get_rate(dev->peri_clk); #endif dev->suspended = 0; ret = sdhci_pltfm_regulator_init(pdev, hw_cfg); if (ret < 0) { dev_err(&pdev->dev, "failed to initialize regulator for %s\n", devname); goto err_term_clk; } /* * Regulators are NOT turned ON in the above functions. * So leave them in OFF state and they'll be handled * appropriately in enable path. */ dev->dpm_state = OFF; if (sd_detection_cmd_dev == NULL){ sd_detection_cmd_dev = device_create(sec_class, NULL, 0, NULL, "sdcard"); if (IS_ERR(sd_detection_cmd_dev)) pr_err("Fail to create sysfs dev\n"); if (device_create_file(sd_detection_cmd_dev, &dev_attr_status) < 0) pr_err("Fail to create sysfs file\n"); } ret = bcm_kona_sd_reset(dev); if (ret) goto err_term_regulator; ret = bcm_kona_sd_init(dev); if (ret) goto err_reset; if (hw_cfg->is_8bit) host->mmc->caps |= MMC_CAP_8_BIT_DATA; /* Note that sdhci_add_host calls --> mmc_add_host, which in turn * checks for the flag MMC_PM_IGNORE_PM_NOTIFY before registering a PM * notifier for the specific instance of SDIO host controller. For * WiFi case, we don't want to get notified, becuase then from there * mmc_power_off is called which will reset the Host registers that * needs to be re-programmed by starting SDIO handsake again. We want * to prevent this in case of WiFi. So enable MMC_PM_IGNORE_PM_NOTIFY * flag, so that notifier never gets registered. */ if (dev->devtype == SDIO_DEV_TYPE_WIFI) { /* The Wireless LAN drivers call the API sdio_get_host_pm_caps * to know the PM capabilities of the driver, which would * return pm_caps. While the internal code decides based on * pm_flags, the pm_caps also should reflect the same. */ host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY; host->mmc->pm_flags = MMC_PM_KEEP_POWER | MMC_PM_IGNORE_PM_NOTIFY; } /* Enable 1.8V DDR operation for e.MMC */ if (dev->devtype == SDIO_DEV_TYPE_EMMC) host->mmc->caps |= MMC_CAP_1_8V_DDR; /* * Temporary UHS support only for eMMC as it does not need volatge level * adjustment. The SD card will not be able to support UHS until the PMU * regulator framework is integrated */ if (hw_cfg->tmp_uhs) host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50; ret = sdhci_add_host(host); if (ret) goto err_reset; ret = proc_init(pdev); if (ret) goto err_rm_host; /* if device is eMMC, emulate card insert right here */ if (dev->devtype == SDIO_DEV_TYPE_EMMC) { ret = bcm_kona_sd_card_emulate(dev, 1); if (ret) { dev_err(&pdev->dev, "unable to emulate card insertion\n"); goto err_proc_term; } pr_info("%s: card insert emulated!\n", devname); } else if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) { ret = gpio_request(dev->cd_gpio, "sdio cd"); if (ret < 0) { dev_err(&pdev->dev, "Unable to request GPIO pin %d\n", dev->cd_gpio); goto err_proc_term; } gpio_direction_input(dev->cd_gpio); /* support SD card detect interrupts for insert/removal */ host->mmc->card_detect_cap = true; /* Set debounce for SD Card detect to maximum value (128ms) * * NOTE-1: If gpio_set_debounce() returns error we still * continue with the default debounce value set. Another reason * for doing this is that on rhea-ray boards the SD Detect GPIO * is on GPIO Expander and gpio_set_debounce() will return error * and if we return error from here, then probe() would fail and * SD detection would always fail. * * NOTE-2: We also give a msleep() of the "debounce" time here * so that we give enough time for the debounce to stabilize * before we read the gpio value in gpio_get_value_cansleep(). */ ret = gpio_set_debounce(dev->cd_gpio, (SD_DETECT_GPIO_DEBOUNCE_128MS * 1000)); if (ret < 0) { dev_err(&pdev->dev, "%s: gpio set debounce failed." "default debounce value assumed\n", __func__); } /* Sleep for 128ms to allow debounce to stabilize */ msleep(SD_DETECT_GPIO_DEBOUNCE_128MS); /* request irq for cd_gpio after the gpio debounce is * stabilized, otherwise, some bogus gpio interrupts might be * triggered. */ ret = request_threaded_irq(gpio_to_irq(dev->cd_gpio), NULL, sdhci_pltfm_cd_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "sdio cd", dev); if (ret) { dev_err(&pdev->dev, "Unable to request card detection irq=%d" " for gpio=%d\n", gpio_to_irq(dev->cd_gpio), dev->cd_gpio); goto err_free_cd_gpio; } if (dev->wp_gpio >= 0) { ret = gpio_request(dev->wp_gpio, "sdio wp"); if (ret < 0) { dev_err(&pdev->dev, "Unable to request WP pin %d\n", dev->wp_gpio); dev->wp_gpio = -1; } else { gpio_direction_input(dev->wp_gpio); } } /* * Since the card detection GPIO interrupt is configured to be * edge sensitive, check the initial GPIO value here, emulate * only if the card is present */ if (gpio_get_value_cansleep(dev->cd_gpio) == 0) bcm_kona_sd_card_emulate(dev, 1); } #ifdef CONFIG_BRCM_UNIFIED_DHD_SUPPORT if ((dev->devtype == SDIO_DEV_TYPE_WIFI) && (hw_cfg->register_status_notify != NULL)) { hw_cfg->register_status_notify(kona_sdio_status_notify_cb, host); } pr_debug("%s: CALL BACK IS REGISTERED\n", __func__); #endif if (dev->vdd_sdxc_regulator) if (regulator_is_enabled(dev->vdd_sdxc_regulator) > 0) regulator_disable(dev->vdd_sdxc_regulator); if (dev->vddo_sd_regulator) if (regulator_is_enabled(dev->vddo_sd_regulator) > 0) regulator_disable(dev->vddo_sd_regulator); atomic_set(&dev->initialized, 1); sdhci_pltfm_clk_enable(host, 0); #ifdef CONFIG_ARCH_CAPRI /* * If the device is WiFi, disable pullup and enable pulldown on SDIO * pins by default, to save power. Pullup only needs to be enabled * when WiFi is in use */ if (dev->devtype == SDIO_DEV_TYPE_WIFI) capri_pm_sdio_pinmux_ctrl(pdev->id, 1); #endif pr_info("%s: initialized properly\n", devname); return 0; err_free_cd_gpio: if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) gpio_free(dev->cd_gpio); err_proc_term: proc_term(pdev); err_rm_host: sdhci_remove_host(host, 0); err_reset: bcm_kona_sd_reset(dev); err_term_regulator: sdhci_pltfm_regulator_term(pdev); err_term_clk: sdhci_pltfm_clk_enable(host, 0); #ifndef CONFIG_MACH_BCM2850_FPGA err_sleep_clk_disable: clk_disable(dev->sleep_clk); err_sleep_clk_put: clk_put(dev->sleep_clk); err_peri_clk_put: clk_put(dev->peri_clk); #endif err_unset_pltfm: platform_set_drvdata(pdev, NULL); iounmap(host->ioaddr); err_free_mem_region: release_mem_region(iomem->start, resource_size(iomem)); err_free_host: sdhci_free_host(host); err: pr_err("Probing of sdhci-pltfm %d failed: %d\n", pdev->id, ret); return ret; }
static int sdhci_pltfm_suspend(struct platform_device *pdev, pm_message_t state) { struct sdio_dev *dev = platform_get_drvdata(pdev); struct sdhci_host *host = dev->host; if (dev->devtype == SDIO_DEV_TYPE_WIFI) { host->mmc->pm_flags |= host->mmc->pm_caps; printk(KERN_DEBUG "%s: pm_flags=0x%08x\n", __FUNCTION__, host->mmc->pm_flags); sdhci_suspend_host(host, state); } #if 0 if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) free_irq(gpio_to_irq(dev->cd_gpio), dev); #endif flush_work_sync(&host->wait_erase_work); /* * If the device type is WIFI, and WiFi is enabled, * turn off the clock since currently * the WIFI driver does not support turning on/off the * clock dynamicly. */ if (dev->devtype == SDIO_DEV_TYPE_WIFI && sdhci_test_sdio_enabled(dev)) sdhci_pltfm_clk_enable(host, 0); /* * Move Dynamic Power Management State machine to OFF state to * ensure the SD card regulators are turned-off during suspend. * * State Machine: * * ENABLED -> DISABLED -> OFF * ^___________| | * |______________________| * * Delayed workqueue host->mmc->disable (mmc_host_deeper_disable) is * scheduled twice: * mmc_host_lazy_disable queues host->mmc->disable for 100ms delay * 1st Entry(after 100ms): work function(mmc_host_deeper_disable) * moves the DPM state: ENABLED -> DISABLED [lazy disable] and * and queues the workqueue host->mmc->disable again for 8s delay * * 2nd Entry(after 8s): work function(mmc_host_deeper_disable) moves * the DPM state: DISABLED -> OFF [deeper disable] this time to * turn-off the SD card/IO regulators. * * We need to call flush_delayed_work_sync twice to ensure the SD card * DPM is moved to OFF state. * */ flush_delayed_work_sync(&host->mmc->disable); flush_delayed_work_sync(&host->mmc->disable); dev->suspended = 1; if(dev->devtype == SDIO_DEV_TYPE_SDMMC) { mdelay(STABLE_TIME_BEFORE_SUSPEND_MS); } return 0; }
static void sdhci_pltfm_shutdown(struct platform_device *pdev) { struct sdio_dev *dev = platform_get_drvdata(pdev); struct sdhci_host *host = dev->host; int dead; u32 scratch; /* Skip shutdown for EMMC device if not explicily requested */ if (dev->devtype == SDIO_DEV_TYPE_EMMC && !dev->remove_card) return; atomic_set(&dev->initialized, 0); gDevs[pdev->id] = NULL; sdhci_pltfm_clk_enable(host, 1); dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32) -1) dead = 1; sdhci_remove_host(host, dead); sdhci_pltfm_clk_enable(host, 0); if (dev->devtype == SDIO_DEV_TYPE_SDMMC && dev->cd_gpio >= 0) { free_irq(gpio_to_irq(dev->cd_gpio), dev); gpio_free(dev->cd_gpio); if (dev->wp_gpio >= 0) { gpio_free(dev->wp_gpio); dev->wp_gpio = -1; } } if (dev->vddo_sd_regulator) { /* Playing safe- if regulator is enabled, disable it first */ if (regulator_is_enabled(dev->vddo_sd_regulator) > 0) regulator_disable(dev->vddo_sd_regulator); regulator_put(dev->vddo_sd_regulator); dev->vddo_sd_regulator = NULL; } if (dev->vdd_sdxc_regulator) { /* Playing safe- if regulator is enabled, disable it first */ if (regulator_is_enabled(dev->vdd_sdxc_regulator) > 0) regulator_disable(dev->vdd_sdxc_regulator); regulator_put(dev->vdd_sdxc_regulator); dev->vdd_sdxc_regulator = NULL; } proc_term(pdev); if(dev->devtype == SDIO_DEV_TYPE_SDMMC) { mdelay(STABLE_TIME_BEFORE_SHUTDOWN_MS); } #ifndef CONFIG_MACH_BCM2850_FPGA clk_disable(dev->sleep_clk); clk_put(dev->sleep_clk); clk_put(dev->peri_clk); #endif }