2 * drivers/mmc/host/sdhci-spear.c
4 * Support of SDHCI platform devices for spear soc family
6 * Copyright (C) 2010 ST Microelectronics
7 * Viresh Kumar <viresh.linux@gmail.com>
9 * Inspired by sdhci-pltfm.c
11 * This file is licensed under the terms of the GNU General Public
12 * License version 2. This program is licensed "as is" without any
13 * warranty of any kind, whether express or implied.
16 #include <linux/clk.h>
17 #include <linux/delay.h>
18 #include <linux/gpio.h>
19 #include <linux/highmem.h>
20 #include <linux/module.h>
21 #include <linux/interrupt.h>
22 #include <linux/irq.h>
24 #include <linux/of_gpio.h>
25 #include <linux/platform_device.h>
27 #include <linux/slab.h>
28 #include <linux/mmc/host.h>
29 #include <linux/mmc/sdhci-spear.h>
35 struct sdhci_plat_data
*data
;
39 static struct sdhci_ops sdhci_pltfm_ops
= {
40 /* Nothing to do for now. */
43 /* gpio card detection interrupt handler */
44 static irqreturn_t
sdhci_gpio_irq(int irq
, void *dev_id
)
46 struct platform_device
*pdev
= dev_id
;
47 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
48 struct spear_sdhci
*sdhci
= dev_get_platdata(&pdev
->dev
);
49 unsigned long gpio_irq_type
;
52 val
= gpio_get_value(sdhci
->data
->card_int_gpio
);
54 /* val == 1 -> card removed, val == 0 -> card inserted */
55 /* if card removed - set irq for low level, else vice versa */
56 gpio_irq_type
= val
? IRQF_TRIGGER_LOW
: IRQF_TRIGGER_HIGH
;
57 irq_set_irq_type(irq
, gpio_irq_type
);
59 if (sdhci
->data
->card_power_gpio
>= 0) {
60 if (!sdhci
->data
->power_always_enb
) {
61 /* if card inserted, give power, otherwise remove it */
62 val
= sdhci
->data
->power_active_high
? !val
: val
;
63 gpio_set_value(sdhci
->data
->card_power_gpio
, val
);
67 /* inform sdhci driver about card insertion/removal */
68 tasklet_schedule(&host
->card_tasklet
);
74 static struct sdhci_plat_data
* __devinit
75 sdhci_probe_config_dt(struct platform_device
*pdev
)
77 struct device_node
*np
= pdev
->dev
.of_node
;
78 struct sdhci_plat_data
*pdata
= NULL
;
81 cd_gpio
= of_get_named_gpio(np
, "cd-gpios", 0);
82 if (!gpio_is_valid(cd_gpio
))
85 /* If pdata is required */
87 pdata
= devm_kzalloc(&pdev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
89 dev_err(&pdev
->dev
, "DT: kzalloc failed\n");
90 return ERR_PTR(-ENOMEM
);
94 pdata
->card_int_gpio
= cd_gpio
;
99 static struct sdhci_plat_data
* __devinit
100 sdhci_probe_config_dt(struct platform_device
*pdev
)
102 return ERR_PTR(-ENOSYS
);
106 static int __devinit
sdhci_probe(struct platform_device
*pdev
)
108 struct device_node
*np
= pdev
->dev
.of_node
;
109 struct sdhci_host
*host
;
110 struct resource
*iomem
;
111 struct spear_sdhci
*sdhci
;
114 iomem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
117 dev_dbg(&pdev
->dev
, "memory resource not defined\n");
121 if (!devm_request_mem_region(&pdev
->dev
, iomem
->start
,
122 resource_size(iomem
), "spear-sdhci")) {
124 dev_dbg(&pdev
->dev
, "cannot request region\n");
128 sdhci
= devm_kzalloc(&pdev
->dev
, sizeof(*sdhci
), GFP_KERNEL
);
131 dev_dbg(&pdev
->dev
, "cannot allocate memory for sdhci\n");
136 sdhci
->clk
= clk_get(&pdev
->dev
, NULL
);
137 if (IS_ERR(sdhci
->clk
)) {
138 ret
= PTR_ERR(sdhci
->clk
);
139 dev_dbg(&pdev
->dev
, "Error getting clock\n");
143 ret
= clk_prepare_enable(sdhci
->clk
);
145 dev_dbg(&pdev
->dev
, "Error enabling clock\n");
150 sdhci
->data
= sdhci_probe_config_dt(pdev
);
151 if (IS_ERR(sdhci
->data
)) {
152 dev_err(&pdev
->dev
, "DT: Failed to get pdata\n");
156 sdhci
->data
= dev_get_platdata(&pdev
->dev
);
159 pdev
->dev
.platform_data
= sdhci
;
161 if (pdev
->dev
.parent
)
162 host
= sdhci_alloc_host(pdev
->dev
.parent
, 0);
164 host
= sdhci_alloc_host(&pdev
->dev
, 0);
168 dev_dbg(&pdev
->dev
, "error allocating host\n");
172 host
->hw_name
= "sdhci";
173 host
->ops
= &sdhci_pltfm_ops
;
174 host
->irq
= platform_get_irq(pdev
, 0);
175 host
->quirks
= SDHCI_QUIRK_BROKEN_ADMA
;
177 host
->ioaddr
= devm_ioremap(&pdev
->dev
, iomem
->start
,
178 resource_size(iomem
));
181 dev_dbg(&pdev
->dev
, "failed to remap registers\n");
185 ret
= sdhci_add_host(host
);
187 dev_dbg(&pdev
->dev
, "error adding host\n");
191 platform_set_drvdata(pdev
, host
);
194 * It is optional to use GPIOs for sdhci Power control & sdhci card
195 * interrupt detection. If sdhci->data is NULL, then use original sdhci
196 * lines otherwise GPIO lines.
197 * If GPIO is selected for power control, then power should be disabled
198 * after card removal and should be enabled when card insertion
204 if (sdhci
->data
->card_power_gpio
>= 0) {
207 ret
= devm_gpio_request(&pdev
->dev
,
208 sdhci
->data
->card_power_gpio
, "sdhci");
210 dev_dbg(&pdev
->dev
, "gpio request fail: %d\n",
211 sdhci
->data
->card_power_gpio
);
215 if (sdhci
->data
->power_always_enb
)
216 val
= sdhci
->data
->power_active_high
;
218 val
= !sdhci
->data
->power_active_high
;
220 ret
= gpio_direction_output(sdhci
->data
->card_power_gpio
, val
);
222 dev_dbg(&pdev
->dev
, "gpio set direction fail: %d\n",
223 sdhci
->data
->card_power_gpio
);
228 if (sdhci
->data
->card_int_gpio
>= 0) {
229 ret
= devm_gpio_request(&pdev
->dev
, sdhci
->data
->card_int_gpio
,
232 dev_dbg(&pdev
->dev
, "gpio request fail: %d\n",
233 sdhci
->data
->card_int_gpio
);
237 ret
= gpio_direction_input(sdhci
->data
->card_int_gpio
);
239 dev_dbg(&pdev
->dev
, "gpio set direction fail: %d\n",
240 sdhci
->data
->card_int_gpio
);
243 ret
= devm_request_irq(&pdev
->dev
,
244 gpio_to_irq(sdhci
->data
->card_int_gpio
),
245 sdhci_gpio_irq
, IRQF_TRIGGER_LOW
,
246 mmc_hostname(host
->mmc
), pdev
);
248 dev_dbg(&pdev
->dev
, "gpio request irq fail: %d\n",
249 sdhci
->data
->card_int_gpio
);
258 platform_set_drvdata(pdev
, NULL
);
259 sdhci_remove_host(host
, 1);
261 sdhci_free_host(host
);
263 clk_disable_unprepare(sdhci
->clk
);
267 dev_err(&pdev
->dev
, "spear-sdhci probe failed: %d\n", ret
);
271 static int __devexit
sdhci_remove(struct platform_device
*pdev
)
273 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
274 struct spear_sdhci
*sdhci
= dev_get_platdata(&pdev
->dev
);
278 platform_set_drvdata(pdev
, NULL
);
279 scratch
= readl(host
->ioaddr
+ SDHCI_INT_STATUS
);
280 if (scratch
== (u32
)-1)
283 sdhci_remove_host(host
, dead
);
284 sdhci_free_host(host
);
285 clk_disable_unprepare(sdhci
->clk
);
292 static int sdhci_suspend(struct device
*dev
)
294 struct sdhci_host
*host
= dev_get_drvdata(dev
);
295 struct spear_sdhci
*sdhci
= dev_get_platdata(dev
);
298 ret
= sdhci_suspend_host(host
);
300 clk_disable_unprepare(sdhci
->clk
);
305 static int sdhci_resume(struct device
*dev
)
307 struct sdhci_host
*host
= dev_get_drvdata(dev
);
308 struct spear_sdhci
*sdhci
= dev_get_platdata(dev
);
311 ret
= clk_prepare_enable(sdhci
->clk
);
313 dev_dbg(dev
, "Resume: Error enabling clock\n");
317 return sdhci_resume_host(host
);
321 static SIMPLE_DEV_PM_OPS(sdhci_pm_ops
, sdhci_suspend
, sdhci_resume
);
324 static const struct of_device_id sdhci_spear_id_table
[] = {
325 { .compatible
= "st,spear300-sdhci" },
328 MODULE_DEVICE_TABLE(of
, sdhci_spear_id_table
);
331 static struct platform_driver sdhci_driver
= {
334 .owner
= THIS_MODULE
,
336 .of_match_table
= of_match_ptr(sdhci_spear_id_table
),
338 .probe
= sdhci_probe
,
339 .remove
= __devexit_p(sdhci_remove
),
342 module_platform_driver(sdhci_driver
);
344 MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
345 MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
346 MODULE_LICENSE("GPL v2");