Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/mmc/host/sdhci-pltfm.c
15112 views
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/mmc/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
const struct platform_device_id *platid = platform_get_device_id(pdev);
56
struct sdhci_pltfm_data *pdata;
57
struct sdhci_host *host;
58
struct sdhci_pltfm_host *pltfm_host;
59
struct resource *iomem;
60
int ret;
61
62
if (platid && platid->driver_data)
63
pdata = (void *)platid->driver_data;
64
else
65
pdata = pdev->dev.platform_data;
66
67
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
68
if (!iomem) {
69
ret = -ENOMEM;
70
goto err;
71
}
72
73
if (resource_size(iomem) < 0x100)
74
dev_err(&pdev->dev, "Invalid iomem size. You may "
75
"experience problems.\n");
76
77
/* Some PCI-based MFD need the parent here */
78
if (pdev->dev.parent != &platform_bus)
79
host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
80
else
81
host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
82
83
if (IS_ERR(host)) {
84
ret = PTR_ERR(host);
85
goto err;
86
}
87
88
pltfm_host = sdhci_priv(host);
89
90
host->hw_name = "platform";
91
if (pdata && pdata->ops)
92
host->ops = pdata->ops;
93
else
94
host->ops = &sdhci_pltfm_ops;
95
if (pdata)
96
host->quirks = pdata->quirks;
97
host->irq = platform_get_irq(pdev, 0);
98
99
if (!request_mem_region(iomem->start, resource_size(iomem),
100
mmc_hostname(host->mmc))) {
101
dev_err(&pdev->dev, "cannot request region\n");
102
ret = -EBUSY;
103
goto err_request;
104
}
105
106
host->ioaddr = ioremap(iomem->start, resource_size(iomem));
107
if (!host->ioaddr) {
108
dev_err(&pdev->dev, "failed to remap registers\n");
109
ret = -ENOMEM;
110
goto err_remap;
111
}
112
113
if (pdata && pdata->init) {
114
ret = pdata->init(host, pdata);
115
if (ret)
116
goto err_plat_init;
117
}
118
119
ret = sdhci_add_host(host);
120
if (ret)
121
goto err_add_host;
122
123
platform_set_drvdata(pdev, host);
124
125
return 0;
126
127
err_add_host:
128
if (pdata && pdata->exit)
129
pdata->exit(host);
130
err_plat_init:
131
iounmap(host->ioaddr);
132
err_remap:
133
release_mem_region(iomem->start, resource_size(iomem));
134
err_request:
135
sdhci_free_host(host);
136
err:
137
printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret);
138
return ret;
139
}
140
141
static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
142
{
143
struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
144
struct sdhci_host *host = platform_get_drvdata(pdev);
145
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
146
int dead;
147
u32 scratch;
148
149
dead = 0;
150
scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
151
if (scratch == (u32)-1)
152
dead = 1;
153
154
sdhci_remove_host(host, dead);
155
if (pdata && pdata->exit)
156
pdata->exit(host);
157
iounmap(host->ioaddr);
158
release_mem_region(iomem->start, resource_size(iomem));
159
sdhci_free_host(host);
160
platform_set_drvdata(pdev, NULL);
161
162
return 0;
163
}
164
165
static const struct platform_device_id sdhci_pltfm_ids[] = {
166
{ "sdhci", },
167
#ifdef CONFIG_MMC_SDHCI_CNS3XXX
168
{ "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
169
#endif
170
#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
171
{ "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
172
#endif
173
#ifdef CONFIG_MMC_SDHCI_DOVE
174
{ "sdhci-dove", (kernel_ulong_t)&sdhci_dove_pdata },
175
#endif
176
#ifdef CONFIG_MMC_SDHCI_TEGRA
177
{ "sdhci-tegra", (kernel_ulong_t)&sdhci_tegra_pdata },
178
#endif
179
{ },
180
};
181
MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
182
183
#ifdef CONFIG_PM
184
static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
185
{
186
struct sdhci_host *host = platform_get_drvdata(dev);
187
188
return sdhci_suspend_host(host, state);
189
}
190
191
static int sdhci_pltfm_resume(struct platform_device *dev)
192
{
193
struct sdhci_host *host = platform_get_drvdata(dev);
194
195
return sdhci_resume_host(host);
196
}
197
#else
198
#define sdhci_pltfm_suspend NULL
199
#define sdhci_pltfm_resume NULL
200
#endif /* CONFIG_PM */
201
202
static struct platform_driver sdhci_pltfm_driver = {
203
.driver = {
204
.name = "sdhci",
205
.owner = THIS_MODULE,
206
},
207
.probe = sdhci_pltfm_probe,
208
.remove = __devexit_p(sdhci_pltfm_remove),
209
.id_table = sdhci_pltfm_ids,
210
.suspend = sdhci_pltfm_suspend,
211
.resume = sdhci_pltfm_resume,
212
};
213
214
/*****************************************************************************\
215
* *
216
* Driver init/exit *
217
* *
218
\*****************************************************************************/
219
220
static int __init sdhci_drv_init(void)
221
{
222
return platform_driver_register(&sdhci_pltfm_driver);
223
}
224
225
static void __exit sdhci_drv_exit(void)
226
{
227
platform_driver_unregister(&sdhci_pltfm_driver);
228
}
229
230
module_init(sdhci_drv_init);
231
module_exit(sdhci_drv_exit);
232
233
MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
234
MODULE_AUTHOR("Mocean Laboratories <[email protected]>");
235
MODULE_LICENSE("GPL v2");
236
237