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 | |
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>
-rw-r--r-- | Documentation/devicetree/bindings/power/opp.txt | 25 | ||||
-rw-r--r-- | drivers/base/power/opp.c | 47 | ||||
-rw-r--r-- | include/linux/opp.h | 8 |
3 files changed, 80 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt new file mode 100644 index 000000000000..74499e5033fc --- /dev/null +++ b/Documentation/devicetree/bindings/power/opp.txt | |||
@@ -0,0 +1,25 @@ | |||
1 | * Generic OPP Interface | ||
2 | |||
3 | SoCs have a standard set of tuples consisting of frequency and | ||
4 | voltage pairs that the device will support per voltage domain. These | ||
5 | are called Operating Performance Points or OPPs. | ||
6 | |||
7 | Properties: | ||
8 | - operating-points: An array of 2-tuples items, and each item consists | ||
9 | of frequency and voltage like <freq-kHz vol-uV>. | ||
10 | freq: clock frequency in kHz | ||
11 | vol: voltage in microvolt | ||
12 | |||
13 | Examples: | ||
14 | |||
15 | cpu@0 { | ||
16 | compatible = "arm,cortex-a9"; | ||
17 | reg = <0>; | ||
18 | next-level-cache = <&L2>; | ||
19 | operating-points = < | ||
20 | /* kHz uV */ | ||
21 | 792000 1100000 | ||
22 | 396000 950000 | ||
23 | 198000 850000 | ||
24 | >; | ||
25 | }; | ||
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 | ||
diff --git a/include/linux/opp.h b/include/linux/opp.h index 2a4e5faee904..214e0ebcb84d 100644 --- a/include/linux/opp.h +++ b/include/linux/opp.h | |||
@@ -48,6 +48,14 @@ int opp_disable(struct device *dev, unsigned long freq); | |||
48 | 48 | ||
49 | struct srcu_notifier_head *opp_get_notifier(struct device *dev); | 49 | struct srcu_notifier_head *opp_get_notifier(struct device *dev); |
50 | 50 | ||
51 | #ifdef CONFIG_OF | ||
52 | int of_init_opp_table(struct device *dev); | ||
53 | #else | ||
54 | static inline int of_init_opp_table(struct device *dev) | ||
55 | { | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | #endif /* CONFIG_OF */ | ||
51 | #else | 59 | #else |
52 | static inline unsigned long opp_get_voltage(struct opp *opp) | 60 | static inline unsigned long opp_get_voltage(struct opp *opp) |
53 | { | 61 | { |