From patchwork Wed Jul 18 16:57:49 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Guo X-Patchwork-Id: 1212571 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 757B33FCFC for ; Wed, 18 Jul 2012 17:01:44 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1SrXZy-0001TU-Rs; Wed, 18 Jul 2012 16:58:26 +0000 Received: from tx2ehsobe005.messaging.microsoft.com ([65.55.88.15] helo=tx2outboundpool.messaging.microsoft.com) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1SrXZu-0001St-7W for linux-arm-kernel@lists.infradead.org; Wed, 18 Jul 2012 16:58:23 +0000 Received: from mail156-tx2-R.bigfish.com (10.9.14.237) by TX2EHSOBE009.bigfish.com (10.9.40.29) with Microsoft SMTP Server id 14.1.225.23; Wed, 18 Jul 2012 16:58:14 +0000 Received: from mail156-tx2 (localhost [127.0.0.1]) by mail156-tx2-R.bigfish.com (Postfix) with ESMTP id E1F4D2A00C8; Wed, 18 Jul 2012 16:58:13 +0000 (UTC) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-SpamScore: 0 X-BigFish: VS0(zzzz1202hzz8275dhz2dh87h2a8h668h839hd24he5bhe96hf0ah107ah) X-FB-DOMAIN-IP-MATCH: fail Received: from mail156-tx2 (localhost.localdomain [127.0.0.1]) by mail156-tx2 (MessageSwitch) id 1342630691535049_26340; Wed, 18 Jul 2012 16:58:11 +0000 (UTC) Received: from TX2EHSMHS039.bigfish.com (unknown [10.9.14.245]) by mail156-tx2.bigfish.com (Postfix) with ESMTP id 79F00100049; Wed, 18 Jul 2012 16:58:11 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by TX2EHSMHS039.bigfish.com (10.9.99.139) with Microsoft SMTP Server (TLS) id 14.1.225.23; Wed, 18 Jul 2012 16:58:10 +0000 Received: from az84smr01.freescale.net (10.64.34.197) by 039-SN1MMR1-001.039d.mgd.msft.net (10.84.1.13) with Microsoft SMTP Server (TLS) id 14.2.298.5; Wed, 18 Jul 2012 11:58:10 -0500 Received: from S2101-09.ap.freescale.net ([10.192.185.60]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id q6IGvvTF007919; Wed, 18 Jul 2012 09:57:58 -0700 From: Shawn Guo To: , , Subject: [PATCH] PM / OPP: Initialize OPP table from device tree Date: Thu, 19 Jul 2012 00:57:49 +0800 Message-ID: <1342630669-27546-1-git-send-email-shawn.guo@linaro.org> X-Mailer: git-send-email 1.7.5.4 MIME-Version: 1.0 X-OriginatorOrg: sigmatel.com X-Spam-Note: CRM114 invocation failed X-Spam-Score: -4.2 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [65.55.88.15 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Nishanth Menon , Kevin Hilman , Shawn Guo , "Rafael J. Wysocki" X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 --- Documentation/devicetree/bindings/power/opp.txt | 29 ++++++++++ drivers/base/power/opp.c | 66 +++++++++++++++++++++++ include/linux/opp.h | 4 ++ 3 files changed, 99 insertions(+), 0 deletions(-) create mode 100644 Documentation/devicetree/bindings/power/opp.txt diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt new file mode 100644 index 0000000..1dd0db2 --- /dev/null +++ b/Documentation/devicetree/bindings/power/opp.txt @@ -0,0 +1,29 @@ +* 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 3-tuples items, and each item consists + of frequency, voltage and enabling like . + freq: clock frequency in kHz + vol: voltage in microvolt + en: initially enabled (1) or not (0) + +Examples: + +cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV en */ + 1200000 1275000 0 + 996000 1225000 1 + 792000 1100000 1 + 672000 1100000 0 + 396000 950000 1 + 198000 850000 1 + >; +}; diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index ac993ea..2d750f9 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -22,6 +22,7 @@ #include #include #include +#include /* * Internal data structure organization with the OPP layer library is as @@ -674,3 +675,68 @@ 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) +{ + struct device_node *np = dev->of_node; + const char *propname = "operating-points"; + const struct property *pp; + u32 *opp; + int ret, i, nr; + + pp = of_find_property(np, propname, NULL); + if (!pp) { + dev_err(dev, "%s: Unable to find property", __func__); + return -ENODEV; + } + + opp = kzalloc(pp->length, GFP_KERNEL); + if (!opp) { + dev_err(dev, "%s: Unable to allocate array\n", __func__); + return -ENOMEM; + } + + nr = pp->length / sizeof(u32); + ret = of_property_read_u32_array(np, propname, opp, nr); + if (ret) { + dev_err(dev, "%s: Unable to read OPPs\n", __func__); + goto out; + } + + nr /= 3; + for (i = 0; i < nr; i++) { + /* + * Each OPP is a set of tuples consisting of frequency, + * voltage and availability like . + */ + u32 *val = opp + i * 3; + + val[0] *= 1000; + ret = opp_add(dev, val[0], val[1]); + if (ret) { + dev_warn(dev, "%s: Failed to add OPP %d: %d\n", + __func__, val[0], ret); + continue; + } + + if (!val[2]) { + ret = opp_disable(dev, val[0]); + if (ret) + dev_warn(dev, "%s: Failed to disable OPP %d: %d\n", + __func__, val[0], ret); + } + } + + ret = 0; +out: + kfree(opp); + return ret; +} +#endif diff --git a/include/linux/opp.h b/include/linux/opp.h index 2a4e5fa..fd165ad 100644 --- a/include/linux/opp.h +++ b/include/linux/opp.h @@ -48,6 +48,10 @@ 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); +#endif + #else static inline unsigned long opp_get_voltage(struct opp *opp) {