aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/power/opp.txt25
-rw-r--r--drivers/base/power/opp.c47
-rw-r--r--include/linux/opp.h8
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
3SoCs have a standard set of tuples consisting of frequency and
4voltage pairs that the device will support per voltage domain. These
5are called Operating Performance Points or OPPs.
6
7Properties:
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
13Examples:
14
15cpu@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 */
686int 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
49struct srcu_notifier_head *opp_get_notifier(struct device *dev); 49struct srcu_notifier_head *opp_get_notifier(struct device *dev);
50 50
51#ifdef CONFIG_OF
52int of_init_opp_table(struct device *dev);
53#else
54static inline int of_init_opp_table(struct device *dev)
55{
56 return -EINVAL;
57}
58#endif /* CONFIG_OF */
51#else 59#else
52static inline unsigned long opp_get_voltage(struct opp *opp) 60static inline unsigned long opp_get_voltage(struct opp *opp)
53{ 61{