aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/omap_device.c
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 /arch/arm/plat-omap/omap_device.c
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>
Diffstat (limited to 'arch/arm/plat-omap/omap_device.c')
-rw-r--r--arch/arm/plat-omap/omap_device.c101
1 files changed, 101 insertions, 0 deletions
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);