Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Shawn Guo and committed by
Rafael J. Wysocki
b496dfbc ec971ea5

+80
+25
Documentation/devicetree/bindings/power/opp.txt
··· 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 + };
+47
drivers/base/power/opp.c
··· 22 22 #include <linux/rculist.h> 23 23 #include <linux/rcupdate.h> 24 24 #include <linux/opp.h> 25 + #include <linux/of.h> 25 26 26 27 /* 27 28 * Internal data structure organization with the OPP layer library is as ··· 675 674 676 675 return &dev_opp->head; 677 676 } 677 + 678 + #ifdef CONFIG_OF 679 + /** 680 + * of_init_opp_table() - Initialize opp table from device tree 681 + * @dev: device pointer used to lookup device OPPs. 682 + * 683 + * Register the initial OPP table with the OPP library for given device. 684 + */ 685 + int of_init_opp_table(struct device *dev) 686 + { 687 + const struct property *prop; 688 + const __be32 *val; 689 + int nr; 690 + 691 + prop = of_find_property(dev->of_node, "operating-points", NULL); 692 + if (!prop) 693 + return -ENODEV; 694 + if (!prop->value) 695 + return -ENODATA; 696 + 697 + /* 698 + * Each OPP is a set of tuples consisting of frequency and 699 + * voltage like <freq-kHz vol-uV>. 700 + */ 701 + nr = prop->length / sizeof(u32); 702 + if (nr % 2) { 703 + dev_err(dev, "%s: Invalid OPP list\n", __func__); 704 + return -EINVAL; 705 + } 706 + 707 + val = prop->value; 708 + while (nr) { 709 + unsigned long freq = be32_to_cpup(val++) * 1000; 710 + unsigned long volt = be32_to_cpup(val++); 711 + 712 + if (opp_add(dev, freq, volt)) { 713 + dev_warn(dev, "%s: Failed to add OPP %ld\n", 714 + __func__, freq); 715 + continue; 716 + } 717 + nr -= 2; 718 + } 719 + 720 + return 0; 721 + } 722 + #endif
+8
include/linux/opp.h
··· 48 48 49 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 59 #else 52 60 static inline unsigned long opp_get_voltage(struct opp *opp) 53 61 {