aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenoit Cousson <b-cousson@ti.com>2011-08-10 07:32:08 -0400
committerKevin Hilman <khilman@ti.com>2011-10-04 12:52:23 -0400
commitdc2d07ebaea839a6e0fa47588c7984931f3c9c71 (patch)
tree5733bcf7467de9d2a7aceb5cf088c7b7eafb50d3
parenta4f6cdb0672fe9f171b1e8a0faa121b5d76e1c4a (diff)
ARM: OMAP: omap_device: Add a method to build an omap_device from a DT node
Add a notifier called during device_add phase. If an of_node is present, retrieve the hwmod entry in order to populate properly the omap_device structure. For the moment the resource from the device-tree are overloaded. DT does not support named resource yet, and thus, most driver will not work without that information. Add a documentation to capture the specifics OMAP bindings needed for device-tree support. Signed-off-by: Benoit Cousson <b-cousson@ti.com> Cc: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Kevin Hilman <khilman@ti.com>
-rw-r--r--Documentation/devicetree/bindings/arm/omap/omap.txt43
-rw-r--r--arch/arm/plat-omap/omap_device.c101
2 files changed, 144 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
new file mode 100644
index 000000000000..dbdab40ed3a6
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -0,0 +1,43 @@
1* Texas Instruments OMAP
2
3OMAP is currently using a static file per SoC family to describe the
4IPs present in the SoC.
5On top of that an omap_device is created to extend the platform_device
6capabilities and to allow binding with one or several hwmods.
7The hwmods will contain all the information to build the device:
8adresse range, irq lines, dma lines, interconnect, PRCM register,
9clock domain, input clocks.
10For the moment just point to the existing hwmod, the next step will be
11to move data from hwmod to device-tree representation.
12
13
14Required properties:
15- compatible: Every devices present in OMAP SoC should be in the
16 form: "ti,XXX"
17- ti,hwmods: list of hwmod names (ascii strings), that comes from the OMAP
18 HW documentation, attached to a device. Must contain at least
19 one hwmod.
20
21Optional properties:
22- ti,no_idle_on_suspend: When present, it prevents the PM to idle the module
23 during suspend.
24
25
26Example:
27
28spinlock@1 {
29 compatible = "ti,omap4-spinlock";
30 ti,hwmods = "spinlock";
31};
32
33
34Boards:
35
36- OMAP3 BeagleBoard : Low cost community board
37 compatible = "ti,omap3-beagle", "ti,omap3"
38
39- OMAP4 SDP : Software Developement Board
40 compatible = "ti,omap4-sdp", "ti,omap4430"
41
42- OMAP4 PandaBoard : Low cost community board
43 compatible = "ti,omap4-panda", "ti,omap4430"
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 6725c72b0cd0..cd90bedd9306 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -85,6 +85,8 @@
85#include <linux/clk.h> 85#include <linux/clk.h>
86#include <linux/clkdev.h> 86#include <linux/clkdev.h>
87#include <linux/pm_runtime.h> 87#include <linux/pm_runtime.h>
88#include <linux/of.h>
89#include <linux/notifier.h>
88 90
89#include <plat/omap_device.h> 91#include <plat/omap_device.h>
90#include <plat/omap_hwmod.h> 92#include <plat/omap_hwmod.h>
@@ -100,6 +102,7 @@ static struct omap_device *omap_device_alloc(struct platform_device *pdev,
100 struct omap_hwmod **ohs, int oh_cnt, 102 struct omap_hwmod **ohs, int oh_cnt,
101 struct omap_device_pm_latency *pm_lats, 103 struct omap_device_pm_latency *pm_lats,
102 int pm_lats_cnt); 104 int pm_lats_cnt);
105static void omap_device_delete(struct omap_device *od);
103 106
104 107
105static struct omap_device_pm_latency omap_default_latency[] = { 108static struct omap_device_pm_latency omap_default_latency[] = {
@@ -316,6 +319,96 @@ static void _add_hwmod_clocks_clkdev(struct omap_device *od,
316} 319}
317 320
318 321
322static struct dev_pm_domain omap_device_pm_domain;
323
324/**
325 * omap_device_build_from_dt - build an omap_device with multiple hwmods
326 * @pdev_name: name of the platform_device driver to use
327 * @pdev_id: this platform_device's connection ID
328 * @oh: ptr to the single omap_hwmod that backs this omap_device
329 * @pdata: platform_data ptr to associate with the platform_device
330 * @pdata_len: amount of memory pointed to by @pdata
331 * @pm_lats: pointer to a omap_device_pm_latency array for this device
332 * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats
333 * @is_early_device: should the device be registered as an early device or not
334 *
335 * Function for building an omap_device already registered from device-tree
336 *
337 * Returns 0 or PTR_ERR() on error.
338 */
339static int omap_device_build_from_dt(struct platform_device *pdev)
340{
341 struct omap_hwmod **hwmods;
342 struct omap_device *od;
343 struct omap_hwmod *oh;
344 struct device_node *node = pdev->dev.of_node;
345 const char *oh_name;
346 int oh_cnt, i, ret = 0;
347
348 oh_cnt = of_property_count_strings(node, "ti,hwmods");
349 if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) {
350 dev_warn(&pdev->dev, "No 'hwmods' to build omap_device\n");
351 return -ENODEV;
352 }
353
354 hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
355 if (!hwmods) {
356 ret = -ENOMEM;
357 goto odbfd_exit;
358 }
359
360 for (i = 0; i < oh_cnt; i++) {
361 of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
362 oh = omap_hwmod_lookup(oh_name);
363 if (!oh) {
364 dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
365 oh_name);
366 ret = -EINVAL;
367 goto odbfd_exit1;
368 }
369 hwmods[i] = oh;
370 }
371
372 od = omap_device_alloc(pdev, hwmods, oh_cnt, NULL, 0);
373 if (!od) {
374 dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
375 oh_name);
376 ret = PTR_ERR(od);
377 goto odbfd_exit1;
378 }
379
380 if (of_get_property(node, "ti,no_idle_on_suspend", NULL))
381 omap_device_disable_idle_on_suspend(pdev);
382
383 pdev->dev.pm_domain = &omap_device_pm_domain;
384
385odbfd_exit1:
386 kfree(hwmods);
387odbfd_exit:
388 return ret;
389}
390
391static int _omap_device_notifier_call(struct notifier_block *nb,
392 unsigned long event, void *dev)
393{
394 struct platform_device *pdev = to_platform_device(dev);
395
396 switch (event) {
397 case BUS_NOTIFY_ADD_DEVICE:
398 if (pdev->dev.of_node)
399 omap_device_build_from_dt(pdev);
400 break;
401
402 case BUS_NOTIFY_DEL_DEVICE:
403 if (pdev->archdata.od)
404 omap_device_delete(pdev->archdata.od);
405 break;
406 }
407
408 return NOTIFY_DONE;
409}
410
411
319/* Public functions for use by core code */ 412/* Public functions for use by core code */
320 413
321/** 414/**
@@ -499,6 +592,9 @@ oda_exit1:
499 592
500static void omap_device_delete(struct omap_device *od) 593static void omap_device_delete(struct omap_device *od)
501{ 594{
595 if (!od)
596 return;
597
502 od->pdev->archdata.od = NULL; 598 od->pdev->archdata.od = NULL;
503 kfree(od->pm_lats); 599 kfree(od->pm_lats);
504 kfree(od->hwmods); 600 kfree(od->hwmods);
@@ -1038,8 +1134,13 @@ struct device omap_device_parent = {
1038 .parent = &platform_bus, 1134 .parent = &platform_bus,
1039}; 1135};
1040 1136
1137static struct notifier_block platform_nb = {
1138 .notifier_call = _omap_device_notifier_call,
1139};
1140
1041static int __init omap_device_init(void) 1141static int __init omap_device_init(void)
1042{ 1142{
1143 bus_register_notifier(&platform_bus_type, &platform_nb);
1043 return device_register(&omap_device_parent); 1144 return device_register(&omap_device_parent);
1044} 1145}
1045core_initcall(omap_device_init); 1146core_initcall(omap_device_init);