aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci-tegra.c
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@linaro.org>2011-05-27 11:48:12 -0400
committerChris Ball <cjb@laptop.org>2011-07-20 17:16:06 -0400
commit85d6509dc8ca24b2b652863ef7a75622ddca17d6 (patch)
treee564c2d4f80478027abc96cb7d87da952b38409e /drivers/mmc/host/sdhci-tegra.c
parent3a5c3743f15f27237ab025736a981e2d0c9fdfed (diff)
mmc: sdhci: make sdhci-pltfm device drivers self registered
The patch turns the common stuff in sdhci-pltfm.c into functions, and add device drivers their own .probe and .remove which in turn call into the common functions, so that those sdhci-pltfm device drivers register itself and keep all device specific things away from common sdhci-pltfm file. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Reviewed-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Anton Vorontsov <cbouatmailru@gmail.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/sdhci-tegra.c')
-rw-r--r--drivers/mmc/host/sdhci-tegra.c116
1 files changed, 81 insertions, 35 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 343c97edba32..1f66aca5f506 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -116,20 +116,42 @@ static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
116 return 0; 116 return 0;
117} 117}
118 118
119static struct sdhci_ops tegra_sdhci_ops = {
120 .get_ro = tegra_sdhci_get_ro,
121 .read_l = tegra_sdhci_readl,
122 .read_w = tegra_sdhci_readw,
123 .write_l = tegra_sdhci_writel,
124 .platform_8bit_width = tegra_sdhci_8bit,
125};
126
127static struct sdhci_pltfm_data sdhci_tegra_pdata = {
128 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
129 SDHCI_QUIRK_SINGLE_POWER_WRITE |
130 SDHCI_QUIRK_NO_HISPD_BIT |
131 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
132 .ops = &tegra_sdhci_ops,
133};
119 134
120static int tegra_sdhci_pltfm_init(struct sdhci_host *host, 135static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
121 struct sdhci_pltfm_data *pdata)
122{ 136{
123 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 137 struct sdhci_pltfm_host *pltfm_host;
124 struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
125 struct tegra_sdhci_platform_data *plat; 138 struct tegra_sdhci_platform_data *plat;
139 struct sdhci_host *host;
126 struct clk *clk; 140 struct clk *clk;
127 int rc; 141 int rc;
128 142
143 host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata);
144 if (IS_ERR(host))
145 return PTR_ERR(host);
146
147 pltfm_host = sdhci_priv(host);
148
129 plat = pdev->dev.platform_data; 149 plat = pdev->dev.platform_data;
150
130 if (plat == NULL) { 151 if (plat == NULL) {
131 dev_err(mmc_dev(host->mmc), "missing platform data\n"); 152 dev_err(mmc_dev(host->mmc), "missing platform data\n");
132 return -ENXIO; 153 rc = -ENXIO;
154 goto err_no_plat;
133 } 155 }
134 156
135 if (gpio_is_valid(plat->power_gpio)) { 157 if (gpio_is_valid(plat->power_gpio)) {
@@ -137,7 +159,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
137 if (rc) { 159 if (rc) {
138 dev_err(mmc_dev(host->mmc), 160 dev_err(mmc_dev(host->mmc),
139 "failed to allocate power gpio\n"); 161 "failed to allocate power gpio\n");
140 goto out; 162 goto err_power_req;
141 } 163 }
142 tegra_gpio_enable(plat->power_gpio); 164 tegra_gpio_enable(plat->power_gpio);
143 gpio_direction_output(plat->power_gpio, 1); 165 gpio_direction_output(plat->power_gpio, 1);
@@ -148,7 +170,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
148 if (rc) { 170 if (rc) {
149 dev_err(mmc_dev(host->mmc), 171 dev_err(mmc_dev(host->mmc),
150 "failed to allocate cd gpio\n"); 172 "failed to allocate cd gpio\n");
151 goto out_power; 173 goto err_cd_req;
152 } 174 }
153 tegra_gpio_enable(plat->cd_gpio); 175 tegra_gpio_enable(plat->cd_gpio);
154 gpio_direction_input(plat->cd_gpio); 176 gpio_direction_input(plat->cd_gpio);
@@ -159,7 +181,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
159 181
160 if (rc) { 182 if (rc) {
161 dev_err(mmc_dev(host->mmc), "request irq error\n"); 183 dev_err(mmc_dev(host->mmc), "request irq error\n");
162 goto out_cd; 184 goto err_cd_irq_req;
163 } 185 }
164 186
165 } 187 }
@@ -169,7 +191,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
169 if (rc) { 191 if (rc) {
170 dev_err(mmc_dev(host->mmc), 192 dev_err(mmc_dev(host->mmc),
171 "failed to allocate wp gpio\n"); 193 "failed to allocate wp gpio\n");
172 goto out_irq; 194 goto err_wp_req;
173 } 195 }
174 tegra_gpio_enable(plat->wp_gpio); 196 tegra_gpio_enable(plat->wp_gpio);
175 gpio_direction_input(plat->wp_gpio); 197 gpio_direction_input(plat->wp_gpio);
@@ -179,7 +201,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
179 if (IS_ERR(clk)) { 201 if (IS_ERR(clk)) {
180 dev_err(mmc_dev(host->mmc), "clk err\n"); 202 dev_err(mmc_dev(host->mmc), "clk err\n");
181 rc = PTR_ERR(clk); 203 rc = PTR_ERR(clk);
182 goto out_wp; 204 goto err_clk_get;
183 } 205 }
184 clk_enable(clk); 206 clk_enable(clk);
185 pltfm_host->clk = clk; 207 pltfm_host->clk = clk;
@@ -189,38 +211,47 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
189 if (plat->is_8bit) 211 if (plat->is_8bit)
190 host->mmc->caps |= MMC_CAP_8_BIT_DATA; 212 host->mmc->caps |= MMC_CAP_8_BIT_DATA;
191 213
214 rc = sdhci_add_host(host);
215 if (rc)
216 goto err_add_host;
217
192 return 0; 218 return 0;
193 219
194out_wp: 220err_add_host:
221 clk_disable(pltfm_host->clk);
222 clk_put(pltfm_host->clk);
223err_clk_get:
195 if (gpio_is_valid(plat->wp_gpio)) { 224 if (gpio_is_valid(plat->wp_gpio)) {
196 tegra_gpio_disable(plat->wp_gpio); 225 tegra_gpio_disable(plat->wp_gpio);
197 gpio_free(plat->wp_gpio); 226 gpio_free(plat->wp_gpio);
198 } 227 }
199 228err_wp_req:
200out_irq:
201 if (gpio_is_valid(plat->cd_gpio)) 229 if (gpio_is_valid(plat->cd_gpio))
202 free_irq(gpio_to_irq(plat->cd_gpio), host); 230 free_irq(gpio_to_irq(plat->cd_gpio), host);
203out_cd: 231err_cd_irq_req:
204 if (gpio_is_valid(plat->cd_gpio)) { 232 if (gpio_is_valid(plat->cd_gpio)) {
205 tegra_gpio_disable(plat->cd_gpio); 233 tegra_gpio_disable(plat->cd_gpio);
206 gpio_free(plat->cd_gpio); 234 gpio_free(plat->cd_gpio);
207 } 235 }
208 236err_cd_req:
209out_power:
210 if (gpio_is_valid(plat->power_gpio)) { 237 if (gpio_is_valid(plat->power_gpio)) {
211 tegra_gpio_disable(plat->power_gpio); 238 tegra_gpio_disable(plat->power_gpio);
212 gpio_free(plat->power_gpio); 239 gpio_free(plat->power_gpio);
213 } 240 }
214 241err_power_req:
215out: 242err_no_plat:
243 sdhci_pltfm_free(pdev);
216 return rc; 244 return rc;
217} 245}
218 246
219static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) 247static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
220{ 248{
249 struct sdhci_host *host = platform_get_drvdata(pdev);
221 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 250 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
222 struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
223 struct tegra_sdhci_platform_data *plat; 251 struct tegra_sdhci_platform_data *plat;
252 int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
253
254 sdhci_remove_host(host, dead);
224 255
225 plat = pdev->dev.platform_data; 256 plat = pdev->dev.platform_data;
226 257
@@ -242,22 +273,37 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
242 273
243 clk_disable(pltfm_host->clk); 274 clk_disable(pltfm_host->clk);
244 clk_put(pltfm_host->clk); 275 clk_put(pltfm_host->clk);
276
277 sdhci_pltfm_free(pdev);
278
279 return 0;
245} 280}
246 281
247static struct sdhci_ops tegra_sdhci_ops = { 282static struct platform_driver sdhci_tegra_driver = {
248 .get_ro = tegra_sdhci_get_ro, 283 .driver = {
249 .read_l = tegra_sdhci_readl, 284 .name = "sdhci-tegra",
250 .read_w = tegra_sdhci_readw, 285 .owner = THIS_MODULE,
251 .write_l = tegra_sdhci_writel, 286 },
252 .platform_8bit_width = tegra_sdhci_8bit, 287 .probe = sdhci_tegra_probe,
288 .remove = __devexit_p(sdhci_tegra_remove),
289#ifdef CONFIG_PM
290 .suspend = sdhci_pltfm_suspend,
291 .resume = sdhci_pltfm_resume,
292#endif
253}; 293};
254 294
255struct sdhci_pltfm_data sdhci_tegra_pdata = { 295static int __init sdhci_tegra_init(void)
256 .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | 296{
257 SDHCI_QUIRK_SINGLE_POWER_WRITE | 297 return platform_driver_register(&sdhci_tegra_driver);
258 SDHCI_QUIRK_NO_HISPD_BIT | 298}
259 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, 299module_init(sdhci_tegra_init);
260 .ops = &tegra_sdhci_ops, 300
261 .init = tegra_sdhci_pltfm_init, 301static void __exit sdhci_tegra_exit(void)
262 .exit = tegra_sdhci_pltfm_exit, 302{
263}; 303 platform_driver_unregister(&sdhci_tegra_driver);
304}
305module_exit(sdhci_tegra_exit);
306
307MODULE_DESCRIPTION("SDHCI driver for Tegra");
308MODULE_AUTHOR(" Google, Inc.");
309MODULE_LICENSE("GPL v2");