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/rculist.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <linux/opp.h>
|
#include <linux/opp.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal data structure organization with the OPP layer library is as
|
* 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;
|
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);
|
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
|
#else
|
||||||
static inline unsigned long opp_get_voltage(struct opp *opp)
|
static inline unsigned long opp_get_voltage(struct opp *opp)
|
||||||
{
|
{
|
||||||
|
|
Reference in New Issue