|
@@ -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
|