diff options
| author | Shawn Guo <shawn.guo@linaro.org> | 2012-09-04 19:09:12 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-09-09 16:06:33 -0400 |
| commit | b496dfbc94ab86f970ef0167eaabe51f930aa5fb (patch) | |
| tree | 3ce7bdb6847fbcff3f46935ebc5b5c17da23d31d /drivers/base | |
| parent | ec971ea5f2426a0bf9d5cca9a103743918c12978 (diff) | |
PM / OPP: Initialize OPP table from device tree
With a lot of devices booting from device tree nowadays, it requires
that OPP table can be initialized from device tree. The patch adds
a helper function of_init_opp_table together with a binding doc for
that purpose.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/power/opp.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index ac993eafec82..d9468642fc41 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/rculist.h> | 22 | #include <linux/rculist.h> |
| 23 | #include <linux/rcupdate.h> | 23 | #include <linux/rcupdate.h> |
| 24 | #include <linux/opp.h> | 24 | #include <linux/opp.h> |
| 25 | #include <linux/of.h> | ||
| 25 | 26 | ||
| 26 | /* | 27 | /* |
| 27 | * Internal data structure organization with the OPP layer library is as | 28 | * Internal data structure organization with the OPP layer library is as |
| @@ -674,3 +675,49 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev) | |||
| 674 | 675 | ||
| 675 | return &dev_opp->head; | 676 | return &dev_opp->head; |
| 676 | } | 677 | } |
| 678 | |||
| 679 | #ifdef CONFIG_OF | ||
| 680 | /** | ||
| 681 | * of_init_opp_table() - Initialize opp table from device tree | ||
| 682 | * @dev: device pointer used to lookup device OPPs. | ||
| 683 | * | ||
| 684 | * Register the initial OPP table with the OPP library for given device. | ||
| 685 | */ | ||
| 686 | int of_init_opp_table(struct device *dev) | ||
| 687 | { | ||
| 688 | const struct property *prop; | ||
| 689 | const __be32 *val; | ||
| 690 | int nr; | ||
| 691 | |||
| 692 | prop = of_find_property(dev->of_node, "operating-points", NULL); | ||
| 693 | if (!prop) | ||
| 694 | return -ENODEV; | ||
| 695 | if (!prop->value) | ||
| 696 | return -ENODATA; | ||
| 697 | |||
| 698 | /* | ||
| 699 | * Each OPP is a set of tuples consisting of frequency and | ||
| 700 | * voltage like <freq-kHz vol-uV>. | ||
| 701 | */ | ||
| 702 | nr = prop->length / sizeof(u32); | ||
| 703 | if (nr % 2) { | ||
| 704 | dev_err(dev, "%s: Invalid OPP list\n", __func__); | ||
| 705 | return -EINVAL; | ||
| 706 | } | ||
| 707 | |||
| 708 | val = prop->value; | ||
| 709 | while (nr) { | ||
| 710 | unsigned long freq = be32_to_cpup(val++) * 1000; | ||
| 711 | unsigned long volt = be32_to_cpup(val++); | ||
| 712 | |||
| 713 | if (opp_add(dev, freq, volt)) { | ||
| 714 | dev_warn(dev, "%s: Failed to add OPP %ld\n", | ||
| 715 | __func__, freq); | ||
| 716 | continue; | ||
| 717 | } | ||
| 718 | nr -= 2; | ||
| 719 | } | ||
| 720 | |||
| 721 | return 0; | ||
| 722 | } | ||
| 723 | #endif | ||
