Blame view
drivers/base/platform.c
36.2 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 |
/* * platform.c - platform 'pseudo' bus for legacy devices * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * * This file is released under the GPLv2 * * Please see Documentation/driver-model/platform.txt for more * information. */ |
daa412267 driver core: plat... |
12 |
#include <linux/string.h> |
d052d1bef Create platform_d... |
13 |
#include <linux/platform_device.h> |
05212157e drivercore/of: Ad... |
14 |
#include <linux/of_device.h> |
9ec36cafe of/irq: do irq re... |
15 |
#include <linux/of_irq.h> |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 19 20 |
#include <linux/module.h> #include <linux/init.h> #include <linux/dma-mapping.h> #include <linux/bootmem.h> #include <linux/err.h> |
4e57b6817 [PATCH] fix missi... |
21 |
#include <linux/slab.h> |
9d7302299 PM: Run-time PM p... |
22 |
#include <linux/pm_runtime.h> |
f48c767ce PM / Domains: Mov... |
23 |
#include <linux/pm_domain.h> |
689ae231a platform: Add sup... |
24 |
#include <linux/idr.h> |
91e568780 ACPI: Add support... |
25 |
#include <linux/acpi.h> |
86be408bf clk: Support for ... |
26 |
#include <linux/clk/clk-conf.h> |
3d713e0e3 driver core: plat... |
27 |
#include <linux/limits.h> |
00bbc1d8e driver core: plat... |
28 |
#include <linux/property.h> |
1da177e4c Linux-2.6.12-rc2 |
29 |
|
a1bdc7aad [PATCH] drivers/b... |
30 |
#include "base.h" |
bed2b42d9 PM / Runtime: All... |
31 |
#include "power/power.h" |
a1bdc7aad [PATCH] drivers/b... |
32 |
|
689ae231a platform: Add sup... |
33 34 |
/* For automatically allocated device IDs */ static DEFINE_IDA(platform_devid_ida); |
1da177e4c Linux-2.6.12-rc2 |
35 |
struct device platform_bus = { |
1e0b2cf93 driver core: stru... |
36 |
.init_name = "platform", |
1da177e4c Linux-2.6.12-rc2 |
37 |
}; |
a96b20420 [PATCH] Driver Co... |
38 |
EXPORT_SYMBOL_GPL(platform_bus); |
1da177e4c Linux-2.6.12-rc2 |
39 40 |
/** |
a77ce8167 driver core: Add ... |
41 |
* arch_setup_pdev_archdata - Allow manipulation of archdata before its used |
7de636fa2 driver core: fix ... |
42 |
* @pdev: platform device |
a77ce8167 driver core: Add ... |
43 44 45 46 47 |
* * This is called before platform_device_add() such that any pdev_archdata may * be setup before the platform_notifier is called. So if a user needs to * manipulate any relevant information in the pdev_archdata they can do: * |
b1d6d8225 drivers/base: fix... |
48 |
* platform_device_alloc() |
0258e182e driver core: plat... |
49 50 |
* ... manipulate ... * platform_device_add() |
a77ce8167 driver core: Add ... |
51 52 53 54 55 56 57 58 59 |
* * And if they don't care they can just call platform_device_register() and * everything will just work out. */ void __weak arch_setup_pdev_archdata(struct platform_device *pdev) { } /** |
4a3ad20cc Driver core: codi... |
60 61 62 63 |
* platform_get_resource - get a resource for a device * @dev: platform device * @type: resource type * @num: resource index |
1da177e4c Linux-2.6.12-rc2 |
64 |
*/ |
4a3ad20cc Driver core: codi... |
65 66 |
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num) |
1da177e4c Linux-2.6.12-rc2 |
67 68 69 70 71 |
{ int i; for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; |
c9f66169f resource: add res... |
72 73 |
if (type == resource_type(r) && num-- == 0) return r; |
1da177e4c Linux-2.6.12-rc2 |
74 75 76 |
} return NULL; } |
a96b20420 [PATCH] Driver Co... |
77 |
EXPORT_SYMBOL_GPL(platform_get_resource); |
1da177e4c Linux-2.6.12-rc2 |
78 79 |
/** |
4a3ad20cc Driver core: codi... |
80 81 82 |
* platform_get_irq - get an IRQ for a device * @dev: platform device * @num: IRQ number index |
1da177e4c Linux-2.6.12-rc2 |
83 84 85 |
*/ int platform_get_irq(struct platform_device *dev, unsigned int num) { |
5cf8f7db8 sparc: Add sparc ... |
86 87 88 89 90 91 |
#ifdef CONFIG_SPARC /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ if (!dev || num >= dev->archdata.num_irqs) return -ENXIO; return dev->archdata.irqs[num]; #else |
9ec36cafe of/irq: do irq re... |
92 |
struct resource *r; |
aff008ad8 platform_get_irq:... |
93 94 95 96 |
if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { int ret; ret = of_irq_get(dev->dev.of_node, num); |
e330b9a6b platform: don't r... |
97 |
if (ret > 0 || ret == -EPROBE_DEFER) |
aff008ad8 platform_get_irq:... |
98 99 |
return ret; } |
9ec36cafe of/irq: do irq re... |
100 101 |
r = platform_get_resource(dev, IORESOURCE_IRQ, num); |
7085a7401 drivers: platform... |
102 103 104 105 106 107 |
/* * The resources may pass trigger flags to the irqs that need * to be set up. It so happens that the trigger flags for * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER* * settings. */ |
60ca5e0d2 driver-core: plat... |
108 109 110 111 112 113 114 115 |
if (r && r->flags & IORESOURCE_BITS) { struct irq_data *irqd; irqd = irq_get_irq_data(r->start); if (!irqd) return -ENXIO; irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); } |
1da177e4c Linux-2.6.12-rc2 |
116 |
|
305b3228f [PATCH] driver co... |
117 |
return r ? r->start : -ENXIO; |
5cf8f7db8 sparc: Add sparc ... |
118 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
119 |
} |
a96b20420 [PATCH] Driver Co... |
120 |
EXPORT_SYMBOL_GPL(platform_get_irq); |
1da177e4c Linux-2.6.12-rc2 |
121 122 |
/** |
4b83555d5 driver-core: plat... |
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
* platform_irq_count - Count the number of IRQs a platform device uses * @dev: platform device * * Return: Number of IRQs a platform device uses or EPROBE_DEFER */ int platform_irq_count(struct platform_device *dev) { int ret, nr = 0; while ((ret = platform_get_irq(dev, nr)) >= 0) nr++; if (ret == -EPROBE_DEFER) return ret; return nr; } EXPORT_SYMBOL_GPL(platform_irq_count); /** |
4a3ad20cc Driver core: codi... |
143 144 145 146 |
* platform_get_resource_byname - get a resource for a device by name * @dev: platform device * @type: resource type * @name: resource name |
1da177e4c Linux-2.6.12-rc2 |
147 |
*/ |
4a3ad20cc Driver core: codi... |
148 |
struct resource *platform_get_resource_byname(struct platform_device *dev, |
c0afe7ba5 driver core: Cons... |
149 150 |
unsigned int type, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
151 152 153 154 155 |
{ int i; for (i = 0; i < dev->num_resources; i++) { struct resource *r = &dev->resource[i]; |
1b8cb9290 driver core: Chec... |
156 157 |
if (unlikely(!r->name)) continue; |
c9f66169f resource: add res... |
158 159 |
if (type == resource_type(r) && !strcmp(r->name, name)) return r; |
1da177e4c Linux-2.6.12-rc2 |
160 161 162 |
} return NULL; } |
a96b20420 [PATCH] Driver Co... |
163 |
EXPORT_SYMBOL_GPL(platform_get_resource_byname); |
1da177e4c Linux-2.6.12-rc2 |
164 165 |
/** |
d6ff85513 driver: platform:... |
166 |
* platform_get_irq_byname - get an IRQ for a device by name |
4a3ad20cc Driver core: codi... |
167 168 |
* @dev: platform device * @name: IRQ name |
1da177e4c Linux-2.6.12-rc2 |
169 |
*/ |
c0afe7ba5 driver core: Cons... |
170 |
int platform_get_irq_byname(struct platform_device *dev, const char *name) |
1da177e4c Linux-2.6.12-rc2 |
171 |
{ |
ad69674e7 of/irq: do irq re... |
172 |
struct resource *r; |
aff008ad8 platform_get_irq:... |
173 174 175 176 |
if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { int ret; ret = of_irq_get_byname(dev->dev.of_node, name); |
e330b9a6b platform: don't r... |
177 |
if (ret > 0 || ret == -EPROBE_DEFER) |
aff008ad8 platform_get_irq:... |
178 179 |
return ret; } |
1da177e4c Linux-2.6.12-rc2 |
180 |
|
ad69674e7 of/irq: do irq re... |
181 |
r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); |
305b3228f [PATCH] driver co... |
182 |
return r ? r->start : -ENXIO; |
1da177e4c Linux-2.6.12-rc2 |
183 |
} |
a96b20420 [PATCH] Driver Co... |
184 |
EXPORT_SYMBOL_GPL(platform_get_irq_byname); |
1da177e4c Linux-2.6.12-rc2 |
185 186 |
/** |
4a3ad20cc Driver core: codi... |
187 188 189 |
* platform_add_devices - add a numbers of platform devices * @devs: array of platform devices to add * @num: number of platform devices in array |
1da177e4c Linux-2.6.12-rc2 |
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
*/ int platform_add_devices(struct platform_device **devs, int num) { int i, ret = 0; for (i = 0; i < num; i++) { ret = platform_device_register(devs[i]); if (ret) { while (--i >= 0) platform_device_unregister(devs[i]); break; } } return ret; } |
a96b20420 [PATCH] Driver Co... |
206 |
EXPORT_SYMBOL_GPL(platform_add_devices); |
1da177e4c Linux-2.6.12-rc2 |
207 |
|
37c12e749 [DRIVER MODEL] Im... |
208 209 |
struct platform_object { struct platform_device pdev; |
1cec24c59 driver core/platf... |
210 |
char name[]; |
37c12e749 [DRIVER MODEL] Im... |
211 |
}; |
1da177e4c Linux-2.6.12-rc2 |
212 |
/** |
3c31f07ad Driver core: Fix ... |
213 |
* platform_device_put - destroy a platform device |
4a3ad20cc Driver core: codi... |
214 |
* @pdev: platform device to free |
37c12e749 [DRIVER MODEL] Im... |
215 |
* |
4a3ad20cc Driver core: codi... |
216 217 |
* Free all memory associated with a platform device. This function must * _only_ be externally called in error cases. All other usage is a bug. |
37c12e749 [DRIVER MODEL] Im... |
218 219 220 221 222 223 224 225 226 227 |
*/ void platform_device_put(struct platform_device *pdev) { if (pdev) put_device(&pdev->dev); } EXPORT_SYMBOL_GPL(platform_device_put); static void platform_device_release(struct device *dev) { |
4a3ad20cc Driver core: codi... |
228 229 |
struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev); |
37c12e749 [DRIVER MODEL] Im... |
230 |
|
7096d0422 of/device: Rework... |
231 |
of_device_node_put(&pa->pdev.dev); |
37c12e749 [DRIVER MODEL] Im... |
232 |
kfree(pa->pdev.dev.platform_data); |
e710d7d5a mfd: Fetch cell p... |
233 |
kfree(pa->pdev.mfd_cell); |
37c12e749 [DRIVER MODEL] Im... |
234 |
kfree(pa->pdev.resource); |
3d713e0e3 driver core: plat... |
235 |
kfree(pa->pdev.driver_override); |
37c12e749 [DRIVER MODEL] Im... |
236 237 238 239 |
kfree(pa); } /** |
3c31f07ad Driver core: Fix ... |
240 |
* platform_device_alloc - create a platform device |
4a3ad20cc Driver core: codi... |
241 242 |
* @name: base name of the device we're adding * @id: instance id |
37c12e749 [DRIVER MODEL] Im... |
243 |
* |
4a3ad20cc Driver core: codi... |
244 245 |
* Create a platform device object which can have other objects attached * to it, and which will have attached objects freed when it is released. |
37c12e749 [DRIVER MODEL] Im... |
246 |
*/ |
1359555eb Driver core: Make... |
247 |
struct platform_device *platform_device_alloc(const char *name, int id) |
37c12e749 [DRIVER MODEL] Im... |
248 249 |
{ struct platform_object *pa; |
1cec24c59 driver core/platf... |
250 |
pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL); |
37c12e749 [DRIVER MODEL] Im... |
251 252 253 254 255 256 |
if (pa) { strcpy(pa->name, name); pa->pdev.name = pa->name; pa->pdev.id = id; device_initialize(&pa->pdev.dev); pa->pdev.dev.release = platform_device_release; |
a77ce8167 driver core: Add ... |
257 |
arch_setup_pdev_archdata(&pa->pdev); |
37c12e749 [DRIVER MODEL] Im... |
258 |
} |
93ce3061b [PATCH] Driver Co... |
259 |
return pa ? &pa->pdev : NULL; |
37c12e749 [DRIVER MODEL] Im... |
260 261 262 263 |
} EXPORT_SYMBOL_GPL(platform_device_alloc); /** |
3c31f07ad Driver core: Fix ... |
264 |
* platform_device_add_resources - add resources to a platform device |
4a3ad20cc Driver core: codi... |
265 266 267 |
* @pdev: platform device allocated by platform_device_alloc to add resources to * @res: set of resources that needs to be allocated for the device * @num: number of resources |
37c12e749 [DRIVER MODEL] Im... |
268 |
* |
4a3ad20cc Driver core: codi... |
269 270 271 |
* Add a copy of the resources to the platform device. The memory * associated with the resources will be freed when the platform device is * released. |
37c12e749 [DRIVER MODEL] Im... |
272 |
*/ |
4a3ad20cc Driver core: codi... |
273 |
int platform_device_add_resources(struct platform_device *pdev, |
0b7f1a7ef platform: Make pl... |
274 |
const struct resource *res, unsigned int num) |
37c12e749 [DRIVER MODEL] Im... |
275 |
{ |
cea896238 driver core/platf... |
276 |
struct resource *r = NULL; |
37c12e749 [DRIVER MODEL] Im... |
277 |
|
cea896238 driver core/platf... |
278 279 280 281 |
if (res) { r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); if (!r) return -ENOMEM; |
37c12e749 [DRIVER MODEL] Im... |
282 |
} |
cea896238 driver core/platf... |
283 |
|
4a03d6f7c driver core/platf... |
284 |
kfree(pdev->resource); |
cea896238 driver core/platf... |
285 286 287 |
pdev->resource = r; pdev->num_resources = num; return 0; |
37c12e749 [DRIVER MODEL] Im... |
288 289 290 291 |
} EXPORT_SYMBOL_GPL(platform_device_add_resources); /** |
3c31f07ad Driver core: Fix ... |
292 |
* platform_device_add_data - add platform-specific data to a platform device |
4a3ad20cc Driver core: codi... |
293 294 295 |
* @pdev: platform device allocated by platform_device_alloc to add resources to * @data: platform specific data for this platform device * @size: size of platform specific data |
37c12e749 [DRIVER MODEL] Im... |
296 |
* |
4a3ad20cc Driver core: codi... |
297 298 299 |
* Add a copy of platform specific data to the platform device's * platform_data pointer. The memory associated with the platform data * will be freed when the platform device is released. |
37c12e749 [DRIVER MODEL] Im... |
300 |
*/ |
4a3ad20cc Driver core: codi... |
301 302 |
int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) |
37c12e749 [DRIVER MODEL] Im... |
303 |
{ |
27a33f9e8 driver core/platf... |
304 |
void *d = NULL; |
5cfc64ceb base/platform: Sa... |
305 |
|
27a33f9e8 driver core/platf... |
306 307 308 309 |
if (data) { d = kmemdup(data, size, GFP_KERNEL); if (!d) return -ENOMEM; |
37c12e749 [DRIVER MODEL] Im... |
310 |
} |
27a33f9e8 driver core/platf... |
311 |
|
251e031d1 driver core/platf... |
312 |
kfree(pdev->dev.platform_data); |
27a33f9e8 driver core/platf... |
313 314 |
pdev->dev.platform_data = d; return 0; |
37c12e749 [DRIVER MODEL] Im... |
315 316 317 318 |
} EXPORT_SYMBOL_GPL(platform_device_add_data); /** |
00bbc1d8e driver core: plat... |
319 320 |
* platform_device_add_properties - add built-in properties to a platform device * @pdev: platform device to add properties to |
f4d052660 device property: ... |
321 |
* @properties: null terminated array of properties to add |
00bbc1d8e driver core: plat... |
322 |
* |
f4d052660 device property: ... |
323 324 325 |
* The function will take deep copy of @properties and attach the copy to the * platform device. The memory associated with properties will be freed when the * platform device is released. |
00bbc1d8e driver core: plat... |
326 327 |
*/ int platform_device_add_properties(struct platform_device *pdev, |
f4d052660 device property: ... |
328 |
struct property_entry *properties) |
00bbc1d8e driver core: plat... |
329 |
{ |
f4d052660 device property: ... |
330 |
return device_add_properties(&pdev->dev, properties); |
00bbc1d8e driver core: plat... |
331 332 333 334 |
} EXPORT_SYMBOL_GPL(platform_device_add_properties); /** |
4a3ad20cc Driver core: codi... |
335 336 |
* platform_device_add - add a platform device to device hierarchy * @pdev: platform device we're adding |
1da177e4c Linux-2.6.12-rc2 |
337 |
* |
4a3ad20cc Driver core: codi... |
338 339 |
* This is part 2 of platform_device_register(), though may be called * separately _iff_ pdev was allocated by platform_device_alloc(). |
1da177e4c Linux-2.6.12-rc2 |
340 |
*/ |
37c12e749 [DRIVER MODEL] Im... |
341 |
int platform_device_add(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
342 |
{ |
689ae231a platform: Add sup... |
343 |
int i, ret; |
1da177e4c Linux-2.6.12-rc2 |
344 345 346 347 348 349 350 351 |
if (!pdev) return -EINVAL; if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; |
689ae231a platform: Add sup... |
352 353 |
switch (pdev->id) { default: |
1e0b2cf93 driver core: stru... |
354 |
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); |
689ae231a platform: Add sup... |
355 356 |
break; case PLATFORM_DEVID_NONE: |
acc0e90fb driver core: fix ... |
357 |
dev_set_name(&pdev->dev, "%s", pdev->name); |
689ae231a platform: Add sup... |
358 359 360 361 362 363 364 365 366 |
break; case PLATFORM_DEVID_AUTO: /* * Automatically allocated device ID. We mark it as such so * that we remember it must be freed, and we append a suffix * to avoid namespace collision with explicit IDs. */ ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); if (ret < 0) |
5da7f7099 Revert "base/plat... |
367 |
goto err_out; |
689ae231a platform: Add sup... |
368 369 370 371 372 |
pdev->id = ret; pdev->id_auto = true; dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); break; } |
1da177e4c Linux-2.6.12-rc2 |
373 374 |
for (i = 0; i < pdev->num_resources; i++) { |
5da7f7099 Revert "base/plat... |
375 |
struct resource *p, *r = &pdev->resource[i]; |
1da177e4c Linux-2.6.12-rc2 |
376 377 |
if (r->name == NULL) |
1e0b2cf93 driver core: stru... |
378 |
r->name = dev_name(&pdev->dev); |
1da177e4c Linux-2.6.12-rc2 |
379 380 381 |
p = r->parent; if (!p) { |
0e6c861f7 Revert "base/plat... |
382 |
if (resource_type(r) == IORESOURCE_MEM) |
1da177e4c Linux-2.6.12-rc2 |
383 |
p = &iomem_resource; |
0e6c861f7 Revert "base/plat... |
384 |
else if (resource_type(r) == IORESOURCE_IO) |
1da177e4c Linux-2.6.12-rc2 |
385 386 |
p = &ioport_resource; } |
0e6c861f7 Revert "base/plat... |
387 |
if (p && insert_resource(p, r)) { |
5da7f7099 Revert "base/plat... |
388 389 390 391 392 |
dev_err(&pdev->dev, "failed to claim resource %d ", i); ret = -EBUSY; goto failed; } |
1da177e4c Linux-2.6.12-rc2 |
393 394 395 396 |
} pr_debug("Registering platform device '%s'. Parent at %s ", |
1e0b2cf93 driver core: stru... |
397 |
dev_name(&pdev->dev), dev_name(pdev->dev.parent)); |
1da177e4c Linux-2.6.12-rc2 |
398 |
|
e39155322 [PATCH] Driver Co... |
399 |
ret = device_add(&pdev->dev); |
8b2dcebae Revert "base/plat... |
400 401 |
if (ret == 0) return ret; |
5da7f7099 Revert "base/plat... |
402 |
failed: |
8b2dcebae Revert "base/plat... |
403 404 405 406 407 408 409 |
if (pdev->id_auto) { ida_simple_remove(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; } while (--i >= 0) { struct resource *r = &pdev->resource[i]; |
7f5dcaf1f drivercore: Fix u... |
410 |
if (r->parent) |
8b2dcebae Revert "base/plat... |
411 412 |
release_resource(r); } |
c9f66169f resource: add res... |
413 |
|
5da7f7099 Revert "base/plat... |
414 |
err_out: |
1da177e4c Linux-2.6.12-rc2 |
415 416 |
return ret; } |
37c12e749 [DRIVER MODEL] Im... |
417 418 419 |
EXPORT_SYMBOL_GPL(platform_device_add); /** |
4a3ad20cc Driver core: codi... |
420 421 |
* platform_device_del - remove a platform-level device * @pdev: platform device we're removing |
1da177e4c Linux-2.6.12-rc2 |
422 |
* |
4a3ad20cc Driver core: codi... |
423 424 425 |
* Note that this function will also release all memory- and port-based * resources owned by the device (@dev->resource). This function must * _only_ be externally called in error cases. All other usage is a bug. |
1da177e4c Linux-2.6.12-rc2 |
426 |
*/ |
93ce3061b [PATCH] Driver Co... |
427 |
void platform_device_del(struct platform_device *pdev) |
1da177e4c Linux-2.6.12-rc2 |
428 |
{ |
8b2dcebae Revert "base/plat... |
429 |
int i; |
c9f66169f resource: add res... |
430 |
|
8b2dcebae Revert "base/plat... |
431 |
if (pdev) { |
c90aab9c9 platform driver: ... |
432 |
device_remove_properties(&pdev->dev); |
8b2dcebae Revert "base/plat... |
433 434 435 436 437 438 439 440 441 |
device_del(&pdev->dev); if (pdev->id_auto) { ida_simple_remove(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; } for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; |
7f5dcaf1f drivercore: Fix u... |
442 |
if (r->parent) |
8b2dcebae Revert "base/plat... |
443 444 445 |
release_resource(r); } } |
1da177e4c Linux-2.6.12-rc2 |
446 |
} |
93ce3061b [PATCH] Driver Co... |
447 448 449 |
EXPORT_SYMBOL_GPL(platform_device_del); /** |
4a3ad20cc Driver core: codi... |
450 451 |
* platform_device_register - add a platform-level device * @pdev: platform device we're adding |
93ce3061b [PATCH] Driver Co... |
452 |
*/ |
4a3ad20cc Driver core: codi... |
453 |
int platform_device_register(struct platform_device *pdev) |
93ce3061b [PATCH] Driver Co... |
454 455 |
{ device_initialize(&pdev->dev); |
a77ce8167 driver core: Add ... |
456 |
arch_setup_pdev_archdata(pdev); |
93ce3061b [PATCH] Driver Co... |
457 458 |
return platform_device_add(pdev); } |
a96b20420 [PATCH] Driver Co... |
459 |
EXPORT_SYMBOL_GPL(platform_device_register); |
93ce3061b [PATCH] Driver Co... |
460 461 |
/** |
4a3ad20cc Driver core: codi... |
462 463 |
* platform_device_unregister - unregister a platform-level device * @pdev: platform device we're unregistering |
93ce3061b [PATCH] Driver Co... |
464 |
* |
4a3ad20cc Driver core: codi... |
465 466 467 |
* Unregistration is done in 2 steps. First we release all resources * and remove it from the subsystem, then we drop reference count by * calling platform_device_put(). |
93ce3061b [PATCH] Driver Co... |
468 |
*/ |
4a3ad20cc Driver core: codi... |
469 |
void platform_device_unregister(struct platform_device *pdev) |
93ce3061b [PATCH] Driver Co... |
470 471 472 473 |
{ platform_device_del(pdev); platform_device_put(pdev); } |
a96b20420 [PATCH] Driver Co... |
474 |
EXPORT_SYMBOL_GPL(platform_device_unregister); |
1da177e4c Linux-2.6.12-rc2 |
475 |
|
1da177e4c Linux-2.6.12-rc2 |
476 |
/** |
01dcc60a7 new helper to cre... |
477 |
* platform_device_register_full - add a platform-level device with |
44f28bdea Driver core: redu... |
478 |
* resources and platform-specific data |
49a4ec188 fix hotplug for l... |
479 |
* |
01dcc60a7 new helper to cre... |
480 |
* @pdevinfo: data used to create device |
d8bf25408 platform: add new... |
481 |
* |
f0eae0ed3 driver-core: docu... |
482 |
* Returns &struct platform_device pointer on success, or ERR_PTR() on error. |
d8bf25408 platform: add new... |
483 |
*/ |
01dcc60a7 new helper to cre... |
484 |
struct platform_device *platform_device_register_full( |
5a3072be6 drivers_base: mak... |
485 |
const struct platform_device_info *pdevinfo) |
d8bf25408 platform: add new... |
486 |
{ |
44f28bdea Driver core: redu... |
487 |
int ret = -ENOMEM; |
d8bf25408 platform: add new... |
488 |
struct platform_device *pdev; |
d8bf25408 platform: add new... |
489 |
|
01dcc60a7 new helper to cre... |
490 |
pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); |
44f28bdea Driver core: redu... |
491 |
if (!pdev) |
01dcc60a7 new helper to cre... |
492 493 494 |
goto err_alloc; pdev->dev.parent = pdevinfo->parent; |
ce793486e driver core / ACP... |
495 |
pdev->dev.fwnode = pdevinfo->fwnode; |
01dcc60a7 new helper to cre... |
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 |
if (pdevinfo->dma_mask) { /* * This memory isn't freed when the device is put, * I don't have a nice idea for that though. Conceptually * dma_mask in struct device should not be a pointer. * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 */ pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); if (!pdev->dev.dma_mask) goto err; *pdev->dev.dma_mask = pdevinfo->dma_mask; pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; } |
d8bf25408 platform: add new... |
512 |
|
01dcc60a7 new helper to cre... |
513 514 |
ret = platform_device_add_resources(pdev, pdevinfo->res, pdevinfo->num_res); |
807508c8f base/platform: Si... |
515 516 |
if (ret) goto err; |
44f28bdea Driver core: redu... |
517 |
|
01dcc60a7 new helper to cre... |
518 519 |
ret = platform_device_add_data(pdev, pdevinfo->data, pdevinfo->size_data); |
807508c8f base/platform: Si... |
520 521 |
if (ret) goto err; |
d8bf25408 platform: add new... |
522 |
|
f4d052660 device property: ... |
523 524 525 |
if (pdevinfo->properties) { ret = platform_device_add_properties(pdev, pdevinfo->properties); |
00bbc1d8e driver core: plat... |
526 527 528 |
if (ret) goto err; } |
44f28bdea Driver core: redu... |
529 530 531 |
ret = platform_device_add(pdev); if (ret) { err: |
7b1998116 ACPI / driver cor... |
532 |
ACPI_COMPANION_SET(&pdev->dev, NULL); |
01dcc60a7 new helper to cre... |
533 534 535 |
kfree(pdev->dev.dma_mask); err_alloc: |
44f28bdea Driver core: redu... |
536 537 538 |
platform_device_put(pdev); return ERR_PTR(ret); } |
d8bf25408 platform: add new... |
539 540 |
return pdev; |
d8bf25408 platform: add new... |
541 |
} |
01dcc60a7 new helper to cre... |
542 |
EXPORT_SYMBOL_GPL(platform_device_register_full); |
d8bf25408 platform: add new... |
543 |
|
00d3dcdd9 [DRIVER MODEL] Ad... |
544 545 546 547 |
static int platform_drv_probe(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); |
94d76d5de platform / ACPI: ... |
548 |
int ret; |
00d3dcdd9 [DRIVER MODEL] Ad... |
549 |
|
86be408bf clk: Support for ... |
550 551 552 |
ret = of_clk_set_defaults(_dev->of_node, false); if (ret < 0) return ret; |
cb5184139 drivercore / plat... |
553 |
ret = dev_pm_domain_attach(_dev, true); |
25cad69f2 base/platform: Fi... |
554 555 556 557 558 559 560 561 562 |
if (ret != -EPROBE_DEFER) { if (drv->probe) { ret = drv->probe(dev); if (ret) dev_pm_domain_detach(_dev, true); } else { /* don't fail if just dev_pm_domain_attach failed */ ret = 0; } |
cb5184139 drivercore / plat... |
563 |
} |
94d76d5de platform / ACPI: ... |
564 |
|
3f9120b04 driver core: prev... |
565 566 567 568 569 |
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported "); ret = -ENXIO; } |
94d76d5de platform / ACPI: ... |
570 |
return ret; |
00d3dcdd9 [DRIVER MODEL] Ad... |
571 |
} |
c67334fbd Driver core: plat... |
572 573 574 575 |
static int platform_drv_probe_fail(struct device *_dev) { return -ENXIO; } |
00d3dcdd9 [DRIVER MODEL] Ad... |
576 577 578 579 |
static int platform_drv_remove(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); |
b8b2c7d84 base/platform: as... |
580 |
int ret = 0; |
00d3dcdd9 [DRIVER MODEL] Ad... |
581 |
|
b8b2c7d84 base/platform: as... |
582 583 |
if (drv->remove) ret = drv->remove(dev); |
cb5184139 drivercore / plat... |
584 |
dev_pm_domain_detach(_dev, true); |
94d76d5de platform / ACPI: ... |
585 586 |
return ret; |
00d3dcdd9 [DRIVER MODEL] Ad... |
587 588 589 590 591 592 |
} static void platform_drv_shutdown(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); |
b8b2c7d84 base/platform: as... |
593 594 |
if (drv->shutdown) drv->shutdown(dev); |
00d3dcdd9 [DRIVER MODEL] Ad... |
595 |
} |
00d3dcdd9 [DRIVER MODEL] Ad... |
596 |
/** |
9447057ea platform_device: ... |
597 |
* __platform_driver_register - register a driver for platform-level devices |
4a3ad20cc Driver core: codi... |
598 |
* @drv: platform driver structure |
08801f966 driver-core: fix ... |
599 |
* @owner: owning module/driver |
00d3dcdd9 [DRIVER MODEL] Ad... |
600 |
*/ |
9447057ea platform_device: ... |
601 602 |
int __platform_driver_register(struct platform_driver *drv, struct module *owner) |
00d3dcdd9 [DRIVER MODEL] Ad... |
603 |
{ |
9447057ea platform_device: ... |
604 |
drv->driver.owner = owner; |
00d3dcdd9 [DRIVER MODEL] Ad... |
605 |
drv->driver.bus = &platform_bus_type; |
b8b2c7d84 base/platform: as... |
606 607 608 |
drv->driver.probe = platform_drv_probe; drv->driver.remove = platform_drv_remove; drv->driver.shutdown = platform_drv_shutdown; |
783ea7d4e Driver Core: Rewo... |
609 |
|
00d3dcdd9 [DRIVER MODEL] Ad... |
610 611 |
return driver_register(&drv->driver); } |
9447057ea platform_device: ... |
612 |
EXPORT_SYMBOL_GPL(__platform_driver_register); |
00d3dcdd9 [DRIVER MODEL] Ad... |
613 614 |
/** |
3c31f07ad Driver core: Fix ... |
615 |
* platform_driver_unregister - unregister a driver for platform-level devices |
4a3ad20cc Driver core: codi... |
616 |
* @drv: platform driver structure |
00d3dcdd9 [DRIVER MODEL] Ad... |
617 618 619 620 621 622 |
*/ void platform_driver_unregister(struct platform_driver *drv) { driver_unregister(&drv->driver); } EXPORT_SYMBOL_GPL(platform_driver_unregister); |
c67334fbd Driver core: plat... |
623 |
/** |
c3b50dc21 core: platform: l... |
624 |
* __platform_driver_probe - register driver for non-hotpluggable device |
c67334fbd Driver core: plat... |
625 |
* @drv: platform driver structure |
3f9120b04 driver core: prev... |
626 |
* @probe: the driver probe routine, probably from an __init section |
c3b50dc21 core: platform: l... |
627 |
* @module: module which will be the owner of the driver |
c67334fbd Driver core: plat... |
628 629 630 631 632 633 634 635 636 637 |
* * Use this instead of platform_driver_register() when you know the device * is not hotpluggable and has already been registered, and you want to * remove its run-once probe() infrastructure from memory after the driver * has bound to the device. * * One typical use for this would be with drivers for controllers integrated * into system-on-chip processors, where the controller devices have been * configured as part of board setup. * |
3f9120b04 driver core: prev... |
638 |
* Note that this is incompatible with deferred probing. |
647c86d0a driver core: warn... |
639 |
* |
c67334fbd Driver core: plat... |
640 641 642 |
* Returns zero if the driver registered and bound to a device, else returns * a negative error code and with the driver not registered. */ |
c3b50dc21 core: platform: l... |
643 644 |
int __init_or_module __platform_driver_probe(struct platform_driver *drv, int (*probe)(struct platform_device *), struct module *module) |
c67334fbd Driver core: plat... |
645 646 |
{ int retval, code; |
5c36eb2a9 driver-core: plat... |
647 648 649 650 651 652 653 654 655 656 657 658 659 |
if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) { pr_err("%s: drivers registered with %s can not be probed asynchronously ", drv->driver.name, __func__); return -EINVAL; } /* * We have to run our probes synchronously because we check if * we find any devices to bind to and exit with error if there * are any. */ drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS; |
3f9120b04 driver core: prev... |
660 661 662 663 664 |
/* * Prevent driver from requesting probe deferral to avoid further * futile probe attempts. */ drv->prevent_deferred_probe = true; |
1a6f2a751 Driver core: allo... |
665 666 |
/* make sure driver won't have bind/unbind attributes */ drv->driver.suppress_bind_attrs = true; |
c67334fbd Driver core: plat... |
667 668 |
/* temporary section violation during probe() */ drv->probe = probe; |
c3b50dc21 core: platform: l... |
669 |
retval = code = __platform_driver_register(drv, module); |
c67334fbd Driver core: plat... |
670 |
|
1a6f2a751 Driver core: allo... |
671 672 |
/* * Fixup that section violation, being paranoid about code scanning |
c67334fbd Driver core: plat... |
673 674 675 676 |
* the list of drivers in order to probe new devices. Check to see * if the probe was successful, and make sure any forced probes of * new devices fail. */ |
d79d32440 driver core: plat... |
677 |
spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); |
c67334fbd Driver core: plat... |
678 |
drv->probe = NULL; |
e5dd12784 Driver core: move... |
679 |
if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) |
c67334fbd Driver core: plat... |
680 681 |
retval = -ENODEV; drv->driver.probe = platform_drv_probe_fail; |
d79d32440 driver core: plat... |
682 |
spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); |
c67334fbd Driver core: plat... |
683 684 685 686 687 |
if (code != retval) platform_driver_unregister(drv); return retval; } |
c3b50dc21 core: platform: l... |
688 |
EXPORT_SYMBOL_GPL(__platform_driver_probe); |
1da177e4c Linux-2.6.12-rc2 |
689 |
|
ecdf6ceb8 Driver core: add ... |
690 |
/** |
291f653a1 core: platform: l... |
691 |
* __platform_create_bundle - register driver and create corresponding device |
ecdf6ceb8 Driver core: add ... |
692 693 694 695 696 697 |
* @driver: platform driver structure * @probe: the driver probe routine, probably from an __init section * @res: set of resources that needs to be allocated for the device * @n_res: number of resources * @data: platform specific data for this platform device * @size: size of platform specific data |
291f653a1 core: platform: l... |
698 |
* @module: module which will be the owner of the driver |
ecdf6ceb8 Driver core: add ... |
699 700 701 |
* * Use this in legacy-style modules that probe hardware directly and * register a single platform device and corresponding platform driver. |
f0eae0ed3 driver-core: docu... |
702 703 |
* * Returns &struct platform_device pointer on success, or ERR_PTR() on error. |
ecdf6ceb8 Driver core: add ... |
704 |
*/ |
291f653a1 core: platform: l... |
705 |
struct platform_device * __init_or_module __platform_create_bundle( |
ecdf6ceb8 Driver core: add ... |
706 707 708 |
struct platform_driver *driver, int (*probe)(struct platform_device *), struct resource *res, unsigned int n_res, |
291f653a1 core: platform: l... |
709 |
const void *data, size_t size, struct module *module) |
ecdf6ceb8 Driver core: add ... |
710 711 712 713 714 715 716 717 718 |
{ struct platform_device *pdev; int error; pdev = platform_device_alloc(driver->driver.name, -1); if (!pdev) { error = -ENOMEM; goto err_out; } |
807508c8f base/platform: Si... |
719 720 721 |
error = platform_device_add_resources(pdev, res, n_res); if (error) goto err_pdev_put; |
ecdf6ceb8 Driver core: add ... |
722 |
|
807508c8f base/platform: Si... |
723 724 725 |
error = platform_device_add_data(pdev, data, size); if (error) goto err_pdev_put; |
ecdf6ceb8 Driver core: add ... |
726 727 728 729 |
error = platform_device_add(pdev); if (error) goto err_pdev_put; |
291f653a1 core: platform: l... |
730 |
error = __platform_driver_probe(driver, probe, module); |
ecdf6ceb8 Driver core: add ... |
731 732 733 734 735 736 737 738 739 740 741 742 |
if (error) goto err_pdev_del; return pdev; err_pdev_del: platform_device_del(pdev); err_pdev_put: platform_device_put(pdev); err_out: return ERR_PTR(error); } |
291f653a1 core: platform: l... |
743 |
EXPORT_SYMBOL_GPL(__platform_create_bundle); |
ecdf6ceb8 Driver core: add ... |
744 |
|
dbe2256dd driver-core: plat... |
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 |
/** * __platform_register_drivers - register an array of platform drivers * @drivers: an array of drivers to register * @count: the number of drivers to register * @owner: module owning the drivers * * Registers platform drivers specified by an array. On failure to register a * driver, all previously registered drivers will be unregistered. Callers of * this API should use platform_unregister_drivers() to unregister drivers in * the reverse order. * * Returns: 0 on success or a negative error code on failure. */ int __platform_register_drivers(struct platform_driver * const *drivers, unsigned int count, struct module *owner) { unsigned int i; int err; for (i = 0; i < count; i++) { pr_debug("registering platform driver %ps ", drivers[i]); err = __platform_driver_register(drivers[i], owner); if (err < 0) { pr_err("failed to register platform driver %ps: %d ", drivers[i], err); goto error; } } return 0; error: while (i--) { pr_debug("unregistering platform driver %ps ", drivers[i]); platform_driver_unregister(drivers[i]); } return err; } EXPORT_SYMBOL_GPL(__platform_register_drivers); /** * platform_unregister_drivers - unregister an array of platform drivers * @drivers: an array of drivers to unregister * @count: the number of drivers to unregister * * Unegisters platform drivers specified by an array. This is typically used * to complement an earlier call to platform_register_drivers(). Drivers are * unregistered in the reverse order in which they were registered. */ void platform_unregister_drivers(struct platform_driver * const *drivers, unsigned int count) { while (count--) { pr_debug("unregistering platform driver %ps ", drivers[count]); platform_driver_unregister(drivers[count]); } } EXPORT_SYMBOL_GPL(platform_unregister_drivers); |
a0245f7ad [PATCH] platform_... |
809 810 811 812 813 814 |
/* modalias support enables more hands-off userspace setup: * (a) environment variable lets new-style hotplug events work once system is * fully running: "modprobe $MODALIAS" * (b) sysfs attribute lets new-style coldplug recover from hotplug events * mishandled before system is fully running: "modprobe $(cat modalias)" */ |
4a3ad20cc Driver core: codi... |
815 816 |
static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) |
a0245f7ad [PATCH] platform_... |
817 818 |
{ struct platform_device *pdev = to_platform_device(dev); |
8c4ff6d00 ACPI: fix module ... |
819 |
int len; |
b9f73067f platform: introdu... |
820 821 822 |
len = of_device_get_modalias(dev, buf, PAGE_SIZE -1); if (len != -ENODEV) return len; |
8c4ff6d00 ACPI: fix module ... |
823 824 825 826 827 828 |
len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); if (len != -ENODEV) return len; len = snprintf(buf, PAGE_SIZE, "platform:%s ", pdev->name); |
a0245f7ad [PATCH] platform_... |
829 830 831 |
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } |
d06262e58 driver-core: plat... |
832 |
static DEVICE_ATTR_RO(modalias); |
a0245f7ad [PATCH] platform_... |
833 |
|
3d713e0e3 driver core: plat... |
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 |
static ssize_t driver_override_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); char *driver_override, *old = pdev->driver_override, *cp; if (count > PATH_MAX) return -EINVAL; driver_override = kstrndup(buf, count, GFP_KERNEL); if (!driver_override) return -ENOMEM; cp = strchr(driver_override, ' '); if (cp) *cp = '\0'; if (strlen(driver_override)) { pdev->driver_override = driver_override; } else { kfree(driver_override); pdev->driver_override = NULL; } kfree(old); return count; } static ssize_t driver_override_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); return sprintf(buf, "%s ", pdev->driver_override); } static DEVICE_ATTR_RW(driver_override); |
d06262e58 driver-core: plat... |
874 875 |
static struct attribute *platform_dev_attrs[] = { &dev_attr_modalias.attr, |
3d713e0e3 driver core: plat... |
876 |
&dev_attr_driver_override.attr, |
d06262e58 driver-core: plat... |
877 |
NULL, |
a0245f7ad [PATCH] platform_... |
878 |
}; |
d06262e58 driver-core: plat... |
879 |
ATTRIBUTE_GROUPS(platform_dev); |
a0245f7ad [PATCH] platform_... |
880 |
|
7eff2e7a8 Driver core: chan... |
881 |
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) |
a0245f7ad [PATCH] platform_... |
882 883 |
{ struct platform_device *pdev = to_platform_device(dev); |
eca393016 of: Merge of_plat... |
884 885 886 |
int rc; /* Some devices have extra OF data and an OF-style MODALIAS */ |
0258e182e driver core: plat... |
887 |
rc = of_device_uevent_modalias(dev, env); |
eca393016 of: Merge of_plat... |
888 889 |
if (rc != -ENODEV) return rc; |
a0245f7ad [PATCH] platform_... |
890 |
|
8c4ff6d00 ACPI: fix module ... |
891 892 893 |
rc = acpi_device_uevent_modalias(dev, env); if (rc != -ENODEV) return rc; |
57fee4a58 platform: introdu... |
894 |
add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, |
0a26813c9 drivers_base: pla... |
895 |
pdev->name); |
a0245f7ad [PATCH] platform_... |
896 897 |
return 0; } |
57fee4a58 platform: introdu... |
898 |
static const struct platform_device_id *platform_match_id( |
831fad2f7 Driver core: make... |
899 |
const struct platform_device_id *id, |
57fee4a58 platform: introdu... |
900 901 902 903 904 905 906 907 908 909 910 |
struct platform_device *pdev) { while (id->name[0]) { if (strcmp(pdev->name, id->name) == 0) { pdev->id_entry = id; return id; } id++; } return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
911 |
/** |
4a3ad20cc Driver core: codi... |
912 913 914 |
* platform_match - bind platform device to platform driver. * @dev: device. * @drv: driver. |
1da177e4c Linux-2.6.12-rc2 |
915 |
* |
4a3ad20cc Driver core: codi... |
916 917 918 919 920 921 922 |
* Platform device IDs are assumed to be encoded like this: * "<name><instance>", where <name> is a short description of the type of * device, like "pci" or "floppy", and <instance> is the enumerated * instance of the device, like '0' or '42'. Driver IDs are simply * "<name>". So, extract the <name> from the platform_device structure, * and compare it against the name of the driver. Return whether they match * or not. |
1da177e4c Linux-2.6.12-rc2 |
923 |
*/ |
4a3ad20cc Driver core: codi... |
924 |
static int platform_match(struct device *dev, struct device_driver *drv) |
1da177e4c Linux-2.6.12-rc2 |
925 |
{ |
71b3e0c1a platform: make be... |
926 |
struct platform_device *pdev = to_platform_device(dev); |
57fee4a58 platform: introdu... |
927 |
struct platform_driver *pdrv = to_platform_driver(drv); |
3d713e0e3 driver core: plat... |
928 929 930 |
/* When driver_override is set, only bind to the matching driver */ if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name); |
05212157e drivercore/of: Ad... |
931 932 933 |
/* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; |
91e568780 ACPI: Add support... |
934 935 936 |
/* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; |
05212157e drivercore/of: Ad... |
937 |
/* Then try to match against the id table */ |
57fee4a58 platform: introdu... |
938 939 |
if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; |
1da177e4c Linux-2.6.12-rc2 |
940 |
|
57fee4a58 platform: introdu... |
941 |
/* fall-back to driver name match */ |
1e0b2cf93 driver core: stru... |
942 |
return (strcmp(pdev->name, drv->name) == 0); |
1da177e4c Linux-2.6.12-rc2 |
943 |
} |
25e18499e Implement new sus... |
944 945 946 |
#ifdef CONFIG_PM_SLEEP static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) |
1da177e4c Linux-2.6.12-rc2 |
947 |
{ |
783ea7d4e Driver Core: Rewo... |
948 949 |
struct platform_driver *pdrv = to_platform_driver(dev->driver); struct platform_device *pdev = to_platform_device(dev); |
1da177e4c Linux-2.6.12-rc2 |
950 |
int ret = 0; |
783ea7d4e Driver Core: Rewo... |
951 952 |
if (dev->driver && pdrv->suspend) ret = pdrv->suspend(pdev, mesg); |
386415d88 PM: platform_bus ... |
953 954 955 |
return ret; } |
25e18499e Implement new sus... |
956 |
static int platform_legacy_resume(struct device *dev) |
1da177e4c Linux-2.6.12-rc2 |
957 |
{ |
783ea7d4e Driver Core: Rewo... |
958 959 |
struct platform_driver *pdrv = to_platform_driver(dev->driver); struct platform_device *pdev = to_platform_device(dev); |
1da177e4c Linux-2.6.12-rc2 |
960 |
int ret = 0; |
783ea7d4e Driver Core: Rewo... |
961 962 |
if (dev->driver && pdrv->resume) ret = pdrv->resume(pdev); |
9480e307c [PATCH] DRIVER MO... |
963 |
|
1da177e4c Linux-2.6.12-rc2 |
964 965 |
return ret; } |
69c9dd1ec PM: Export platfo... |
966 |
#endif /* CONFIG_PM_SLEEP */ |
9d7302299 PM: Run-time PM p... |
967 |
|
25e18499e Implement new sus... |
968 |
#ifdef CONFIG_SUSPEND |
69c9dd1ec PM: Export platfo... |
969 |
int platform_pm_suspend(struct device *dev) |
25e18499e Implement new sus... |
970 971 972 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
973 974 975 976 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
977 978 979 980 981 982 983 984 |
if (drv->pm->suspend) ret = drv->pm->suspend(dev); } else { ret = platform_legacy_suspend(dev, PMSG_SUSPEND); } return ret; } |
69c9dd1ec PM: Export platfo... |
985 |
int platform_pm_resume(struct device *dev) |
25e18499e Implement new sus... |
986 987 988 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
989 990 991 992 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
993 994 995 996 997 998 999 1000 |
if (drv->pm->resume) ret = drv->pm->resume(dev); } else { ret = platform_legacy_resume(dev); } return ret; } |
69c9dd1ec PM: Export platfo... |
1001 |
#endif /* CONFIG_SUSPEND */ |
25e18499e Implement new sus... |
1002 |
|
1f112cee0 PM / Hibernate: I... |
1003 |
#ifdef CONFIG_HIBERNATE_CALLBACKS |
25e18499e Implement new sus... |
1004 |
|
69c9dd1ec PM: Export platfo... |
1005 |
int platform_pm_freeze(struct device *dev) |
25e18499e Implement new sus... |
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 |
{ struct device_driver *drv = dev->driver; int ret = 0; if (!drv) return 0; if (drv->pm) { if (drv->pm->freeze) ret = drv->pm->freeze(dev); } else { ret = platform_legacy_suspend(dev, PMSG_FREEZE); } return ret; } |
69c9dd1ec PM: Export platfo... |
1022 |
int platform_pm_thaw(struct device *dev) |
25e18499e Implement new sus... |
1023 1024 1025 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
1026 1027 1028 1029 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
1030 1031 1032 1033 1034 1035 1036 1037 |
if (drv->pm->thaw) ret = drv->pm->thaw(dev); } else { ret = platform_legacy_resume(dev); } return ret; } |
69c9dd1ec PM: Export platfo... |
1038 |
int platform_pm_poweroff(struct device *dev) |
25e18499e Implement new sus... |
1039 1040 1041 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
1042 1043 1044 1045 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
1046 1047 1048 1049 1050 1051 1052 1053 |
if (drv->pm->poweroff) ret = drv->pm->poweroff(dev); } else { ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); } return ret; } |
69c9dd1ec PM: Export platfo... |
1054 |
int platform_pm_restore(struct device *dev) |
25e18499e Implement new sus... |
1055 1056 1057 |
{ struct device_driver *drv = dev->driver; int ret = 0; |
adf094931 PM: Simplify the ... |
1058 1059 1060 1061 |
if (!drv) return 0; if (drv->pm) { |
25e18499e Implement new sus... |
1062 1063 1064 1065 1066 1067 1068 1069 |
if (drv->pm->restore) ret = drv->pm->restore(dev); } else { ret = platform_legacy_resume(dev); } return ret; } |
69c9dd1ec PM: Export platfo... |
1070 |
#endif /* CONFIG_HIBERNATE_CALLBACKS */ |
25e18499e Implement new sus... |
1071 |
|
d9ab77161 Driver Core: Make... |
1072 |
static const struct dev_pm_ops platform_dev_pm_ops = { |
8b313a38e PM / Platform: Us... |
1073 1074 |
.runtime_suspend = pm_generic_runtime_suspend, .runtime_resume = pm_generic_runtime_resume, |
69c9dd1ec PM: Export platfo... |
1075 |
USE_PLATFORM_PM_SLEEP_OPS |
25e18499e Implement new sus... |
1076 |
}; |
1da177e4c Linux-2.6.12-rc2 |
1077 1078 |
struct bus_type platform_bus_type = { .name = "platform", |
d06262e58 driver-core: plat... |
1079 |
.dev_groups = platform_dev_groups, |
1da177e4c Linux-2.6.12-rc2 |
1080 |
.match = platform_match, |
a0245f7ad [PATCH] platform_... |
1081 |
.uevent = platform_uevent, |
9d7302299 PM: Run-time PM p... |
1082 |
.pm = &platform_dev_pm_ops, |
1da177e4c Linux-2.6.12-rc2 |
1083 |
}; |
a96b20420 [PATCH] Driver Co... |
1084 |
EXPORT_SYMBOL_GPL(platform_bus_type); |
1da177e4c Linux-2.6.12-rc2 |
1085 1086 1087 |
int __init platform_bus_init(void) { |
fbfb14455 driver core fixes... |
1088 |
int error; |
13977091a Driver Core: earl... |
1089 |
early_platform_cleanup(); |
fbfb14455 driver core fixes... |
1090 1091 1092 1093 1094 1095 |
error = device_register(&platform_bus); if (error) return error; error = bus_register(&platform_bus_type); if (error) device_unregister(&platform_bus); |
801d728c1 of/reconfig: Add ... |
1096 |
of_platform_register_reconfig_notifier(); |
fbfb14455 driver core fixes... |
1097 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 |
} #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK u64 dma_get_required_mask(struct device *dev) { u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); u64 mask; if (!high_totalram) { /* convert to mask just covering totalram */ low_totalram = (1 << (fls(low_totalram) - 1)); low_totalram += low_totalram - 1; mask = low_totalram; } else { high_totalram = (1 << (fls(high_totalram) - 1)); high_totalram += high_totalram - 1; mask = (((u64)high_totalram) << 32) + 0xffffffff; } |
e88a0c2ca drivers: fix dma_... |
1117 |
return mask; |
1da177e4c Linux-2.6.12-rc2 |
1118 1119 1120 |
} EXPORT_SYMBOL_GPL(dma_get_required_mask); #endif |
13977091a Driver Core: earl... |
1121 1122 1123 1124 1125 |
static __initdata LIST_HEAD(early_platform_driver_list); static __initdata LIST_HEAD(early_platform_device_list); /** |
4d26e139f Driver core: Earl... |
1126 |
* early_platform_driver_register - register early platform driver |
d86c1302c Driver core: plat... |
1127 |
* @epdrv: early_platform driver structure |
13977091a Driver Core: earl... |
1128 |
* @buf: string passed from early_param() |
4d26e139f Driver core: Earl... |
1129 1130 |
* * Helper function for early_platform_init() / early_platform_init_buffer() |
13977091a Driver Core: earl... |
1131 1132 1133 1134 |
*/ int __init early_platform_driver_register(struct early_platform_driver *epdrv, char *buf) { |
c60e0504c Driver Core: Earl... |
1135 |
char *tmp; |
13977091a Driver Core: earl... |
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 |
int n; /* Simply add the driver to the end of the global list. * Drivers will by default be put on the list in compiled-in order. */ if (!epdrv->list.next) { INIT_LIST_HEAD(&epdrv->list); list_add_tail(&epdrv->list, &early_platform_driver_list); } /* If the user has specified device then make sure the driver * gets prioritized. The driver of the last device specified on * command line will be put first on the list. */ n = strlen(epdrv->pdrv->driver.name); if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { list_move(&epdrv->list, &early_platform_driver_list); |
c60e0504c Driver Core: Earl... |
1153 1154 |
/* Allow passing parameters after device name */ if (buf[n] == '\0' || buf[n] == ',') |
13977091a Driver Core: earl... |
1155 |
epdrv->requested_id = -1; |
c60e0504c Driver Core: Earl... |
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 |
else { epdrv->requested_id = simple_strtoul(&buf[n + 1], &tmp, 10); if (buf[n] != '.' || (tmp == &buf[n + 1])) { epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; n = 0; } else n += strcspn(&buf[n + 1], ",") + 1; } if (buf[n] == ',') n++; if (epdrv->bufsize) { memcpy(epdrv->buffer, &buf[n], min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); epdrv->buffer[epdrv->bufsize - 1] = '\0'; } |
13977091a Driver Core: earl... |
1175 1176 1177 1178 1179 1180 |
} return 0; } /** |
4d26e139f Driver core: Earl... |
1181 |
* early_platform_add_devices - adds a number of early platform devices |
13977091a Driver Core: earl... |
1182 1183 |
* @devs: array of early platform devices to add * @num: number of early platform devices in array |
4d26e139f Driver core: Earl... |
1184 1185 1186 |
* * Used by early architecture code to register early platform devices and * their platform data. |
13977091a Driver Core: earl... |
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 |
*/ void __init early_platform_add_devices(struct platform_device **devs, int num) { struct device *dev; int i; /* simply add the devices to list */ for (i = 0; i < num; i++) { dev = &devs[i]->dev; if (!dev->devres_head.next) { |
bed2b42d9 PM / Runtime: All... |
1198 |
pm_runtime_early_init(dev); |
13977091a Driver Core: earl... |
1199 1200 1201 1202 1203 1204 1205 1206 |
INIT_LIST_HEAD(&dev->devres_head); list_add_tail(&dev->devres_head, &early_platform_device_list); } } } /** |
4d26e139f Driver core: Earl... |
1207 |
* early_platform_driver_register_all - register early platform drivers |
13977091a Driver Core: earl... |
1208 |
* @class_str: string to identify early platform driver class |
4d26e139f Driver core: Earl... |
1209 1210 1211 1212 |
* * Used by architecture code to register all early platform drivers * for a certain class. If omitted then only early platform drivers * with matching kernel command line class parameters will be registered. |
13977091a Driver Core: earl... |
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 |
*/ void __init early_platform_driver_register_all(char *class_str) { /* The "class_str" parameter may or may not be present on the kernel * command line. If it is present then there may be more than one * matching parameter. * * Since we register our early platform drivers using early_param() * we need to make sure that they also get registered in the case * when the parameter is missing from the kernel command line. * * We use parse_early_options() to make sure the early_param() gets * called at least once. The early_param() may be called more than * once since the name of the preferred device may be specified on * the kernel command line. early_platform_driver_register() handles * this case for us. */ parse_early_options(class_str); } /** |
4d26e139f Driver core: Earl... |
1234 |
* early_platform_match - find early platform device matching driver |
d86c1302c Driver core: plat... |
1235 |
* @epdrv: early platform driver structure |
13977091a Driver Core: earl... |
1236 1237 |
* @id: id to match against */ |
a82579106 drivers / platfor... |
1238 |
static struct platform_device * __init |
13977091a Driver Core: earl... |
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 |
early_platform_match(struct early_platform_driver *epdrv, int id) { struct platform_device *pd; list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) if (platform_match(&pd->dev, &epdrv->pdrv->driver)) if (pd->id == id) return pd; return NULL; } /** |
4d26e139f Driver core: Earl... |
1252 |
* early_platform_left - check if early platform driver has matching devices |
d86c1302c Driver core: plat... |
1253 |
* @epdrv: early platform driver structure |
13977091a Driver Core: earl... |
1254 1255 |
* @id: return true if id or above exists */ |
a82579106 drivers / platfor... |
1256 |
static int __init early_platform_left(struct early_platform_driver *epdrv, |
13977091a Driver Core: earl... |
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
int id) { struct platform_device *pd; list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) if (platform_match(&pd->dev, &epdrv->pdrv->driver)) if (pd->id >= id) return 1; return 0; } /** |
4d26e139f Driver core: Earl... |
1270 |
* early_platform_driver_probe_id - probe drivers matching class_str and id |
13977091a Driver Core: earl... |
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 |
* @class_str: string to identify early platform driver class * @id: id to match against * @nr_probe: number of platform devices to successfully probe before exiting */ static int __init early_platform_driver_probe_id(char *class_str, int id, int nr_probe) { struct early_platform_driver *epdrv; struct platform_device *match; int match_id; int n = 0; int left = 0; list_for_each_entry(epdrv, &early_platform_driver_list, list) { /* only use drivers matching our class_str */ if (strcmp(class_str, epdrv->class_str)) continue; if (id == -2) { match_id = epdrv->requested_id; left = 1; } else { match_id = id; left += early_platform_left(epdrv, id); /* skip requested id */ switch (epdrv->requested_id) { case EARLY_PLATFORM_ID_ERROR: case EARLY_PLATFORM_ID_UNSET: break; default: if (epdrv->requested_id == id) match_id = EARLY_PLATFORM_ID_UNSET; } } switch (match_id) { case EARLY_PLATFORM_ID_ERROR: |
0258e182e driver core: plat... |
1311 1312 1313 |
pr_warn("%s: unable to parse %s parameter ", class_str, epdrv->pdrv->driver.name); |
13977091a Driver Core: earl... |
1314 1315 1316 1317 1318 1319 1320 1321 1322 |
/* fall-through */ case EARLY_PLATFORM_ID_UNSET: match = NULL; break; default: match = early_platform_match(epdrv, match_id); } if (match) { |
a636ee7fb driver core: Earl... |
1323 1324 1325 1326 1327 |
/* * Set up a sensible init_name to enable * dev_name() and others to be used before the * rest of the driver core is initialized. */ |
06fe53beb driver core: Earl... |
1328 |
if (!match->dev.init_name && slab_is_available()) { |
a636ee7fb driver core: Earl... |
1329 |
if (match->id != -1) |
bd05086bb driver core: Conv... |
1330 1331 1332 1333 |
match->dev.init_name = kasprintf(GFP_KERNEL, "%s.%d", match->name, match->id); |
a636ee7fb driver core: Earl... |
1334 |
else |
bd05086bb driver core: Conv... |
1335 1336 1337 |
match->dev.init_name = kasprintf(GFP_KERNEL, "%s", match->name); |
a636ee7fb driver core: Earl... |
1338 |
|
a636ee7fb driver core: Earl... |
1339 1340 1341 |
if (!match->dev.init_name) return -ENOMEM; } |
bd05086bb driver core: Conv... |
1342 |
|
13977091a Driver Core: earl... |
1343 |
if (epdrv->pdrv->probe(match)) |
0258e182e driver core: plat... |
1344 1345 1346 |
pr_warn("%s: unable to probe %s early. ", class_str, match->name); |
13977091a Driver Core: earl... |
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 |
else n++; } if (n >= nr_probe) break; } if (left) return n; else return -ENODEV; } /** |
4d26e139f Driver core: Earl... |
1362 |
* early_platform_driver_probe - probe a class of registered drivers |
13977091a Driver Core: earl... |
1363 1364 1365 |
* @class_str: string to identify early platform driver class * @nr_probe: number of platform devices to successfully probe before exiting * @user_only: only probe user specified early platform devices |
4d26e139f Driver core: Earl... |
1366 1367 1368 1369 |
* * Used by architecture code to probe registered early platform drivers * within a certain class. For probe to happen a registered early platform * device matching a registered early platform driver is needed. |
13977091a Driver Core: earl... |
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 |
*/ int __init early_platform_driver_probe(char *class_str, int nr_probe, int user_only) { int k, n, i; n = 0; for (i = -2; n < nr_probe; i++) { k = early_platform_driver_probe_id(class_str, i, nr_probe - n); if (k < 0) break; n += k; if (user_only) break; } return n; } /** * early_platform_cleanup - clean up early platform code */ void __init early_platform_cleanup(void) { struct platform_device *pd, *pd2; /* clean up the devres list used to chain devices */ list_for_each_entry_safe(pd, pd2, &early_platform_device_list, dev.devres_head) { list_del(&pd->dev.devres_head); memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); } } |