static int bxt_get_cd(struct mmc_host *mmc) { int gpio_cd = mmc_gpio_get_cd(mmc); struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; int ret = 0; if (!gpio_cd) return 0; pm_runtime_get_sync(mmc->parent); spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) goto out; ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); out: spin_unlock_irqrestore(&host->lock, flags); pm_runtime_mark_last_busy(mmc->parent); pm_runtime_put_autosuspend(mmc->parent); return ret; }
/* * SD card interrupt event callback */ static void sdhci_bcm_kona_card_event(struct sdhci_host *host) { if (mmc_gpio_get_cd(host->mmc) > 0) { dev_dbg(mmc_dev(host->mmc), "card inserted\n"); sdhci_bcm_kona_sd_card_emulate(host, 1); } else { dev_dbg(mmc_dev(host->mmc), "card removed\n"); sdhci_bcm_kona_sd_card_emulate(host, 0); } }
static int sh_mmcif_get_cd(struct mmc_host *mmc) { struct sh_mmcif_host *host = mmc_priv(mmc); struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; int ret = mmc_gpio_get_cd(mmc); if (ret >= 0) return ret; if (!p || !p->get_cd) return -ENOSYS; else return p->get_cd(host->pd); }
static int mxs_mmc_get_cd(struct mmc_host *mmc) { struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_ssp *ssp = &host->ssp; int present, ret; if (host->broken_cd) return -ENOSYS; ret = mmc_gpio_get_cd(mmc); if (ret >= 0) return ret; present = !(readl(ssp->base + HW_SSP_STATUS(ssp)) & BM_SSP_STATUS_CARD_DETECT); if (mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH) present = !present; return present; }
static int sdhci_bcm_kona_probe(struct platform_device *pdev) { struct sdhci_bcm_kona_dev *kona_dev = NULL; struct sdhci_pltfm_host *pltfm_priv; struct device *dev = &pdev->dev; struct sdhci_host *host; int ret; ret = 0; host = sdhci_pltfm_init(pdev, &sdhci_pltfm_data_kona, sizeof(*kona_dev)); if (IS_ERR(host)) return PTR_ERR(host); dev_dbg(dev, "%s: inited. IOADDR=%p\n", __func__, host->ioaddr); pltfm_priv = sdhci_priv(host); kona_dev = sdhci_pltfm_priv(pltfm_priv); mutex_init(&kona_dev->write_lock); mmc_of_parse(host->mmc); if (!host->mmc->f_max) { dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n"); ret = -ENXIO; goto err_pltfm_free; } /* Get and enable the external clock */ kona_dev->external_clk = devm_clk_get(dev, NULL); if (IS_ERR(kona_dev->external_clk)) { dev_err(dev, "Failed to get external clock\n"); ret = PTR_ERR(kona_dev->external_clk); goto err_pltfm_free; } if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) { dev_err(dev, "Failed to set rate external clock\n"); goto err_pltfm_free; } if (clk_prepare_enable(kona_dev->external_clk) != 0) { dev_err(dev, "Failed to enable external clock\n"); goto err_pltfm_free; } dev_dbg(dev, "non-removable=%c\n", (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N'); dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n", (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N', (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N'); if (host->mmc->caps & MMC_CAP_NONREMOVABLE) host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; dev_dbg(dev, "is_8bit=%c\n", (host->mmc->caps | MMC_CAP_8_BIT_DATA) ? 'Y' : 'N'); ret = sdhci_bcm_kona_sd_reset(host); if (ret) goto err_clk_disable; sdhci_bcm_kona_sd_init(host); ret = sdhci_add_host(host); if (ret) { dev_err(dev, "Failed sdhci_add_host\n"); goto err_reset; } /* if device is eMMC, emulate card insert right here */ if (host->mmc->caps & MMC_CAP_NONREMOVABLE) { ret = sdhci_bcm_kona_sd_card_emulate(host, 1); if (ret) { dev_err(dev, "unable to emulate card insertion\n"); goto err_remove_host; } } /* * 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 (mmc_gpio_get_cd(host->mmc) > 0) sdhci_bcm_kona_sd_card_emulate(host, 1); dev_dbg(dev, "initialized properly\n"); return 0; err_remove_host: sdhci_remove_host(host, 0); err_reset: sdhci_bcm_kona_sd_reset(host); err_clk_disable: clk_disable_unprepare(kona_dev->external_clk); err_pltfm_free: sdhci_pltfm_free(pdev); dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret); return ret; }
static int sdhci_at91_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct sdhci_pltfm_data *soc_data; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; struct sdhci_at91_priv *priv; unsigned int caps0, caps1; unsigned int clk_base, clk_mul; unsigned int gck_rate, real_gck_rate; int ret; unsigned int preset_div, preset_common = 0x400; /* drv type B, programmable clock mode */ match = of_match_device(sdhci_at91_dt_match, &pdev->dev); if (!match) return -EINVAL; soc_data = match->data; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "unable to allocate private data\n"); return -ENOMEM; } priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); if (IS_ERR(priv->mainck)) { dev_err(&pdev->dev, "failed to get baseclk\n"); return PTR_ERR(priv->mainck); } priv->hclock = devm_clk_get(&pdev->dev, "hclock"); if (IS_ERR(priv->hclock)) { dev_err(&pdev->dev, "failed to get hclock\n"); return PTR_ERR(priv->hclock); } priv->gck = devm_clk_get(&pdev->dev, "multclk"); if (IS_ERR(priv->gck)) { dev_err(&pdev->dev, "failed to get multclk\n"); return PTR_ERR(priv->gck); } host = sdhci_pltfm_init(pdev, soc_data, 0); if (IS_ERR(host)) return PTR_ERR(host); /* * The mult clock is provided by as a generated clock by the PMC * controller. In order to set the rate of gck, we have to get the * base clock rate and the clock mult from capabilities. */ clk_prepare_enable(priv->hclock); caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES); caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1); clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; gck_rate = clk_base * 1000000 * (clk_mul + 1); ret = clk_set_rate(priv->gck, gck_rate); if (ret < 0) { dev_err(&pdev->dev, "failed to set gck"); goto hclock_disable_unprepare; } /* * We need to check if we have the requested rate for gck because in * some cases this rate could be not supported. If it happens, the rate * is the closest one gck can provide. We have to update the value * of clk mul. */ real_gck_rate = clk_get_rate(priv->gck); if (real_gck_rate != gck_rate) { clk_mul = real_gck_rate / (clk_base * 1000000) - 1; caps1 &= (~SDHCI_CLOCK_MUL_MASK); caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK); /* Set capabilities in r/w mode. */ writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR); writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1); /* Set capabilities in ro mode. */ writel(0, host->ioaddr + SDMMC_CACR); dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n", clk_mul, real_gck_rate); } /* * We have to set preset values because it depends on the clk_mul * value. Moreover, SDR104 is supported in a degraded mode since the * maximum sd clock value is 120 MHz instead of 208 MHz. For that * reason, we need to use presets to support SDR104. */ preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1; writew(preset_common | preset_div, host->ioaddr + SDHCI_PRESET_FOR_SDR12); preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; writew(preset_common | preset_div, host->ioaddr + SDHCI_PRESET_FOR_SDR25); preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1; writew(preset_common | preset_div, host->ioaddr + SDHCI_PRESET_FOR_SDR50); preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1; writew(preset_common | preset_div, host->ioaddr + SDHCI_PRESET_FOR_SDR104); preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; writew(preset_common | preset_div, host->ioaddr + SDHCI_PRESET_FOR_DDR50); clk_prepare_enable(priv->mainck); clk_prepare_enable(priv->gck); pltfm_host = sdhci_priv(host); pltfm_host->priv = priv; ret = mmc_of_parse(host->mmc); if (ret) goto clocks_disable_unprepare; sdhci_get_of_property(pdev); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 50); pm_runtime_use_autosuspend(&pdev->dev); ret = sdhci_add_host(host); if (ret) goto pm_runtime_disable; /* * When calling sdhci_runtime_suspend_host(), the sdhci layer makes * the assumption that all the clocks of the controller are disabled. * It means we can't get irq from it when it is runtime suspended. * For that reason, it is not planned to wake-up on a card detect irq * from the controller. * If we want to use runtime PM and to be able to wake-up on card * insertion, we have to use a GPIO for the card detection or we can * use polling. Be aware that using polling will resume/suspend the * controller between each attempt. * Disable SDHCI_QUIRK_BROKEN_CARD_DETECTION to be sure nobody tries * to enable polling via device tree with broken-cd property. */ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc))) { host->mmc->caps |= MMC_CAP_NEEDS_POLL; host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; } pm_runtime_put_autosuspend(&pdev->dev); return 0; pm_runtime_disable: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); clocks_disable_unprepare: clk_disable_unprepare(priv->gck); clk_disable_unprepare(priv->mainck); hclock_disable_unprepare: clk_disable_unprepare(priv->hclock); sdhci_pltfm_free(pdev); return ret; }