mmc: dw_mmc: Make sure we don't get stuck when we get an error
[cascardo/linux.git] / drivers / mmc / host / sdhci-sirf.c
1 /*
2  * SDHCI support for SiRF primaII and marco SoCs
3  *
4  * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5  *
6  * Licensed under GPLv2 or later.
7  */
8
9 #include <linux/delay.h>
10 #include <linux/device.h>
11 #include <linux/mmc/host.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_gpio.h>
15 #include <linux/mmc/slot-gpio.h>
16 #include "sdhci-pltfm.h"
17
18 struct sdhci_sirf_priv {
19         struct clk *clk;
20         int gpio_cd;
21 };
22
23 static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
24 {
25         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
26         struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
27         return clk_get_rate(priv->clk);
28 }
29
30 static struct sdhci_ops sdhci_sirf_ops = {
31         .set_clock = sdhci_set_clock,
32         .get_max_clock  = sdhci_sirf_get_max_clk,
33         .set_bus_width = sdhci_set_bus_width,
34         .reset = sdhci_reset,
35         .set_uhs_signaling = sdhci_set_uhs_signaling,
36 };
37
38 static struct sdhci_pltfm_data sdhci_sirf_pdata = {
39         .ops = &sdhci_sirf_ops,
40         .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
41                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
42                 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
43                 SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
44                 SDHCI_QUIRK_DELAY_AFTER_POWER,
45 };
46
47 static int sdhci_sirf_probe(struct platform_device *pdev)
48 {
49         struct sdhci_host *host;
50         struct sdhci_pltfm_host *pltfm_host;
51         struct sdhci_sirf_priv *priv;
52         struct clk *clk;
53         int gpio_cd;
54         int ret;
55
56         clk = devm_clk_get(&pdev->dev, NULL);
57         if (IS_ERR(clk)) {
58                 dev_err(&pdev->dev, "unable to get clock");
59                 return PTR_ERR(clk);
60         }
61
62         if (pdev->dev.of_node)
63                 gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
64         else
65                 gpio_cd = -EINVAL;
66
67         host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
68         if (IS_ERR(host))
69                 return PTR_ERR(host);
70
71         pltfm_host = sdhci_priv(host);
72         priv = sdhci_pltfm_priv(pltfm_host);
73         priv->clk = clk;
74         priv->gpio_cd = gpio_cd;
75
76         sdhci_get_of_property(pdev);
77
78         ret = clk_prepare_enable(priv->clk);
79         if (ret)
80                 goto err_clk_prepare;
81
82         ret = sdhci_add_host(host);
83         if (ret)
84                 goto err_sdhci_add;
85
86         /*
87          * We must request the IRQ after sdhci_add_host(), as the tasklet only
88          * gets setup in sdhci_add_host() and we oops.
89          */
90         if (gpio_is_valid(priv->gpio_cd)) {
91                 ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0);
92                 if (ret) {
93                         dev_err(&pdev->dev, "card detect irq request failed: %d\n",
94                                 ret);
95                         goto err_request_cd;
96                 }
97         }
98
99         return 0;
100
101 err_request_cd:
102         sdhci_remove_host(host, 0);
103 err_sdhci_add:
104         clk_disable_unprepare(priv->clk);
105 err_clk_prepare:
106         sdhci_pltfm_free(pdev);
107         return ret;
108 }
109
110 static int sdhci_sirf_remove(struct platform_device *pdev)
111 {
112         struct sdhci_host *host = platform_get_drvdata(pdev);
113         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
114         struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
115
116         sdhci_pltfm_unregister(pdev);
117
118         if (gpio_is_valid(priv->gpio_cd))
119                 mmc_gpio_free_cd(host->mmc);
120
121         clk_disable_unprepare(priv->clk);
122         return 0;
123 }
124
125 #ifdef CONFIG_PM_SLEEP
126 static int sdhci_sirf_suspend(struct device *dev)
127 {
128         struct sdhci_host *host = dev_get_drvdata(dev);
129         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
130         struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
131         int ret;
132
133         ret = sdhci_suspend_host(host);
134         if (ret)
135                 return ret;
136
137         clk_disable(priv->clk);
138
139         return 0;
140 }
141
142 static int sdhci_sirf_resume(struct device *dev)
143 {
144         struct sdhci_host *host = dev_get_drvdata(dev);
145         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
146         struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
147         int ret;
148
149         ret = clk_enable(priv->clk);
150         if (ret) {
151                 dev_dbg(dev, "Resume: Error enabling clock\n");
152                 return ret;
153         }
154
155         return sdhci_resume_host(host);
156 }
157
158 static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
159 #endif
160
161 static const struct of_device_id sdhci_sirf_of_match[] = {
162         { .compatible = "sirf,prima2-sdhc" },
163         { }
164 };
165 MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
166
167 static struct platform_driver sdhci_sirf_driver = {
168         .driver         = {
169                 .name   = "sdhci-sirf",
170                 .owner  = THIS_MODULE,
171                 .of_match_table = sdhci_sirf_of_match,
172 #ifdef CONFIG_PM_SLEEP
173                 .pm     = &sdhci_sirf_pm_ops,
174 #endif
175         },
176         .probe          = sdhci_sirf_probe,
177         .remove         = sdhci_sirf_remove,
178 };
179
180 module_platform_driver(sdhci_sirf_driver);
181
182 MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco");
183 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
184 MODULE_LICENSE("GPL v2");