Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e29a7d73 PO |
2 | /* |
3 | * linux/drivers/mmc/core/sdio_bus.c | |
4 | * | |
5 | * Copyright 2007 Pierre Ossman | |
6 | * | |
e29a7d73 PO |
7 | * SDIO function driver model |
8 | */ | |
9 | ||
10 | #include <linux/device.h> | |
11 | #include <linux/err.h> | |
3ef77af1 | 12 | #include <linux/export.h> |
5a0e3ad6 | 13 | #include <linux/slab.h> |
80fd933c | 14 | #include <linux/pm_runtime.h> |
f48c767c | 15 | #include <linux/pm_domain.h> |
eed222ac | 16 | #include <linux/acpi.h> |
e29a7d73 PO |
17 | |
18 | #include <linux/mmc/card.h> | |
ed919b01 | 19 | #include <linux/mmc/host.h> |
e29a7d73 | 20 | #include <linux/mmc/sdio_func.h> |
25185f3f | 21 | #include <linux/of.h> |
e29a7d73 | 22 | |
25185f3f | 23 | #include "core.h" |
4facdde1 | 24 | #include "card.h" |
b1538bcf | 25 | #include "sdio_cis.h" |
e29a7d73 PO |
26 | #include "sdio_bus.h" |
27 | ||
433b7b12 UH |
28 | #define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) |
29 | ||
bcfe66e2 | 30 | /* show configuration fields */ |
b91ec1dc | 31 | #define sdio_config_attr(field, format_string, args...) \ |
bcfe66e2 PO |
32 | static ssize_t \ |
33 | field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ | |
34 | { \ | |
35 | struct sdio_func *func; \ | |
36 | \ | |
37 | func = dev_to_sdio_func (dev); \ | |
b91ec1dc | 38 | return sprintf(buf, format_string, args); \ |
f24fc57b GKH |
39 | } \ |
40 | static DEVICE_ATTR_RO(field) | |
bcfe66e2 | 41 | |
b91ec1dc PR |
42 | sdio_config_attr(class, "0x%02x\n", func->class); |
43 | sdio_config_attr(vendor, "0x%04x\n", func->vendor); | |
44 | sdio_config_attr(device, "0x%04x\n", func->device); | |
b698f6ab | 45 | sdio_config_attr(revision, "%u.%u\n", func->major_rev, func->minor_rev); |
b91ec1dc | 46 | sdio_config_attr(modalias, "sdio:c%02Xv%04Xd%04X\n", func->class, func->vendor, func->device); |
f24fc57b | 47 | |
b698f6ab PR |
48 | #define sdio_info_attr(num) \ |
49 | static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \ | |
50 | { \ | |
51 | struct sdio_func *func = dev_to_sdio_func(dev); \ | |
52 | \ | |
53 | if (num > func->num_info) \ | |
54 | return -ENODATA; \ | |
55 | if (!func->info[num-1][0]) \ | |
56 | return 0; \ | |
57 | return sprintf(buf, "%s\n", func->info[num-1]); \ | |
58 | } \ | |
59 | static DEVICE_ATTR_RO(info##num) | |
60 | ||
61 | sdio_info_attr(1); | |
62 | sdio_info_attr(2); | |
63 | sdio_info_attr(3); | |
64 | sdio_info_attr(4); | |
65 | ||
f24fc57b GKH |
66 | static struct attribute *sdio_dev_attrs[] = { |
67 | &dev_attr_class.attr, | |
68 | &dev_attr_vendor.attr, | |
69 | &dev_attr_device.attr, | |
b698f6ab PR |
70 | &dev_attr_revision.attr, |
71 | &dev_attr_info1.attr, | |
72 | &dev_attr_info2.attr, | |
73 | &dev_attr_info3.attr, | |
74 | &dev_attr_info4.attr, | |
f24fc57b GKH |
75 | &dev_attr_modalias.attr, |
76 | NULL, | |
bcfe66e2 | 77 | }; |
f24fc57b | 78 | ATTRIBUTE_GROUPS(sdio_dev); |
bcfe66e2 | 79 | |
3b38bea0 PO |
80 | static const struct sdio_device_id *sdio_match_one(struct sdio_func *func, |
81 | const struct sdio_device_id *id) | |
82 | { | |
83 | if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class) | |
84 | return NULL; | |
85 | if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor) | |
86 | return NULL; | |
87 | if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device) | |
88 | return NULL; | |
89 | return id; | |
90 | } | |
91 | ||
92 | static const struct sdio_device_id *sdio_match_device(struct sdio_func *func, | |
93 | struct sdio_driver *sdrv) | |
94 | { | |
95 | const struct sdio_device_id *ids; | |
96 | ||
97 | ids = sdrv->id_table; | |
98 | ||
99 | if (ids) { | |
100 | while (ids->class || ids->vendor || ids->device) { | |
101 | if (sdio_match_one(func, ids)) | |
102 | return ids; | |
103 | ids++; | |
104 | } | |
105 | } | |
106 | ||
107 | return NULL; | |
108 | } | |
e29a7d73 | 109 | |
e29a7d73 PO |
110 | static int sdio_bus_match(struct device *dev, struct device_driver *drv) |
111 | { | |
3b38bea0 PO |
112 | struct sdio_func *func = dev_to_sdio_func(dev); |
113 | struct sdio_driver *sdrv = to_sdio_driver(drv); | |
114 | ||
115 | if (sdio_match_device(func, sdrv)) | |
116 | return 1; | |
117 | ||
118 | return 0; | |
e29a7d73 PO |
119 | } |
120 | ||
121 | static int | |
7ac0326c | 122 | sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env) |
e29a7d73 | 123 | { |
d59b66c7 | 124 | struct sdio_func *func = dev_to_sdio_func(dev); |
b698f6ab | 125 | unsigned int i; |
d59b66c7 | 126 | |
7ac0326c | 127 | if (add_uevent_var(env, |
d59b66c7 PO |
128 | "SDIO_CLASS=%02X", func->class)) |
129 | return -ENOMEM; | |
130 | ||
7ac0326c | 131 | if (add_uevent_var(env, |
d59b66c7 PO |
132 | "SDIO_ID=%04X:%04X", func->vendor, func->device)) |
133 | return -ENOMEM; | |
134 | ||
b698f6ab PR |
135 | if (add_uevent_var(env, |
136 | "SDIO_REVISION=%u.%u", func->major_rev, func->minor_rev)) | |
137 | return -ENOMEM; | |
138 | ||
139 | for (i = 0; i < func->num_info; i++) { | |
140 | if (add_uevent_var(env, "SDIO_INFO%u=%s", i+1, func->info[i])) | |
141 | return -ENOMEM; | |
142 | } | |
143 | ||
7ac0326c | 144 | if (add_uevent_var(env, |
d59b66c7 PO |
145 | "MODALIAS=sdio:c%02Xv%04Xd%04X", |
146 | func->class, func->vendor, func->device)) | |
147 | return -ENOMEM; | |
148 | ||
e29a7d73 PO |
149 | return 0; |
150 | } | |
151 | ||
152 | static int sdio_bus_probe(struct device *dev) | |
153 | { | |
3b38bea0 PO |
154 | struct sdio_driver *drv = to_sdio_driver(dev->driver); |
155 | struct sdio_func *func = dev_to_sdio_func(dev); | |
156 | const struct sdio_device_id *id; | |
9a08f82b | 157 | int ret; |
3b38bea0 PO |
158 | |
159 | id = sdio_match_device(func, drv); | |
160 | if (!id) | |
161 | return -ENODEV; | |
162 | ||
1ef48e3d | 163 | ret = dev_pm_domain_attach(dev, false); |
d23fc022 | 164 | if (ret) |
1ef48e3d UH |
165 | return ret; |
166 | ||
2ac55d5e UH |
167 | atomic_inc(&func->card->sdio_funcs_probed); |
168 | ||
40bba0c1 OBC |
169 | /* Unbound SDIO functions are always suspended. |
170 | * During probe, the function is set active and the usage count | |
171 | * is incremented. If the driver supports runtime PM, | |
172 | * it should call pm_runtime_put_noidle() in its probe routine and | |
173 | * pm_runtime_get_noresume() in its remove routine. | |
174 | */ | |
ed919b01 OBC |
175 | if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { |
176 | ret = pm_runtime_get_sync(dev); | |
177 | if (ret < 0) | |
3bffb800 | 178 | goto disable_runtimepm; |
ed919b01 | 179 | } |
40bba0c1 | 180 | |
9a08f82b DV |
181 | /* Set the default block size so the driver is sure it's something |
182 | * sensible. */ | |
183 | sdio_claim_host(func); | |
2ac55d5e UH |
184 | if (mmc_card_removed(func->card)) |
185 | ret = -ENOMEDIUM; | |
186 | else | |
187 | ret = sdio_set_block_size(func, 0); | |
9a08f82b DV |
188 | sdio_release_host(func); |
189 | if (ret) | |
40bba0c1 OBC |
190 | goto disable_runtimepm; |
191 | ||
192 | ret = drv->probe(func, id); | |
193 | if (ret) | |
194 | goto disable_runtimepm; | |
195 | ||
196 | return 0; | |
9a08f82b | 197 | |
40bba0c1 | 198 | disable_runtimepm: |
2ac55d5e | 199 | atomic_dec(&func->card->sdio_funcs_probed); |
ed919b01 OBC |
200 | if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) |
201 | pm_runtime_put_noidle(dev); | |
1ef48e3d | 202 | dev_pm_domain_detach(dev, false); |
40bba0c1 | 203 | return ret; |
e29a7d73 PO |
204 | } |
205 | ||
206 | static int sdio_bus_remove(struct device *dev) | |
207 | { | |
3b38bea0 PO |
208 | struct sdio_driver *drv = to_sdio_driver(dev->driver); |
209 | struct sdio_func *func = dev_to_sdio_func(dev); | |
40bba0c1 OBC |
210 | |
211 | /* Make sure card is powered before invoking ->remove() */ | |
ecc02441 OBC |
212 | if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) |
213 | pm_runtime_get_sync(dev); | |
3b38bea0 PO |
214 | |
215 | drv->remove(func); | |
2ac55d5e | 216 | atomic_dec(&func->card->sdio_funcs_probed); |
3b38bea0 | 217 | |
d1496c39 | 218 | if (func->irq_handler) { |
6606110d JP |
219 | pr_warn("WARNING: driver %s did not remove its interrupt handler!\n", |
220 | drv->name); | |
d1496c39 NP |
221 | sdio_claim_host(func); |
222 | sdio_release_irq(func); | |
223 | sdio_release_host(func); | |
224 | } | |
225 | ||
40bba0c1 | 226 | /* First, undo the increment made directly above */ |
ed919b01 OBC |
227 | if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) |
228 | pm_runtime_put_noidle(dev); | |
40bba0c1 OBC |
229 | |
230 | /* Then undo the runtime PM settings in sdio_bus_probe() */ | |
ed919b01 | 231 | if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) |
297c7f2f | 232 | pm_runtime_put_sync(dev); |
40bba0c1 | 233 | |
1ef48e3d UH |
234 | dev_pm_domain_detach(dev, false); |
235 | ||
7e926f42 | 236 | return 0; |
e29a7d73 PO |
237 | } |
238 | ||
80fd933c | 239 | static const struct dev_pm_ops sdio_bus_pm_ops = { |
573185cc | 240 | SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) |
80fd933c OBC |
241 | SET_RUNTIME_PM_OPS( |
242 | pm_generic_runtime_suspend, | |
243 | pm_generic_runtime_resume, | |
45f0a85c | 244 | NULL |
80fd933c OBC |
245 | ) |
246 | }; | |
247 | ||
e29a7d73 PO |
248 | static struct bus_type sdio_bus_type = { |
249 | .name = "sdio", | |
f24fc57b | 250 | .dev_groups = sdio_dev_groups, |
e29a7d73 PO |
251 | .match = sdio_bus_match, |
252 | .uevent = sdio_bus_uevent, | |
253 | .probe = sdio_bus_probe, | |
254 | .remove = sdio_bus_remove, | |
d99903ca | 255 | .pm = &sdio_bus_pm_ops, |
e29a7d73 PO |
256 | }; |
257 | ||
258 | int sdio_register_bus(void) | |
259 | { | |
260 | return bus_register(&sdio_bus_type); | |
261 | } | |
262 | ||
263 | void sdio_unregister_bus(void) | |
264 | { | |
265 | bus_unregister(&sdio_bus_type); | |
266 | } | |
267 | ||
f76c8515 PO |
268 | /** |
269 | * sdio_register_driver - register a function driver | |
270 | * @drv: SDIO function driver | |
271 | */ | |
272 | int sdio_register_driver(struct sdio_driver *drv) | |
273 | { | |
274 | drv->drv.name = drv->name; | |
275 | drv->drv.bus = &sdio_bus_type; | |
276 | return driver_register(&drv->drv); | |
277 | } | |
278 | EXPORT_SYMBOL_GPL(sdio_register_driver); | |
279 | ||
280 | /** | |
281 | * sdio_unregister_driver - unregister a function driver | |
282 | * @drv: SDIO function driver | |
283 | */ | |
284 | void sdio_unregister_driver(struct sdio_driver *drv) | |
285 | { | |
286 | drv->drv.bus = &sdio_bus_type; | |
287 | driver_unregister(&drv->drv); | |
288 | } | |
289 | EXPORT_SYMBOL_GPL(sdio_unregister_driver); | |
290 | ||
e29a7d73 PO |
291 | static void sdio_release_func(struct device *dev) |
292 | { | |
293 | struct sdio_func *func = dev_to_sdio_func(dev); | |
b1538bcf | 294 | |
1a632f8c | 295 | sdio_free_func_cis(func); |
e29a7d73 | 296 | |
4c42d6cc | 297 | kfree(func->info); |
5ef1ecf0 | 298 | kfree(func->tmpbuf); |
e29a7d73 PO |
299 | kfree(func); |
300 | } | |
301 | ||
302 | /* | |
303 | * Allocate and initialise a new SDIO function structure. | |
304 | */ | |
305 | struct sdio_func *sdio_alloc_func(struct mmc_card *card) | |
306 | { | |
307 | struct sdio_func *func; | |
308 | ||
9f2fcf99 | 309 | func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL); |
e29a7d73 PO |
310 | if (!func) |
311 | return ERR_PTR(-ENOMEM); | |
312 | ||
5ef1ecf0 HK |
313 | /* |
314 | * allocate buffer separately to make sure it's properly aligned for | |
315 | * DMA usage (incl. 64 bit DMA) | |
316 | */ | |
317 | func->tmpbuf = kmalloc(4, GFP_KERNEL); | |
318 | if (!func->tmpbuf) { | |
319 | kfree(func); | |
320 | return ERR_PTR(-ENOMEM); | |
321 | } | |
322 | ||
e29a7d73 PO |
323 | func->card = card; |
324 | ||
325 | device_initialize(&func->dev); | |
326 | ||
327 | func->dev.parent = &card->dev; | |
328 | func->dev.bus = &sdio_bus_type; | |
329 | func->dev.release = sdio_release_func; | |
330 | ||
331 | return func; | |
332 | } | |
333 | ||
eed222ac AL |
334 | #ifdef CONFIG_ACPI |
335 | static void sdio_acpi_set_handle(struct sdio_func *func) | |
336 | { | |
337 | struct mmc_host *host = func->card->host; | |
51d34606 | 338 | u64 addr = ((u64)host->slotno << 16) | func->num; |
eed222ac | 339 | |
9c5ad36d | 340 | acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); |
eed222ac AL |
341 | } |
342 | #else | |
343 | static inline void sdio_acpi_set_handle(struct sdio_func *func) {} | |
344 | #endif | |
345 | ||
25185f3f SH |
346 | static void sdio_set_of_node(struct sdio_func *func) |
347 | { | |
348 | struct mmc_host *host = func->card->host; | |
349 | ||
350 | func->dev.of_node = mmc_of_find_child_device(host, func->num); | |
351 | } | |
352 | ||
e29a7d73 PO |
353 | /* |
354 | * Register a new SDIO function with the driver model. | |
355 | */ | |
356 | int sdio_add_func(struct sdio_func *func) | |
357 | { | |
358 | int ret; | |
359 | ||
d1b26863 | 360 | dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); |
e29a7d73 | 361 | |
25185f3f | 362 | sdio_set_of_node(func); |
eed222ac | 363 | sdio_acpi_set_handle(func); |
ec076cd2 | 364 | device_enable_async_suspend(&func->dev); |
e29a7d73 | 365 | ret = device_add(&func->dev); |
1ef48e3d | 366 | if (ret == 0) |
e29a7d73 PO |
367 | sdio_func_set_present(func); |
368 | ||
369 | return ret; | |
370 | } | |
371 | ||
372 | /* | |
373 | * Unregister a SDIO function with the driver model, and | |
374 | * (eventually) free it. | |
3d10a1ba DD |
375 | * This function can be called through error paths where sdio_add_func() was |
376 | * never executed (because a failure occurred at an earlier point). | |
e29a7d73 PO |
377 | */ |
378 | void sdio_remove_func(struct sdio_func *func) | |
379 | { | |
3d10a1ba DD |
380 | if (!sdio_func_present(func)) |
381 | return; | |
e29a7d73 | 382 | |
3d10a1ba | 383 | device_del(&func->dev); |
25185f3f | 384 | of_node_put(func->dev.of_node); |
e29a7d73 PO |
385 | put_device(&func->dev); |
386 | } | |
387 |