diff options
author | Benoit Cousson <b-cousson@ti.com> | 2011-08-09 10:47:01 -0400 |
---|---|---|
committer | Kevin Hilman <khilman@ti.com> | 2011-10-04 12:52:23 -0400 |
commit | a4f6cdb0672fe9f171b1e8a0faa121b5d76e1c4a (patch) | |
tree | 258c84e4f5fbec8e3f353a199724639d6ea6dcf6 /arch/arm/plat-omap/omap_device.c | |
parent | 4fcd15a032cec4b2684a32c86e895b50cdbee50c (diff) |
ARM: OMAP: omap_device: Add omap_device_[alloc|delete] for DT integration
Split the omap_device_build_ss into two smaller functions
that will allow to populate a platform_device already allocated by
device-tree.
The functionality of the omap_device_build_ss is still the same, but
the omap_device_alloc will be usable with devices already built by
device-tree.
Signed-off-by: Benoit Cousson <b-cousson@ti.com>
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.c | 177 |
1 files changed, 119 insertions, 58 deletions
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index cd8d9778b14e..6725c72b0cd0 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c | |||
@@ -96,6 +96,11 @@ | |||
96 | 96 | ||
97 | static int omap_device_register(struct platform_device *pdev); | 97 | static int omap_device_register(struct platform_device *pdev); |
98 | static int omap_early_device_register(struct platform_device *pdev); | 98 | static int omap_early_device_register(struct platform_device *pdev); |
99 | static struct omap_device *omap_device_alloc(struct platform_device *pdev, | ||
100 | struct omap_hwmod **ohs, int oh_cnt, | ||
101 | struct omap_device_pm_latency *pm_lats, | ||
102 | int pm_lats_cnt); | ||
103 | |||
99 | 104 | ||
100 | static struct omap_device_pm_latency omap_default_latency[] = { | 105 | static struct omap_device_pm_latency omap_default_latency[] = { |
101 | { | 106 | { |
@@ -397,6 +402,110 @@ static int omap_device_fill_resources(struct omap_device *od, | |||
397 | } | 402 | } |
398 | 403 | ||
399 | /** | 404 | /** |
405 | * omap_device_alloc - allocate an omap_device | ||
406 | * @pdev: platform_device that will be included in this omap_device | ||
407 | * @oh: ptr to the single omap_hwmod that backs this omap_device | ||
408 | * @pdata: platform_data ptr to associate with the platform_device | ||
409 | * @pdata_len: amount of memory pointed to by @pdata | ||
410 | * @pm_lats: pointer to a omap_device_pm_latency array for this device | ||
411 | * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats | ||
412 | * | ||
413 | * Convenience function for allocating an omap_device structure and filling | ||
414 | * hwmods, resources and pm_latency attributes. | ||
415 | * | ||
416 | * Returns an struct omap_device pointer or ERR_PTR() on error; | ||
417 | */ | ||
418 | static struct omap_device *omap_device_alloc(struct platform_device *pdev, | ||
419 | struct omap_hwmod **ohs, int oh_cnt, | ||
420 | struct omap_device_pm_latency *pm_lats, | ||
421 | int pm_lats_cnt) | ||
422 | { | ||
423 | int ret = -ENOMEM; | ||
424 | struct omap_device *od; | ||
425 | struct resource *res = NULL; | ||
426 | int i, res_count; | ||
427 | struct omap_hwmod **hwmods; | ||
428 | |||
429 | od = kzalloc(sizeof(struct omap_device), GFP_KERNEL); | ||
430 | if (!od) { | ||
431 | ret = -ENOMEM; | ||
432 | goto oda_exit1; | ||
433 | } | ||
434 | od->hwmods_cnt = oh_cnt; | ||
435 | |||
436 | hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL); | ||
437 | if (!hwmods) | ||
438 | goto oda_exit2; | ||
439 | |||
440 | od->hwmods = hwmods; | ||
441 | od->pdev = pdev; | ||
442 | |||
443 | /* | ||
444 | * HACK: Ideally the resources from DT should match, and hwmod | ||
445 | * should just add the missing ones. Since the name is not | ||
446 | * properly populated by DT, stick to hwmod resources only. | ||
447 | */ | ||
448 | if (pdev->num_resources && pdev->resource) | ||
449 | dev_warn(&pdev->dev, "%s(): resources already allocated %d\n", | ||
450 | __func__, pdev->num_resources); | ||
451 | |||
452 | res_count = omap_device_count_resources(od); | ||
453 | if (res_count > 0) { | ||
454 | dev_dbg(&pdev->dev, "%s(): resources allocated from hwmod %d\n", | ||
455 | __func__, res_count); | ||
456 | res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); | ||
457 | if (!res) | ||
458 | goto oda_exit3; | ||
459 | |||
460 | omap_device_fill_resources(od, res); | ||
461 | |||
462 | ret = platform_device_add_resources(pdev, res, res_count); | ||
463 | kfree(res); | ||
464 | |||
465 | if (ret) | ||
466 | goto oda_exit3; | ||
467 | } | ||
468 | |||
469 | if (!pm_lats) { | ||
470 | pm_lats = omap_default_latency; | ||
471 | pm_lats_cnt = ARRAY_SIZE(omap_default_latency); | ||
472 | } | ||
473 | |||
474 | od->pm_lats_cnt = pm_lats_cnt; | ||
475 | od->pm_lats = kmemdup(pm_lats, | ||
476 | sizeof(struct omap_device_pm_latency) * pm_lats_cnt, | ||
477 | GFP_KERNEL); | ||
478 | if (!od->pm_lats) | ||
479 | goto oda_exit3; | ||
480 | |||
481 | pdev->archdata.od = od; | ||
482 | |||
483 | for (i = 0; i < oh_cnt; i++) { | ||
484 | hwmods[i]->od = od; | ||
485 | _add_hwmod_clocks_clkdev(od, hwmods[i]); | ||
486 | } | ||
487 | |||
488 | return od; | ||
489 | |||
490 | oda_exit3: | ||
491 | kfree(hwmods); | ||
492 | oda_exit2: | ||
493 | kfree(od); | ||
494 | oda_exit1: | ||
495 | dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret); | ||
496 | |||
497 | return ERR_PTR(ret); | ||
498 | } | ||
499 | |||
500 | static void omap_device_delete(struct omap_device *od) | ||
501 | { | ||
502 | od->pdev->archdata.od = NULL; | ||
503 | kfree(od->pm_lats); | ||
504 | kfree(od->hwmods); | ||
505 | kfree(od); | ||
506 | } | ||
507 | |||
508 | /** | ||
400 | * omap_device_build - build and register an omap_device with one omap_hwmod | 509 | * omap_device_build - build and register an omap_device with one omap_hwmod |
401 | * @pdev_name: name of the platform_device driver to use | 510 | * @pdev_name: name of the platform_device driver to use |
402 | * @pdev_id: this platform_device's connection ID | 511 | * @pdev_id: this platform_device's connection ID |
@@ -455,9 +564,6 @@ struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, | |||
455 | int ret = -ENOMEM; | 564 | int ret = -ENOMEM; |
456 | struct platform_device *pdev; | 565 | struct platform_device *pdev; |
457 | struct omap_device *od; | 566 | struct omap_device *od; |
458 | struct resource *res = NULL; | ||
459 | int i, res_count; | ||
460 | struct omap_hwmod **hwmods; | ||
461 | 567 | ||
462 | if (!ohs || oh_cnt == 0 || !pdev_name) | 568 | if (!ohs || oh_cnt == 0 || !pdev_name) |
463 | return ERR_PTR(-EINVAL); | 569 | return ERR_PTR(-EINVAL); |
@@ -471,76 +577,31 @@ struct platform_device *omap_device_build_ss(const char *pdev_name, int pdev_id, | |||
471 | goto odbs_exit; | 577 | goto odbs_exit; |
472 | } | 578 | } |
473 | 579 | ||
474 | pr_debug("omap_device: %s: building with %d hwmods\n", pdev_name, | 580 | /* Set the dev_name early to allow dev_xxx in omap_device_alloc */ |
475 | oh_cnt); | 581 | if (pdev->id != -1) |
582 | dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); | ||
583 | else | ||
584 | dev_set_name(&pdev->dev, "%s", pdev->name); | ||
476 | 585 | ||
477 | od = kzalloc(sizeof(struct omap_device), GFP_KERNEL); | 586 | od = omap_device_alloc(pdev, ohs, oh_cnt, pm_lats, pm_lats_cnt); |
478 | if (!od) { | 587 | if (!od) |
479 | ret = -ENOMEM; | ||
480 | goto odbs_exit1; | 588 | goto odbs_exit1; |
481 | } | ||
482 | od->hwmods_cnt = oh_cnt; | ||
483 | |||
484 | hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, | ||
485 | GFP_KERNEL); | ||
486 | if (!hwmods) | ||
487 | goto odbs_exit2; | ||
488 | |||
489 | memcpy(hwmods, ohs, sizeof(struct omap_hwmod *) * oh_cnt); | ||
490 | od->hwmods = hwmods; | ||
491 | od->pdev = pdev; | ||
492 | |||
493 | res_count = omap_device_count_resources(od); | ||
494 | if (res_count > 0) { | ||
495 | res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); | ||
496 | if (!res) | ||
497 | goto odbs_exit3; | ||
498 | |||
499 | omap_device_fill_resources(od, res); | ||
500 | |||
501 | ret = platform_device_add_resources(pdev, res, res_count); | ||
502 | kfree(res); | ||
503 | |||
504 | if (ret) | ||
505 | goto odbs_exit3; | ||
506 | } | ||
507 | 589 | ||
508 | ret = platform_device_add_data(pdev, pdata, pdata_len); | 590 | ret = platform_device_add_data(pdev, pdata, pdata_len); |
509 | if (ret) | 591 | if (ret) |
510 | goto odbs_exit3; | 592 | goto odbs_exit2; |
511 | |||
512 | pdev->archdata.od = od; | ||
513 | 593 | ||
514 | if (is_early_device) | 594 | if (is_early_device) |
515 | ret = omap_early_device_register(pdev); | 595 | ret = omap_early_device_register(pdev); |
516 | else | 596 | else |
517 | ret = omap_device_register(pdev); | 597 | ret = omap_device_register(pdev); |
518 | if (ret) | 598 | if (ret) |
519 | goto odbs_exit3; | 599 | goto odbs_exit2; |
520 | |||
521 | if (!pm_lats) { | ||
522 | pm_lats = omap_default_latency; | ||
523 | pm_lats_cnt = ARRAY_SIZE(omap_default_latency); | ||
524 | } | ||
525 | |||
526 | od->pm_lats_cnt = pm_lats_cnt; | ||
527 | od->pm_lats = kmemdup(pm_lats, | ||
528 | sizeof(struct omap_device_pm_latency) * pm_lats_cnt, | ||
529 | GFP_KERNEL); | ||
530 | if (!od->pm_lats) | ||
531 | goto odbs_exit3; | ||
532 | |||
533 | for (i = 0; i < oh_cnt; i++) { | ||
534 | hwmods[i]->od = od; | ||
535 | _add_hwmod_clocks_clkdev(od, hwmods[i]); | ||
536 | } | ||
537 | 600 | ||
538 | return pdev; | 601 | return pdev; |
539 | 602 | ||
540 | odbs_exit3: | ||
541 | kfree(hwmods); | ||
542 | odbs_exit2: | 603 | odbs_exit2: |
543 | kfree(od); | 604 | omap_device_delete(od); |
544 | odbs_exit1: | 605 | odbs_exit1: |
545 | platform_device_put(pdev); | 606 | platform_device_put(pdev); |
546 | odbs_exit: | 607 | odbs_exit: |