]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/mmc/host/sdhci-sirf.c
mmc: sdhci: Use work structs instead of tasklets
[karo-tx-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         .get_max_clock  = sdhci_sirf_get_max_clk,
32 };
33
34 static struct sdhci_pltfm_data sdhci_sirf_pdata = {
35         .ops = &sdhci_sirf_ops,
36         .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
37                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
38                 SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
39                 SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
40                 SDHCI_QUIRK_DELAY_AFTER_POWER,
41 };
42
43 static int sdhci_sirf_probe(struct platform_device *pdev)
44 {
45         struct sdhci_host *host;
46         struct sdhci_pltfm_host *pltfm_host;
47         struct sdhci_sirf_priv *priv;
48         struct clk *clk;
49         int gpio_cd;
50         int ret;
51
52         clk = devm_clk_get(&pdev->dev, NULL);
53         if (IS_ERR(clk)) {
54                 dev_err(&pdev->dev, "unable to get clock");
55                 return PTR_ERR(clk);
56         }
57
58         if (pdev->dev.of_node)
59                 gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
60         else
61                 gpio_cd = -EINVAL;
62
63         host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
64         if (IS_ERR(host))
65                 return PTR_ERR(host);
66
67         pltfm_host = sdhci_priv(host);
68         priv = sdhci_pltfm_priv(pltfm_host);
69         priv->clk = clk;
70         priv->gpio_cd = gpio_cd;
71
72         sdhci_get_of_property(pdev);
73
74         ret = clk_prepare_enable(priv->clk);
75         if (ret)
76                 goto err_clk_prepare;
77
78         ret = sdhci_add_host(host);
79         if (ret)
80                 goto err_sdhci_add;
81
82         /*
83          * We must request the IRQ after sdhci_add_host(), as the workqueue
84          * only gets setup in sdhci_add_host() and we oops.
85          */
86         if (gpio_is_valid(priv->gpio_cd)) {
87                 ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0);
88                 if (ret) {
89                         dev_err(&pdev->dev, "card detect irq request failed: %d\n",
90                                 ret);
91                         goto err_request_cd;
92                 }
93         }
94
95         return 0;
96
97 err_request_cd:
98         sdhci_remove_host(host, 0);
99 err_sdhci_add:
100         clk_disable_unprepare(priv->clk);
101 err_clk_prepare:
102         sdhci_pltfm_free(pdev);
103         return ret;
104 }
105
106 static int sdhci_sirf_remove(struct platform_device *pdev)
107 {
108         struct sdhci_host *host = platform_get_drvdata(pdev);
109         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
110         struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
111
112         sdhci_pltfm_unregister(pdev);
113
114         if (gpio_is_valid(priv->gpio_cd))
115                 mmc_gpio_free_cd(host->mmc);
116
117         clk_disable_unprepare(priv->clk);
118         return 0;
119 }
120
121 #ifdef CONFIG_PM_SLEEP
122 static int sdhci_sirf_suspend(struct device *dev)
123 {
124         struct sdhci_host *host = dev_get_drvdata(dev);
125         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
126         struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
127         int ret;
128
129         ret = sdhci_suspend_host(host);
130         if (ret)
131                 return ret;
132
133         clk_disable(priv->clk);
134
135         return 0;
136 }
137
138 static int sdhci_sirf_resume(struct device *dev)
139 {
140         struct sdhci_host *host = dev_get_drvdata(dev);
141         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
142         struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
143         int ret;
144
145         ret = clk_enable(priv->clk);
146         if (ret) {
147                 dev_dbg(dev, "Resume: Error enabling clock\n");
148                 return ret;
149         }
150
151         return sdhci_resume_host(host);
152 }
153
154 static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
155 #endif
156
157 static const struct of_device_id sdhci_sirf_of_match[] = {
158         { .compatible = "sirf,prima2-sdhc" },
159         { }
160 };
161 MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
162
163 static struct platform_driver sdhci_sirf_driver = {
164         .driver         = {
165                 .name   = "sdhci-sirf",
166                 .owner  = THIS_MODULE,
167                 .of_match_table = sdhci_sirf_of_match,
168 #ifdef CONFIG_PM_SLEEP
169                 .pm     = &sdhci_sirf_pm_ops,
170 #endif
171         },
172         .probe          = sdhci_sirf_probe,
173         .remove         = sdhci_sirf_remove,
174 };
175
176 module_platform_driver(sdhci_sirf_driver);
177
178 MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco");
179 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
180 MODULE_LICENSE("GPL v2");