diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2011-08-23 14:15:33 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-10-26 15:43:35 -0400 |
commit | 275173b225ae663e54d8dc5c93d79265aad19f89 (patch) | |
tree | ce6cd20e8d888c74d0eaa3975acee705f239462a /drivers/mmc | |
parent | 08da834a24312157f512224691ad1fddd11c1073 (diff) |
mmc: sdhci-tegra: Add Device Tree probing support
Add hooks to read gpio configuration out of the device tree node.
[grant.likely: Rewrite of original patch from John Bonesio]
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
[swarren: Fixed tegra_sdhci_get_ro() to retrieve pdata correctly]
[swarren: Reworked to avoid #ifdef CONFIG_OF]
[swarren: Reworked binding based on fsl-imx-esdhc.txt]
[swarren: Documented binding]
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 18b0bd31de78..8a114b6211c7 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
20 | #include <linux/of_gpio.h> | ||
20 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
21 | #include <linux/mmc/card.h> | 22 | #include <linux/mmc/card.h> |
22 | #include <linux/mmc/host.h> | 23 | #include <linux/mmc/host.h> |
@@ -73,10 +74,8 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) | |||
73 | 74 | ||
74 | static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci) | 75 | static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci) |
75 | { | 76 | { |
76 | struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc)); | 77 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); |
77 | struct tegra_sdhci_platform_data *plat; | 78 | struct tegra_sdhci_platform_data *plat = pltfm_host->priv; |
78 | |||
79 | plat = pdev->dev.platform_data; | ||
80 | 79 | ||
81 | if (!gpio_is_valid(plat->wp_gpio)) | 80 | if (!gpio_is_valid(plat->wp_gpio)) |
82 | return -1; | 81 | return -1; |
@@ -94,12 +93,10 @@ static irqreturn_t carddetect_irq(int irq, void *data) | |||
94 | 93 | ||
95 | static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) | 94 | static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) |
96 | { | 95 | { |
97 | struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); | 96 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
98 | struct tegra_sdhci_platform_data *plat; | 97 | struct tegra_sdhci_platform_data *plat = pltfm_host->priv; |
99 | u32 ctrl; | 98 | u32 ctrl; |
100 | 99 | ||
101 | plat = pdev->dev.platform_data; | ||
102 | |||
103 | ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); | 100 | ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); |
104 | if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { | 101 | if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { |
105 | ctrl &= ~SDHCI_CTRL_4BITBUS; | 102 | ctrl &= ~SDHCI_CTRL_4BITBUS; |
@@ -131,6 +128,34 @@ static struct sdhci_pltfm_data sdhci_tegra_pdata = { | |||
131 | .ops = &tegra_sdhci_ops, | 128 | .ops = &tegra_sdhci_ops, |
132 | }; | 129 | }; |
133 | 130 | ||
131 | static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = { | ||
132 | { .compatible = "nvidia,tegra20-sdhci", }, | ||
133 | {} | ||
134 | }; | ||
135 | MODULE_DEVICE_TABLE(of, sdhci_dt_ids); | ||
136 | |||
137 | static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( | ||
138 | struct platform_device *pdev) | ||
139 | { | ||
140 | struct tegra_sdhci_platform_data *plat; | ||
141 | struct device_node *np = pdev->dev.of_node; | ||
142 | |||
143 | if (!np) | ||
144 | return NULL; | ||
145 | |||
146 | plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); | ||
147 | if (!plat) { | ||
148 | dev_err(&pdev->dev, "Can't allocate platform data\n"); | ||
149 | return NULL; | ||
150 | } | ||
151 | |||
152 | plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); | ||
153 | plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); | ||
154 | plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0); | ||
155 | |||
156 | return plat; | ||
157 | } | ||
158 | |||
134 | static int __devinit sdhci_tegra_probe(struct platform_device *pdev) | 159 | static int __devinit sdhci_tegra_probe(struct platform_device *pdev) |
135 | { | 160 | { |
136 | struct sdhci_pltfm_host *pltfm_host; | 161 | struct sdhci_pltfm_host *pltfm_host; |
@@ -147,12 +172,17 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) | |||
147 | 172 | ||
148 | plat = pdev->dev.platform_data; | 173 | plat = pdev->dev.platform_data; |
149 | 174 | ||
175 | if (plat == NULL) | ||
176 | plat = sdhci_tegra_dt_parse_pdata(pdev); | ||
177 | |||
150 | if (plat == NULL) { | 178 | if (plat == NULL) { |
151 | dev_err(mmc_dev(host->mmc), "missing platform data\n"); | 179 | dev_err(mmc_dev(host->mmc), "missing platform data\n"); |
152 | rc = -ENXIO; | 180 | rc = -ENXIO; |
153 | goto err_no_plat; | 181 | goto err_no_plat; |
154 | } | 182 | } |
155 | 183 | ||
184 | pltfm_host->priv = plat; | ||
185 | |||
156 | if (gpio_is_valid(plat->power_gpio)) { | 186 | if (gpio_is_valid(plat->power_gpio)) { |
157 | rc = gpio_request(plat->power_gpio, "sdhci_power"); | 187 | rc = gpio_request(plat->power_gpio, "sdhci_power"); |
158 | if (rc) { | 188 | if (rc) { |
@@ -247,13 +277,11 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev) | |||
247 | { | 277 | { |
248 | struct sdhci_host *host = platform_get_drvdata(pdev); | 278 | struct sdhci_host *host = platform_get_drvdata(pdev); |
249 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 279 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
250 | struct tegra_sdhci_platform_data *plat; | 280 | struct tegra_sdhci_platform_data *plat = pltfm_host->priv; |
251 | int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); | 281 | int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); |
252 | 282 | ||
253 | sdhci_remove_host(host, dead); | 283 | sdhci_remove_host(host, dead); |
254 | 284 | ||
255 | plat = pdev->dev.platform_data; | ||
256 | |||
257 | if (gpio_is_valid(plat->wp_gpio)) { | 285 | if (gpio_is_valid(plat->wp_gpio)) { |
258 | tegra_gpio_disable(plat->wp_gpio); | 286 | tegra_gpio_disable(plat->wp_gpio); |
259 | gpio_free(plat->wp_gpio); | 287 | gpio_free(plat->wp_gpio); |
@@ -282,6 +310,7 @@ static struct platform_driver sdhci_tegra_driver = { | |||
282 | .driver = { | 310 | .driver = { |
283 | .name = "sdhci-tegra", | 311 | .name = "sdhci-tegra", |
284 | .owner = THIS_MODULE, | 312 | .owner = THIS_MODULE, |
313 | .of_match_table = sdhci_tegra_dt_match, | ||
285 | }, | 314 | }, |
286 | .probe = sdhci_tegra_probe, | 315 | .probe = sdhci_tegra_probe, |
287 | .remove = __devexit_p(sdhci_tegra_remove), | 316 | .remove = __devexit_p(sdhci_tegra_remove), |