xref: /linux/drivers/mmc/host/sdhci-pltfm.c (revision 515033f97c0b5a1bce13fa93e09704d95b44f376)
1 /*
2  * sdhci-pltfm.c Support for SDHCI platform devices
3  * Copyright (c) 2009 Intel Corporation
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 /* Supports:
20  * SDHCI platform devices
21  *
22  * Inspired by sdhci-pci.c, by Pierre Ossman
23  */
24 
25 #include <linux/delay.h>
26 #include <linux/highmem.h>
27 #include <linux/mod_devicetable.h>
28 #include <linux/platform_device.h>
29 
30 #include <linux/mmc/host.h>
31 
32 #include <linux/io.h>
33 #include <linux/sdhci-pltfm.h>
34 
35 #include "sdhci.h"
36 #include "sdhci-pltfm.h"
37 
38 /*****************************************************************************\
39  *                                                                           *
40  * SDHCI core callbacks                                                      *
41  *                                                                           *
42 \*****************************************************************************/
43 
44 static struct sdhci_ops sdhci_pltfm_ops = {
45 };
46 
47 /*****************************************************************************\
48  *                                                                           *
49  * Device probing/removal                                                    *
50  *                                                                           *
51 \*****************************************************************************/
52 
53 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
54 {
55 	struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
56 	const struct platform_device_id *platid = platform_get_device_id(pdev);
57 	struct sdhci_host *host;
58 	struct resource *iomem;
59 	int ret;
60 
61 	if (!pdata && platid && platid->driver_data)
62 		pdata = (void *)platid->driver_data;
63 
64 	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
65 	if (!iomem) {
66 		ret = -ENOMEM;
67 		goto err;
68 	}
69 
70 	if (resource_size(iomem) < 0x100)
71 		dev_err(&pdev->dev, "Invalid iomem size. You may "
72 			"experience problems.\n");
73 
74 	if (pdev->dev.parent)
75 		host = sdhci_alloc_host(pdev->dev.parent, 0);
76 	else
77 		host = sdhci_alloc_host(&pdev->dev, 0);
78 
79 	if (IS_ERR(host)) {
80 		ret = PTR_ERR(host);
81 		goto err;
82 	}
83 
84 	host->hw_name = "platform";
85 	if (pdata && pdata->ops)
86 		host->ops = pdata->ops;
87 	else
88 		host->ops = &sdhci_pltfm_ops;
89 	if (pdata)
90 		host->quirks = pdata->quirks;
91 	host->irq = platform_get_irq(pdev, 0);
92 
93 	if (!request_mem_region(iomem->start, resource_size(iomem),
94 		mmc_hostname(host->mmc))) {
95 		dev_err(&pdev->dev, "cannot request region\n");
96 		ret = -EBUSY;
97 		goto err_request;
98 	}
99 
100 	host->ioaddr = ioremap(iomem->start, resource_size(iomem));
101 	if (!host->ioaddr) {
102 		dev_err(&pdev->dev, "failed to remap registers\n");
103 		ret = -ENOMEM;
104 		goto err_remap;
105 	}
106 
107 	if (pdata && pdata->init) {
108 		ret = pdata->init(host);
109 		if (ret)
110 			goto err_plat_init;
111 	}
112 
113 	ret = sdhci_add_host(host);
114 	if (ret)
115 		goto err_add_host;
116 
117 	platform_set_drvdata(pdev, host);
118 
119 	return 0;
120 
121 err_add_host:
122 	if (pdata && pdata->exit)
123 		pdata->exit(host);
124 err_plat_init:
125 	iounmap(host->ioaddr);
126 err_remap:
127 	release_mem_region(iomem->start, resource_size(iomem));
128 err_request:
129 	sdhci_free_host(host);
130 err:
131 	printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret);
132 	return ret;
133 }
134 
135 static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
136 {
137 	struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
138 	struct sdhci_host *host = platform_get_drvdata(pdev);
139 	struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
140 	int dead;
141 	u32 scratch;
142 
143 	dead = 0;
144 	scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
145 	if (scratch == (u32)-1)
146 		dead = 1;
147 
148 	sdhci_remove_host(host, dead);
149 	if (pdata && pdata->exit)
150 		pdata->exit(host);
151 	iounmap(host->ioaddr);
152 	release_mem_region(iomem->start, resource_size(iomem));
153 	sdhci_free_host(host);
154 	platform_set_drvdata(pdev, NULL);
155 
156 	return 0;
157 }
158 
159 static const struct platform_device_id sdhci_pltfm_ids[] = {
160 	{ "sdhci", },
161 	{ },
162 };
163 MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
164 
165 static struct platform_driver sdhci_pltfm_driver = {
166 	.driver = {
167 		.name	= "sdhci",
168 		.owner	= THIS_MODULE,
169 	},
170 	.probe		= sdhci_pltfm_probe,
171 	.remove		= __devexit_p(sdhci_pltfm_remove),
172 	.id_table	= sdhci_pltfm_ids,
173 };
174 
175 /*****************************************************************************\
176  *                                                                           *
177  * Driver init/exit                                                          *
178  *                                                                           *
179 \*****************************************************************************/
180 
181 static int __init sdhci_drv_init(void)
182 {
183 	return platform_driver_register(&sdhci_pltfm_driver);
184 }
185 
186 static void __exit sdhci_drv_exit(void)
187 {
188 	platform_driver_unregister(&sdhci_pltfm_driver);
189 }
190 
191 module_init(sdhci_drv_init);
192 module_exit(sdhci_drv_exit);
193 
194 MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
195 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
196 MODULE_LICENSE("GPL v2");
197