コード例 #1
0
/*
 * 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;
}
コード例 #2
0
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;
}
コード例 #3
0
ファイル: sdhci-tegra.c プロジェクト: michabs/linux-imx6-3.14
static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
{
	return mmc_gpio_get_ro(host->mmc);
}