From patchwork Tue Mar 19 17:09:33 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Fuzzey X-Patchwork-Id: 229146 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 17EA82C00DC for ; Wed, 20 Mar 2013 04:12:34 +1100 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UI02e-0006Ce-4J; Tue, 19 Mar 2013 17:09:40 +0000 Received: from mta1.parkeon.com ([91.121.43.66]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UI02a-0006Bv-RX for linux-arm-kernel@lists.infradead.org; Tue, 19 Mar 2013 17:09:37 +0000 Received: from [213.152.31.71] (helo=mta2.parkeon.com) by mta1.parkeon.com with esmtp (Exim 4.76) (envelope-from ) id 1UI02X-0005Cg-Mx; Tue, 19 Mar 2013 18:09:33 +0100 Received: from [10.32.16.23] (helo=mail.besancon.parkeon.com) by mta2.parkeon.com with esmtp (Exim 4.77) (envelope-from ) id 1UI02U-0000K9-FT; Tue, 19 Mar 2013 18:09:30 +0100 Received: from [10.32.51.221] (port=59836 helo=[127.0.0.1]) by mail.besancon.parkeon.com with esmtp (Exim 4.71) (envelope-from ) id 1UI02X-00020j-Gw; Tue, 19 Mar 2013 18:09:33 +0100 Subject: [RFC PATCH] CLK: Allow parent clock and rate to be configured in DT. To: Sascha Hauer , devicetree-discuss@lists.ozlabs.org, linux-arm-kernel@lists.infradead.org, Mike Turquette From: Martin Fuzzey Date: Tue, 19 Mar 2013 18:09:33 +0100 Message-ID: <20130319170933.28337.50448.stgit@localhost> User-Agent: StGit/0.15 MIME-Version: 1.0 X-Virus-Scanned: by ClamAV at mta2.parkeon.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130319_130936_997940_D85474D2 X-CRM114-Status: GOOD ( 19.91 ) X-Spam-Score: -4.4 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -2.5 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Even on platforms where the entire clock tree is not represented in the DT it can still be useful to allow parents and rates to be set from the DT. An example of such a case is when a multiplexable clock output from a SOC is used to supply external chips (eg an audio codec connected to the i.MX53 cko1 pin). The cko1 pin can output various internal clock signals but, in order to obtain a suitable frequency for the codec, an appropriate parent must be selected. Another example is setting root clock dividers. This is board specific rather than device driver or platform clock framework specific information and thus would be better in the DT. Signed-off-by: Martin Fuzzey --- Sending as RFC for the moment in a single patch together with an example for i.MX53. Will split if this goes anywhere. --- .../bindings/clock/clock-configuration.txt | 35 +++++++++ arch/arm/mach-imx/clk-imx51-imx53.c | 9 +- drivers/clk/Makefile | 1 drivers/clk/clk-configuration.c | 79 ++++++++++++++++++++ include/linux/clk.h | 5 + 5 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/clock-configuration.txt create mode 100644 drivers/clk/clk-configuration.c diff --git a/Documentation/devicetree/bindings/clock/clock-configuration.txt b/Documentation/devicetree/bindings/clock/clock-configuration.txt new file mode 100644 index 0000000..482b0ff --- /dev/null +++ b/Documentation/devicetree/bindings/clock/clock-configuration.txt @@ -0,0 +1,35 @@ +This binding allows clocks to configured by setting their parent and/or rate. + +Configurations are specified subnodes of nodes with +compatible="clock-configuration" + +The subnode properties are: + +Required properties: +clocks: phandle of clock to configure in clock consumer format + +Optional properties: +parent: phandle of clock to use as parent in clock consumer format +clock-rate: clock rate to use + + +For example: + clock-configuration { + compatible = "clock-configuration"; + clko1 { + clocks = <&clks 160>; /* cko1_sel */ + parent = <&clks 114>; /* pll3_sw */ + }; + + esdhca { + clocks = <&clks 102>; /* esdhc_a_podf */ + clock-frequency = <200000000>; + }; + + esdhcb { + clocks = <&clks 103>; /* esdhc_b_podf */ + clock-frequency = <200000000>; + }; + }; + + diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 872a7bc..fd74795 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -432,7 +432,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, val |= 1 << 23; writel(val, MXC_CCM_CLPCR); - return 0; + return of_clk_configure(); } int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, @@ -523,10 +523,6 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.3"); clk_register_clkdev(clk[esdhc4_per_gate], "per", "sdhci-esdhc-imx53.3"); - /* set SDHC root clock to 200MHZ*/ - clk_set_rate(clk[esdhc_a_podf], 200000000); - clk_set_rate(clk[esdhc_b_podf], 200000000); - /* System timer */ mxc_timer_init(MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), MX53_INT_GPT); @@ -536,8 +532,7 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, r = clk_round_rate(clk[usboh3_per_gate], 54000000); clk_set_rate(clk[usboh3_per_gate], r); - - return 0; + return of_clk_configure(); } #ifdef CONFIG_OF diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 300d477..bf364dd 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o +obj-$(CONFIG_COMMON_CLK) += clk-configuration.o # SoCs specific obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o diff --git a/drivers/clk/clk-configuration.c b/drivers/clk/clk-configuration.c new file mode 100644 index 0000000..ee70619 --- /dev/null +++ b/drivers/clk/clk-configuration.c @@ -0,0 +1,79 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Device tree clock parent, rate configuration + */ + +#include +#include + + +static int configure_one_clock(struct clk *clk, struct device_node *np) +{ + int ret; + struct of_phandle_args clkspec; + struct clk *parent; + u32 rate; + + ret = of_parse_phandle_with_args(np, "parent", "#clock-cells", 0, + &clkspec); + if (!ret) { + parent = of_clk_get_from_provider(&clkspec); + if (!IS_ERR(parent)) { + ret = clk_set_parent(clk, parent); + clk_put(parent); + } + of_node_put(clkspec.np); + if (ret) + goto err; + } + + ret = 0; + if (!of_property_read_u32(np, "clock-frequency", &rate)) + ret = clk_set_rate(clk, rate); + +err: + return ret; + +} + +/** + * of_clk_configure - configure clocks from device tree + * + * Allows parent and rate to be set from nodes having + * clock-configuration compatible property. + * + * See binding documentation for example + * + * Returns 0 on success, -EERROR otherwise. + */ +int of_clk_configure() +{ + struct device_node *config_node, *np; + struct clk *clk; + int err_count = 0; + int ret = 0; + + for_each_compatible_node(config_node, NULL, "clock-configuration") { + for_each_child_of_node(config_node, np) { + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_warn("%s: Failed to obtain clock configuration for %s : %d\n", __func__, np->name); + err_count++; + } else { + if (configure_one_clock(clk, np)) + err_count++; + clk_put(clk); + } + } + } + + if (err_count) { + pr_warn("%s: Failed %d clocks\n", __func__, err_count); + ret = -EINVAL; + } + return ret; +} +EXPORT_SYMBOL_GPL(of_clk_configure); diff --git a/include/linux/clk.h b/include/linux/clk.h index b3ac22d..4f7f605 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -368,6 +368,7 @@ struct of_phandle_args; struct clk *of_clk_get(struct device_node *np, int index); struct clk *of_clk_get_by_name(struct device_node *np, const char *name); struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec); +int of_clk_configure(void); #else static inline struct clk *of_clk_get(struct device_node *np, int index) { @@ -378,6 +379,10 @@ static inline struct clk *of_clk_get_by_name(struct device_node *np, { return ERR_PTR(-ENOENT); } +static inline int of_clk_configure(void) +{ + return 0; +} #endif #endif