static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret = 0; printk(KERN_INFO "%s (%s) ++ \n", __func__, mmc_hostname(host->sdhci->mmc)); if (time_before(jiffies, host->card_detection_time + msecs_to_jiffies(SD_TIME_GAP_FOR_SUSPEND))) { printk(KERN_INFO "%s: Prevent from going to suspend mode too soon \n", __func__); return -1; } if (host->irq_cd != -1) disable_irq(host->irq_cd); if (host->card_always_on && is_card_sdio(host->sdhci->mmc->card)) { int div = 0; u16 clk; unsigned int clock = 100000; if (device_may_wakeup(&pdev->dev)) { enable_irq_wake(host->sdhci->irq); } /* save interrupt status before suspending */ host->sdhci_ints = sdhci_readl(host->sdhci, SDHCI_INT_ENABLE); /* reduce host controller clk and card clk to 100 KHz */ tegra_sdhci_set_clock(host->sdhci, clock); sdhci_writew(host->sdhci, 0, SDHCI_CLOCK_CONTROL); if (host->sdhci->max_clk > clock) { div = 1 << (fls(host->sdhci->max_clk / clock) - 2); if (div > 128) div = 128; } clk = div << SDHCI_DIVIDER_SHIFT; clk |= SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_CARD_EN; sdhci_writew(host->sdhci, clk, SDHCI_CLOCK_CONTROL); return ret; } /* * Set disable_delay to zero * to disable mmc_schedule_delay_work * before suspend */ mmc_set_disable_delay(host->sdhci->mmc, 0); ret = sdhci_suspend_host(host->sdhci, state); if (ret) pr_err("%s: failed, error = %d\n", __func__, ret); tegra_sdhci_enable_clock(host, 0); printk(KERN_INFO "%s (%s) -- \n", __func__, mmc_hostname(host->sdhci->mmc)); return ret; }
static int __init omap_hsmmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; struct omap_hsmmc_host *host = NULL; struct resource *res; int ret = 0, irq; if (pdata == NULL) { dev_err(&pdev->dev, "Platform Data is missing\n"); return -ENXIO; } if (pdata->nr_slots == 0) { dev_err(&pdev->dev, "No Slots\n"); return -ENXIO; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (res == NULL || irq < 0) return -ENXIO; res = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (res == NULL) return -EBUSY; mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev); if (!mmc) { ret = -ENOMEM; goto err; } host = mmc_priv(mmc); host->mmc = mmc; host->pdata = pdata; host->dev = &pdev->dev; host->use_dma = 1; host->dev->dma_mask = &pdata->dma_mask; host->dma_ch = -1; host->irq = irq; host->id = pdev->id; host->slot_id = 0; host->mapbase = res->start; host->base = ioremap(host->mapbase, SZ_4K); host->power_mode = -1; platform_set_drvdata(pdev, host); INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); if (mmc_slot(host).power_saving) mmc->ops = &omap_hsmmc_ps_ops; else mmc->ops = &omap_hsmmc_ops; mmc->f_min = 400000; mmc->f_max = 52000000; sema_init(&host->sem, 1); spin_lock_init(&host->irq_lock); host->iclk = clk_get(&pdev->dev, "ick"); if (IS_ERR(host->iclk)) { ret = PTR_ERR(host->iclk); host->iclk = NULL; goto err1; } host->fclk = clk_get(&pdev->dev, "fck"); if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); host->fclk = NULL; clk_put(host->iclk); goto err1; } omap_hsmmc_context_save(host); mmc->caps |= MMC_CAP_DISABLE; mmc_set_disable_delay(mmc, OMAP_MMC_DISABLED_TIMEOUT); /* we start off in DISABLED state */ host->dpm_state = DISABLED; if (mmc_host_enable(host->mmc) != 0) { clk_put(host->iclk); clk_put(host->fclk); goto err1; } if (clk_enable(host->iclk) != 0) { mmc_host_disable(host->mmc); clk_put(host->iclk); clk_put(host->fclk); goto err1; } if (cpu_is_omap2430()) { host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); /* * MMC can still work without debounce clock. */ if (IS_ERR(host->dbclk)) dev_warn(mmc_dev(host->mmc), "Failed to get debounce clock\n"); else host->got_dbclk = 1; if (host->got_dbclk) if (clk_enable(host->dbclk) != 0) dev_dbg(mmc_dev(host->mmc), "Enabling debounce" " clk failed\n"); } /* Since we do only SG emulation, we can have as many segs * as we want. */ mmc->max_phys_segs = 1024; mmc->max_hw_segs = 1024; mmc->max_blk_size = 512; /* Block Length at max can be 1024 */ mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_seg_size = mmc->max_req_size; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY; if (mmc_slot(host).wires >= 8) mmc->caps |= MMC_CAP_8_BIT_DATA; else if (mmc_slot(host).wires >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; if (mmc_slot(host).nonremovable) mmc->caps |= MMC_CAP_NONREMOVABLE; omap_hsmmc_conf_bus_power(host); /* Select DMA lines */ switch (host->id) { case OMAP_MMC1_DEVID: host->dma_line_tx = OMAP24XX_DMA_MMC1_TX; host->dma_line_rx = OMAP24XX_DMA_MMC1_RX; break; case OMAP_MMC2_DEVID: host->dma_line_tx = OMAP24XX_DMA_MMC2_TX; host->dma_line_rx = OMAP24XX_DMA_MMC2_RX; break; case OMAP_MMC3_DEVID: host->dma_line_tx = OMAP34XX_DMA_MMC3_TX; host->dma_line_rx = OMAP34XX_DMA_MMC3_RX; break; case OMAP_MMC4_DEVID: host->dma_line_tx = OMAP44XX_DMA_MMC4_TX; host->dma_line_rx = OMAP44XX_DMA_MMC4_RX; break; case OMAP_MMC5_DEVID: host->dma_line_tx = OMAP44XX_DMA_MMC5_TX; host->dma_line_rx = OMAP44XX_DMA_MMC5_RX; break; default: dev_err(mmc_dev(host->mmc), "Invalid MMC id\n"); goto err_irq; } /* Request IRQ for MMC operations */ ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); goto err_irq; } /* initialize power supplies, gpios, etc */ if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { dev_dbg(mmc_dev(host->mmc), "Unable to configure MMC IRQs\n"); goto err_irq_cd_init; } } mmc->ocr_avail = mmc_slot(host).ocr_mask; /* Request IRQ for card detect */ if ((mmc_slot(host).card_detect_irq)) { ret = request_irq(mmc_slot(host).card_detect_irq, omap_hsmmc_cd_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED, mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab MMC CD IRQ\n"); goto err_irq_cd; } } OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); mmc_host_lazy_disable(host->mmc); omap_hsmmc_protect_card(host); mmc_add_host(mmc); if (mmc_slot(host).name != NULL) { ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name); if (ret < 0) goto err_slot_name; } if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) { ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch); if (ret < 0) goto err_cover_switch; } omap_hsmmc_debugfs(mmc); return 0; err_cover_switch: device_remove_file(&mmc->class_dev, &dev_attr_cover_switch); err_slot_name: mmc_remove_host(mmc); err_irq_cd: free_irq(mmc_slot(host).card_detect_irq, host); err_irq_cd_init: free_irq(host->irq, host); err_irq: mmc_host_disable(host->mmc); clk_disable(host->iclk); clk_put(host->fclk); clk_put(host->iclk); if (host->got_dbclk) { clk_disable(host->dbclk); clk_put(host->dbclk); } err1: iounmap(host->base); err: dev_dbg(mmc_dev(host->mmc), "Probe Failed\n"); release_mem_region(res->start, res->end - res->start + 1); if (host) mmc_free_host(mmc); return ret; }
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 tegra_sdhci_resume(struct platform_device *pdev) { struct tegra_sdhci_host *host = platform_get_drvdata(pdev); int ret; u8 pwr; if (host->card_always_on && is_card_sdio(host->sdhci->mmc->card)) { int ret = 0; if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(host->sdhci->irq); } /* soft reset SD host controller and enable interrupts */ ret = tegra_sdhci_restore(host->sdhci); if (ret) { pr_err("%s: failed, error = %d\n", __func__, ret); return ret; } mmiowb(); host->sdhci->mmc->ops->set_ios(host->sdhci->mmc, &host->sdhci->mmc->ios); return 0; } if (host->cd_gpio != -1) { bool card_status_before_suspend = host->card_present; if (host->cd_gpio != -1) { host->card_present = host->card_present_old = (gpio_get_value(host->cd_gpio) == host->cd_gpio_polarity); } pr_info("%s: card_status_before_suspend=%d, card_present=%d \n", __func__, card_status_before_suspend, host->card_present); if (card_status_before_suspend != host->card_present) { if (!host->card_present) { #ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME mmc_set_bus_resume_policy(host->sdhci->mmc, 0); #endif } } } tegra_sdhci_enable_clock(host, 1); pwr = SDHCI_POWER_ON; sdhci_writeb(host->sdhci, pwr, SDHCI_POWER_CONTROL); host->sdhci->pwr = 0; /* * Set disable_delay * to enable mmc_schedule_delay_work */ mmc_set_disable_delay(host->sdhci->mmc, 5); ret = sdhci_resume_host(host->sdhci); if (ret) pr_err("%s: failed, error = %d\n", __func__, ret); if (host->irq_cd != -1) enable_irq(host->irq_cd); return ret; }