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 const 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
*sdhci_probe_config_dt(struct platform_device
*pdev
)
76 struct device_node
*np
= pdev
->dev
.of_node
;
77 struct sdhci_plat_data
*pdata
= NULL
;
80 cd_gpio
= of_get_named_gpio(np
, "cd-gpios", 0);
81 if (!gpio_is_valid(cd_gpio
))
84 /* If pdata is required */
86 pdata
= devm_kzalloc(&pdev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
88 dev_err(&pdev
->dev
, "DT: kzalloc failed\n");
89 return ERR_PTR(-ENOMEM
);
93 pdata
->card_int_gpio
= cd_gpio
;
98 static struct sdhci_plat_data
*sdhci_probe_config_dt(struct platform_device
*pdev
)
100 return ERR_PTR(-ENOSYS
);
104 static int sdhci_probe(struct platform_device
*pdev
)
106 struct device_node
*np
= pdev
->dev
.of_node
;
107 struct sdhci_host
*host
;
108 struct resource
*iomem
;
109 struct spear_sdhci
*sdhci
;
112 iomem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
115 dev_dbg(&pdev
->dev
, "memory resource not defined\n");
119 if (!devm_request_mem_region(&pdev
->dev
, iomem
->start
,
120 resource_size(iomem
), "spear-sdhci")) {
122 dev_dbg(&pdev
->dev
, "cannot request region\n");
126 sdhci
= devm_kzalloc(&pdev
->dev
, sizeof(*sdhci
), GFP_KERNEL
);
129 dev_dbg(&pdev
->dev
, "cannot allocate memory for sdhci\n");
134 sdhci
->clk
= clk_get(&pdev
->dev
, NULL
);
135 if (IS_ERR(sdhci
->clk
)) {
136 ret
= PTR_ERR(sdhci
->clk
);
137 dev_dbg(&pdev
->dev
, "Error getting clock\n");
141 ret
= clk_prepare_enable(sdhci
->clk
);
143 dev_dbg(&pdev
->dev
, "Error enabling clock\n");
147 ret
= clk_set_rate(sdhci
->clk
, 50000000);
149 dev_dbg(&pdev
->dev
, "Error setting desired clk, clk=%lu\n",
150 clk_get_rate(sdhci
->clk
));
153 sdhci
->data
= sdhci_probe_config_dt(pdev
);
154 if (IS_ERR(sdhci
->data
)) {
155 dev_err(&pdev
->dev
, "DT: Failed to get pdata\n");
159 sdhci
->data
= dev_get_platdata(&pdev
->dev
);
162 pdev
->dev
.platform_data
= sdhci
;
164 if (pdev
->dev
.parent
)
165 host
= sdhci_alloc_host(pdev
->dev
.parent
, 0);
167 host
= sdhci_alloc_host(&pdev
->dev
, 0);
171 dev_dbg(&pdev
->dev
, "error allocating host\n");
175 host
->hw_name
= "sdhci";
176 host
->ops
= &sdhci_pltfm_ops
;
177 host
->irq
= platform_get_irq(pdev
, 0);
178 host
->quirks
= SDHCI_QUIRK_BROKEN_ADMA
;
180 host
->ioaddr
= devm_ioremap(&pdev
->dev
, iomem
->start
,
181 resource_size(iomem
));
184 dev_dbg(&pdev
->dev
, "failed to remap registers\n");
188 ret
= sdhci_add_host(host
);
190 dev_dbg(&pdev
->dev
, "error adding host\n");
194 platform_set_drvdata(pdev
, host
);
197 * It is optional to use GPIOs for sdhci Power control & sdhci card
198 * interrupt detection. If sdhci->data is NULL, then use original sdhci
199 * lines otherwise GPIO lines.
200 * If GPIO is selected for power control, then power should be disabled
201 * after card removal and should be enabled when card insertion
207 if (sdhci
->data
->card_power_gpio
>= 0) {
210 ret
= devm_gpio_request(&pdev
->dev
,
211 sdhci
->data
->card_power_gpio
, "sdhci");
213 dev_dbg(&pdev
->dev
, "gpio request fail: %d\n",
214 sdhci
->data
->card_power_gpio
);
218 if (sdhci
->data
->power_always_enb
)
219 val
= sdhci
->data
->power_active_high
;
221 val
= !sdhci
->data
->power_active_high
;
223 ret
= gpio_direction_output(sdhci
->data
->card_power_gpio
, val
);
225 dev_dbg(&pdev
->dev
, "gpio set direction fail: %d\n",
226 sdhci
->data
->card_power_gpio
);
231 if (sdhci
->data
->card_int_gpio
>= 0) {
232 ret
= devm_gpio_request(&pdev
->dev
, sdhci
->data
->card_int_gpio
,
235 dev_dbg(&pdev
->dev
, "gpio request fail: %d\n",
236 sdhci
->data
->card_int_gpio
);
240 ret
= gpio_direction_input(sdhci
->data
->card_int_gpio
);
242 dev_dbg(&pdev
->dev
, "gpio set direction fail: %d\n",
243 sdhci
->data
->card_int_gpio
);
246 ret
= devm_request_irq(&pdev
->dev
,
247 gpio_to_irq(sdhci
->data
->card_int_gpio
),
248 sdhci_gpio_irq
, IRQF_TRIGGER_LOW
,
249 mmc_hostname(host
->mmc
), pdev
);
251 dev_dbg(&pdev
->dev
, "gpio request irq fail: %d\n",
252 sdhci
->data
->card_int_gpio
);
261 sdhci_remove_host(host
, 1);
263 sdhci_free_host(host
);
265 clk_disable_unprepare(sdhci
->clk
);
269 dev_err(&pdev
->dev
, "spear-sdhci probe failed: %d\n", ret
);
273 static int sdhci_remove(struct platform_device
*pdev
)
275 struct sdhci_host
*host
= platform_get_drvdata(pdev
);
276 struct spear_sdhci
*sdhci
= dev_get_platdata(&pdev
->dev
);
280 scratch
= readl(host
->ioaddr
+ SDHCI_INT_STATUS
);
281 if (scratch
== (u32
)-1)
284 sdhci_remove_host(host
, dead
);
285 sdhci_free_host(host
);
286 clk_disable_unprepare(sdhci
->clk
);
292 #ifdef CONFIG_PM_SLEEP
293 static int sdhci_suspend(struct device
*dev
)
295 struct sdhci_host
*host
= dev_get_drvdata(dev
);
296 struct spear_sdhci
*sdhci
= dev_get_platdata(dev
);
299 ret
= sdhci_suspend_host(host
);
301 clk_disable(sdhci
->clk
);
306 static int sdhci_resume(struct device
*dev
)
308 struct sdhci_host
*host
= dev_get_drvdata(dev
);
309 struct spear_sdhci
*sdhci
= dev_get_platdata(dev
);
312 ret
= clk_enable(sdhci
->clk
);
314 dev_dbg(dev
, "Resume: Error enabling clock\n");
318 return sdhci_resume_host(host
);
322 static SIMPLE_DEV_PM_OPS(sdhci_pm_ops
, sdhci_suspend
, sdhci_resume
);
325 static const struct of_device_id sdhci_spear_id_table
[] = {
326 { .compatible
= "st,spear300-sdhci" },
329 MODULE_DEVICE_TABLE(of
, sdhci_spear_id_table
);
332 static struct platform_driver sdhci_driver
= {
335 .owner
= THIS_MODULE
,
337 .of_match_table
= of_match_ptr(sdhci_spear_id_table
),
339 .probe
= sdhci_probe
,
340 .remove
= sdhci_remove
,
343 module_platform_driver(sdhci_driver
);
345 MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
346 MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
347 MODULE_LICENSE("GPL v2");