static bool tegra_sdhci_is_pad_and_regulator_valid(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); int has_1v8, has_3v3; /* * The SoCs which have NVQUIRK_NEEDS_PAD_CONTROL require software pad * voltage configuration in order to perform voltage switching. This * means that valid pinctrl info is required on SDHCI instances capable * of performing voltage switching. Whether or not an SDHCI instance is * capable of voltage switching is determined based on the regulator. */ if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)) return true; if (IS_ERR(host->mmc->supply.vqmmc)) return false; has_1v8 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 1700000, 1950000); has_3v3 = regulator_is_supported_voltage(host->mmc->supply.vqmmc, 2700000, 3600000); if (has_1v8 == 1 && has_3v3 == 1) return tegra_host->pad_control_available; /* Fixed voltage, no pad control required. */ return true; }
static int sdhci_at91_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; ret = clk_prepare_enable(priv->mainck); if (ret) { dev_err(dev, "can't enable mainck\n"); return ret; } ret = clk_prepare_enable(priv->hclock); if (ret) { dev_err(dev, "can't enable hclock\n"); return ret; } ret = clk_prepare_enable(priv->gck); if (ret) { dev_err(dev, "can't enable gck\n"); return ret; } return sdhci_runtime_resume_host(host); }
static int tegra_sdhci_set_padctrl(struct sdhci_host *host, int voltage) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); int ret; if (!tegra_host->pad_control_available) return 0; if (voltage == MMC_SIGNAL_VOLTAGE_180) { ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, tegra_host->pinctrl_state_1v8); if (ret < 0) dev_err(mmc_dev(host->mmc), "setting 1.8V failed, ret: %d\n", ret); } else { ret = pinctrl_select_state(tegra_host->pinctrl_sdmmc, tegra_host->pinctrl_state_3v3); if (ret < 0) dev_err(mmc_dev(host->mmc), "setting 3.3V failed, ret: %d\n", ret); } return ret; }
static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); return clk_round_rate(msm_host->clk, ULONG_MAX); }
static int sdhci_tegra_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); int ret = 0; if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); if (ret < 0) return ret; ret = sdhci_start_signal_voltage_switch(mmc, ios); } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { ret = sdhci_start_signal_voltage_switch(mmc, ios); if (ret < 0) return ret; ret = tegra_sdhci_set_padctrl(host, ios->signal_voltage); } if (tegra_host->pad_calib_required) tegra_sdhci_pad_autocalib(host); return ret; }
static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); int ret; u32 config; pr_debug("%s: %s: Enter\n", mmc_hostname(host->mmc), __func__); /* * Retuning in HS400 (DDR mode) will fail, just reset the * tuning block and restore the saved tuning phase. */ ret = msm_init_cm_dll(host); if (ret) goto out; /* Set the selected phase in delay line hw block */ ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase); if (ret) goto out; config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG); config |= CORE_CMD_DAT_TRACK_SEL; writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG); if (msm_host->use_cdclp533) ret = sdhci_msm_cdclp533_calibration(host); else ret = sdhci_msm_cm_dll_sdc4_calibration(host); out: pr_debug("%s: %s: Exit, ret %d\n", mmc_hostname(host->mmc), __func__, ret); return ret; }
static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); unsigned long host_clk; if (!clock) return sdhci_set_clock(host, clock); /* * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI * divider to be configured to divided the host clock by two. The SDHCI * clock divider is calculated as part of sdhci_set_clock() by * sdhci_calc_clk(). The divider is calculated from host->max_clk and * the requested clock rate. * * By setting the host->max_clk to clock * 2 the divider calculation * will always result in the correct value for DDR50/52 modes, * regardless of clock rate rounding, which may happen if the value * from clk_get_rate() is used. */ host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; clk_set_rate(pltfm_host->clk, host_clk); if (tegra_host->ddr_signaling) host->max_clk = host_clk; else host->max_clk = clk_get_rate(pltfm_host->clk); sdhci_set_clock(host, clock); if (tegra_host->pad_calib_required) { tegra_sdhci_pad_autocalib(host); tegra_host->pad_calib_required = false; } }
static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; bool card_clk_enabled = false; u32 reg; /* * Touching the tap values is a bit tricky on some SoC generations. * The quirk enables a workaround for a glitch that sometimes occurs if * the tap values are changed. */ if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP) card_clk_enabled = tegra_sdhci_configure_card_clk(host, false); reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK; reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT; sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); if (soc_data->nvquirks & NVQUIRK_DIS_CARD_CLK_CONFIG_TAP && card_clk_enabled) { udelay(1); sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); tegra_sdhci_configure_card_clk(host, card_clk_enabled); } }
/* * Platform specific register write functions. This is so that, if any * register write needs to be followed up by platform specific actions, * they can be added here. These functions can go to sleep when writes * to certain registers are done. * These functions are relying on sdhci_set_ios not using spinlock. */ static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); u32 req_type = 0; switch (reg) { case SDHCI_HOST_CONTROL2: req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW : REQ_IO_HIGH; break; case SDHCI_SOFTWARE_RESET: if (host->pwr && (val & SDHCI_RESET_ALL)) req_type = REQ_BUS_OFF; break; case SDHCI_POWER_CONTROL: req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON; break; } if (req_type) { msm_host->pwr_irq_flag = 0; /* * Since this register write may trigger a power irq, ensure * all previous register writes are complete by this point. */ mb(); } return req_type; }
static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; /* Seems like we're getting spurious timeout and crc errors, so * disable signalling of them. In case of real errors software * timers should take care of eventually detecting them. */ if (unlikely(reg == SDHCI_SIGNAL_ENABLE)) val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC); writel(val, host->ioaddr + reg); if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) && (reg == SDHCI_INT_ENABLE))) { /* Erratum: Must enable block gap interrupt detection */ u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); if (val & SDHCI_INT_CARD_INT) gap_ctrl |= 0x8; else gap_ctrl &= ~0x8; writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL); } }
/* * Software emulation of the SD card insertion/removal. Set insert=1 for insert * and insert=0 for removal. The card detection is done by GPIO. For Broadcom * IP to function properly the bit 0 of CORESTAT register needs to be set/reset * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet. */ static int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert) { struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); u32 val; /* * Back-to-Back register write needs a delay of min 10uS. * Back-to-Back writes to same register needs delay when SD bus clock * is very low w.r.t AHB clock, mainly during boot-time and during card * insert-removal. * We keep 20uS */ mutex_lock(&kona_dev->write_lock); udelay(20); val = sdhci_readl(host, KONA_SDHOST_CORESTAT); if (insert) { int ret; ret = mmc_gpio_get_ro(host->mmc); if (ret >= 0) val = (val & ~KONA_SDHOST_WP) | ((ret) ? KONA_SDHOST_WP : 0); 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); } mutex_unlock(&kona_dev->write_lock); return 0; }
static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); u16 ctrl_2; /* * Set V18_EN -- UHS modes do not work without this. * does not change signaling voltage */ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; switch (uhs) { case MMC_TIMING_UHS_SDR12: ctrl_2 |= SDHCI_CTRL_UHS_SDR12; break; case MMC_TIMING_UHS_SDR25: ctrl_2 |= SDHCI_CTRL_UHS_SDR25; break; case MMC_TIMING_UHS_SDR50: ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_UHS_SDR104: ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; break; case MMC_TIMING_MMC_DDR52: case MMC_TIMING_UHS_DDR50: ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; break; } /* * Update SDIO3 Configuration register according to erratum * FE-2946959 */ if (pxa->sdio3_conf_reg) { u8 reg_val = readb(pxa->sdio3_conf_reg); if (uhs == MMC_TIMING_UHS_SDR50 || uhs == MMC_TIMING_UHS_DDR50) { reg_val &= ~SDIO3_CONF_CLK_INV; reg_val |= SDIO3_CONF_SD_FB_CLK; } else if (uhs == MMC_TIMING_MMC_HS) { reg_val &= ~SDIO3_CONF_CLK_INV; reg_val &= ~SDIO3_CONF_SD_FB_CLK; } else { reg_val |= SDIO3_CONF_CLK_INV; reg_val &= ~SDIO3_CONF_SD_FB_CLK; } writeb(reg_val, pxa->sdio3_conf_reg); } sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); dev_dbg(mmc_dev(host->mmc), "%s uhs = %d, ctrl_2 = %04X\n", __func__, uhs, ctrl_2); }
static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct clk *core_clk = msm_host->bulk_clks[0].clk; return clk_round_rate(core_clk, ULONG_MAX); }
/* * Get the base clock. Use central clock source for now. Not sure if different * clock speed to each dev is allowed */ static unsigned int sdhci_bcm_kona_get_max_clk(struct sdhci_host *host) { struct sdhci_bcm_kona_dev *kona_dev; struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); kona_dev = sdhci_pltfm_priv(pltfm_priv); return host->mmc->f_max; }
/* * sdhci_msm_check_power_status API should be called when registers writes * which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens. * To what state the register writes will change the IO lines should be passed * as the argument req_type. This API will check whether the IO line's state * is already the expected state and will wait for power irq only if * power irq is expected to be trigerred based on the current IO line state * and expected IO line state. */ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); bool done = false; u32 val; pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n", mmc_hostname(host->mmc), __func__, req_type, msm_host->curr_pwr_state, msm_host->curr_io_level); /* * The power interrupt will not be generated for signal voltage * switches if SWITCHABLE_SIGNALING_VOLTAGE in MCI_GENERICS is not set. */ val = readl(msm_host->core_mem + CORE_MCI_GENERICS); if ((req_type & REQ_IO_HIGH || req_type & REQ_IO_LOW) && !(val & SWITCHABLE_SIGNALING_VOLTAGE)) { return; } /* * The IRQ for request type IO High/LOW will be generated when - * there is a state change in 1.8V enable bit (bit 3) of * SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0 * which indicates 3.3V IO voltage. So, when MMC core layer tries * to set it to 3.3V before card detection happens, the * IRQ doesn't get triggered as there is no state change in this bit. * The driver already handles this case by changing the IO voltage * level to high as part of controller power up sequence. Hence, check * for host->pwr to handle a case where IO voltage high request is * issued even before controller power up. */ if ((req_type & REQ_IO_HIGH) && !host->pwr) { pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n", mmc_hostname(host->mmc), req_type); return; } if ((req_type & msm_host->curr_pwr_state) || (req_type & msm_host->curr_io_level)) done = true; /* * This is needed here to handle cases where register writes will * not change the current bus state or io level of the controller. * In this case, no power irq will be triggerred and we should * not wait. */ if (!done) { if (!wait_event_timeout(msm_host->pwr_irq_wait, msm_host->pwr_irq_flag, msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS))) dev_warn(&msm_host->pdev->dev, "%s: pwr_irq for req: (%d) timed out\n", mmc_hostname(host->mmc), req_type); } pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc), __func__, req_type); }
static void tegra_sdhci_voltage_switch(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) tegra_host->pad_calib_required = true; }
static int sdhci_msm_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); return clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); }
static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; u32 misc_ctrl, clk_ctrl, pad_ctrl; sdhci_reset(host, mask); if (!(mask & SDHCI_RESET_ALL)) return; tegra_sdhci_set_tap(host, tegra_host->default_tap); misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); misc_ctrl &= ~(SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 | SDHCI_MISC_CTRL_ENABLE_SDR50 | SDHCI_MISC_CTRL_ENABLE_DDR50 | SDHCI_MISC_CTRL_ENABLE_SDR104); clk_ctrl &= ~(SDHCI_CLOCK_CTRL_TRIM_MASK | SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE); if (tegra_sdhci_is_pad_and_regulator_valid(host)) { /* Erratum: Enable SDHCI spec v3.00 support */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; /* Advertise UHS modes as supported by host */ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; } clk_ctrl |= tegra_host->default_trim << SDHCI_CLOCK_CTRL_TRIM_SHIFT; sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB) { pad_ctrl = sdhci_readl(host, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); pad_ctrl &= ~SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_MASK; pad_ctrl |= SDHCI_TEGRA_SDMEM_COMP_PADCTRL_VREF_SEL_VAL; sdhci_writel(host, pad_ctrl, SDHCI_TEGRA_SDMEM_COMP_PADCTRL); tegra_host->pad_calib_required = true; } tegra_host->ddr_signaling = false; }
static int sdhci_iproc_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct sdhci_iproc_data *iproc_data; struct sdhci_host *host; struct sdhci_iproc_host *iproc_host; struct sdhci_pltfm_host *pltfm_host; int ret; match = of_match_device(sdhci_iproc_of_match, &pdev->dev); if (!match) return -EINVAL; iproc_data = match->data; host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host)); if (IS_ERR(host)) return PTR_ERR(host); pltfm_host = sdhci_priv(host); iproc_host = sdhci_pltfm_priv(pltfm_host); iproc_host->data = iproc_data; mmc_of_parse(host->mmc); sdhci_get_of_property(pdev); host->mmc->caps |= iproc_host->data->mmc_caps; pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pltfm_host->clk)) { ret = PTR_ERR(pltfm_host->clk); goto err; } ret = clk_prepare_enable(pltfm_host->clk); if (ret) { dev_err(&pdev->dev, "failed to enable host clk\n"); goto err; } if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) { host->caps = iproc_host->data->caps; host->caps1 = iproc_host->data->caps1; } ret = sdhci_add_host(host); if (ret) goto err_clk; return 0; err_clk: clk_disable_unprepare(pltfm_host->clk); err: sdhci_pltfm_free(pdev); return ret; }
static int sdhci_sirf_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); sdhci_pltfm_unregister(pdev); clk_disable_unprepare(priv->clk); return 0; }
static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n", mmc_hostname(host->mmc), readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS), readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK), readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL)); }
static int sdhci_msm_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); clk_disable_unprepare(msm_host->clk); clk_disable_unprepare(msm_host->pclk); return 0; }
static int sdhci_pxav3_runtime_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); clk_prepare_enable(pxa->clk_io); if (!IS_ERR(pxa->clk_core)) clk_prepare_enable(pxa->clk_core); return sdhci_runtime_resume_host(host); }
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) { struct sdhci_host *host = (struct sdhci_host *)data; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); sdhci_msm_handle_pwr_irq(host, irq); msm_host->pwr_irq_flag = 1; sdhci_msm_complete_pwr_irq_wait(msm_host); return IRQ_HANDLED; }
static int sdhci_sirf_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); sdhci_pltfm_unregister(pdev); if (gpio_is_valid(priv->gpio_cd)) mmc_gpio_free_cd(host->mmc); clk_disable_unprepare(priv->clk); return 0; }
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && (reg == SDHCI_HOST_VERSION))) { /* Erratum: Version register is invalid in HW. */ return SDHCI_SPEC_200; } return readw(host->ioaddr + reg); }
static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); clk_disable_unprepare(kona_dev->external_clk); sdhci_pltfm_free(pdev); return 0; }
static int sdhci_at91_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; ret = sdhci_runtime_suspend_host(host); clk_disable_unprepare(priv->gck); clk_disable_unprepare(priv->hclock); clk_disable_unprepare(priv->mainck); return ret; }
static int sdhci_sirf_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; ret = clk_enable(priv->clk); if (ret) { dev_dbg(dev, "Resume: Error enabling clock\n"); return ret; } return sdhci_resume_host(host); }
static int sdhci_sirf_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); int ret; ret = sdhci_suspend_host(host); if (ret) return ret; clk_disable(priv->clk); return 0; }