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>
This commit is contained in:
parent
ec971ea5f2
commit
b496dfbc94
|
@ -0,0 +1,25 @@
|
|||
* Generic OPP Interface
|
||||
|
||||
SoCs have a standard set of tuples consisting of frequency and
|
||||
voltage pairs that the device will support per voltage domain. These
|
||||
are called Operating Performance Points or OPPs.
|
||||
|
||||
Properties:
|
||||
- operating-points: An array of 2-tuples items, and each item consists
|
||||
of frequency and voltage like <freq-kHz vol-uV>.
|
||||
freq: clock frequency in kHz
|
||||
vol: voltage in microvolt
|
||||
|
||||
Examples:
|
||||
|
||||
cpu@0 {
|
||||
compatible = "arm,cortex-a9";
|
||||
reg = <0>;
|
||||
next-level-cache = <&L2>;
|
||||
operating-points = <
|
||||
/* kHz uV */
|
||||
792000 1100000
|
||||
396000 950000
|
||||
198000 850000
|
||||
>;
|
||||
};
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/opp.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/*
|
||||
* 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)
|
|||
|
||||
return &dev_opp->head;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* of_init_opp_table() - Initialize opp table from device tree
|
||||
* @dev: device pointer used to lookup device OPPs.
|
||||
*
|
||||
* Register the initial OPP table with the OPP library for given device.
|
||||
*/
|
||||
int of_init_opp_table(struct device *dev)
|
||||
{
|
||||
const struct property *prop;
|
||||
const __be32 *val;
|
||||
int nr;
|
||||
|
||||
prop = of_find_property(dev->of_node, "operating-points", NULL);
|
||||
if (!prop)
|
||||
return -ENODEV;
|
||||
if (!prop->value)
|
||||
return -ENODATA;
|
||||
|
||||
/*
|
||||
* Each OPP is a set of tuples consisting of frequency and
|
||||
* voltage like <freq-kHz vol-uV>.
|
||||
*/
|
||||
nr = prop->length / sizeof(u32);
|
||||
if (nr % 2) {
|
||||
dev_err(dev, "%s: Invalid OPP list\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = prop->value;
|
||||
while (nr) {
|
||||
unsigned long freq = be32_to_cpup(val++) * 1000;
|
||||
unsigned long volt = be32_to_cpup(val++);
|
||||
|
||||
if (opp_add(dev, freq, volt)) {
|
||||
dev_warn(dev, "%s: Failed to add OPP %ld\n",
|
||||
__func__, freq);
|
||||
continue;
|
||||
}
|
||||
nr -= 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -48,6 +48,14 @@ int opp_disable(struct device *dev, unsigned long freq);
|
|||
|
||||
struct srcu_notifier_head *opp_get_notifier(struct device *dev);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
int of_init_opp_table(struct device *dev);
|
||||
#else
|
||||
static inline int of_init_opp_table(struct device *dev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
#else
|
||||
static inline unsigned long opp_get_voltage(struct opp *opp)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue