From e1e3da4a8e222552fc8175b7a90a9da945c1e6c8 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 21 Jun 2011 10:53:42 -0600 Subject: mmc/tegra: add sdhci device tree handling This patch adds support for configuring the NVIDIA tegra250 sdhci device from the device tree. Signed-off-by: Grant Likely --- drivers/mmc/host/sdhci-pltfm.c | 34 ++++++++++++++++++++++++++++- drivers/mmc/host/sdhci-pltfm.h | 1 + drivers/mmc/host/sdhci-tegra.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index dbab0407f4b..e231f917225 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -49,10 +49,30 @@ static struct sdhci_ops sdhci_pltfm_ops = { * Device probing/removal * * * \*****************************************************************************/ +#if defined(CONFIG_OF) +#include +static const struct of_device_id sdhci_dt_ids[] = { + { .compatible = "nvidia,tegra20-sdhci", .data = &sdhci_tegra_dt_pdata }, + { } +}; +MODULE_DEVICE_TABLE(platform, sdhci_dt_ids); + +static const struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return of_match_device(sdhci_dt_ids, &pdev->dev); +} +#else +#define sdhci_dt_ids NULL +static inline struct of_device_id *sdhci_get_of_device_id(struct platform_device *pdev) +{ + return NULL; +} +#endif static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) { const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); struct sdhci_pltfm_data *pdata; struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -61,6 +81,8 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) if (platid && platid->driver_data) pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; else pdata = pdev->dev.platform_data; @@ -140,12 +162,21 @@ err: static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) { - struct sdhci_pltfm_data *pdata = pdev->dev.platform_data; + const struct platform_device_id *platid = platform_get_device_id(pdev); + const struct of_device_id *dtid = sdhci_get_of_device_id(pdev); + struct sdhci_pltfm_data *pdata; struct sdhci_host *host = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int dead; u32 scratch; + if (platid && platid->driver_data) + pdata = (void *)platid->driver_data; + else if (dtid && dtid->data) + pdata = dtid->data; + else + pdata = pdev->dev.platform_data; + dead = 0; scratch = readl(host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -203,6 +234,7 @@ static struct platform_driver sdhci_pltfm_driver = { .driver = { .name = "sdhci", .owner = THIS_MODULE, + .of_match_table = sdhci_dt_ids, }, .probe = sdhci_pltfm_probe, .remove = __devexit_p(sdhci_pltfm_remove), diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 2b37016ad0a..2a438175839 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -24,5 +24,6 @@ extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata; extern struct sdhci_pltfm_data sdhci_dove_pdata; extern struct sdhci_pltfm_data sdhci_tegra_pdata; +extern struct sdhci_pltfm_data sdhci_tegra_dt_pdata; #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 343c97edba3..c9d4d282041 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -18,8 +18,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -216,6 +218,33 @@ out: return rc; } +static int tegra_sdhci_pltfm_dt_init(struct sdhci_host *host, + struct sdhci_pltfm_data *pdata) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + struct tegra_sdhci_platform_data *plat; + + if (pdev->dev.platform_data) { + dev_err(&pdev->dev, "%s: platform_data not NULL; aborting\n", + __func__); + return -ENODEV; + } + + plat = kzalloc(sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + pdev->dev.platform_data = plat; + + plat->cd_gpio = of_get_gpio(pdev->dev.of_node, 0); + plat->wp_gpio = of_get_gpio(pdev->dev.of_node, 1); + plat->power_gpio = of_get_gpio(pdev->dev.of_node, 2); + + dev_info(&pdev->dev, "using gpios cd=%i, wp=%i power=%i\n", + plat->cd_gpio, plat->wp_gpio, plat->power_gpio); + + return tegra_sdhci_pltfm_init(host, pdata); +} + static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -244,6 +273,16 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) clk_put(pltfm_host->clk); } +static void tegra_sdhci_pltfm_dt_exit(struct sdhci_host *host) +{ + struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); + + tegra_sdhci_pltfm_exit(host); + + kfree(pdev->dev.platform_data); + pdev->dev.platform_data = NULL; +} + static struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_l = tegra_sdhci_readl, @@ -261,3 +300,13 @@ struct sdhci_pltfm_data sdhci_tegra_pdata = { .init = tegra_sdhci_pltfm_init, .exit = tegra_sdhci_pltfm_exit, }; + +struct sdhci_pltfm_data sdhci_tegra_dt_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .ops = &tegra_sdhci_ops, + .init = tegra_sdhci_pltfm_dt_init, + .exit = tegra_sdhci_pltfm_dt_exit, +}; -- cgit v1.2.3