From patchwork Wed Jul 10 15:22:00 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shawn Guo X-Patchwork-Id: 2825759 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 869FFC0AB2 for ; Wed, 10 Jul 2013 15:23:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 289ED201BA for ; Wed, 10 Jul 2013 15:23:22 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7844A20137 for ; Wed, 10 Jul 2013 15:23:20 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UwwDP-0002je-DF; Wed, 10 Jul 2013 15:21:59 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UwwDD-0008Cj-Ae; Wed, 10 Jul 2013 15:21:47 +0000 Received: from co9ehsobe001.messaging.microsoft.com ([207.46.163.24] helo=co9outboundpool.messaging.microsoft.com) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UwwCt-00088l-JY for linux-arm-kernel@lists.infradead.org; Wed, 10 Jul 2013 15:21:32 +0000 Received: from mail17-co9-R.bigfish.com (10.236.132.225) by CO9EHSOBE023.bigfish.com (10.236.130.86) with Microsoft SMTP Server id 14.1.225.22; Wed, 10 Jul 2013 15:21:06 +0000 Received: from mail17-co9 (localhost [127.0.0.1]) by mail17-co9-R.bigfish.com (Postfix) with ESMTP id 699393802A2; Wed, 10 Jul 2013 15:21:06 +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(zzzz1f42h1ee6h1de0h1fdah2073h1202h1e76h1d1ah1d2ah1fc6hzz17326ah84d07h8275bh8275dhz2dh87h2a8h668h839hd24he5bhf0ah1288h12a5h12a9h12bdh12e5h137ah139eh13b6h1441h1504h1537h162dh1631h1758h1898h18e1h1946h19b5h1ad9h1b0ah1d0ch1d2eh1d3fh1dfeh1dffh1e23h1151h1155h) X-FB-DOMAIN-IP-MATCH: fail Received: from mail17-co9 (localhost.localdomain [127.0.0.1]) by mail17-co9 (MessageSwitch) id 1373469664632882_16048; Wed, 10 Jul 2013 15:21:04 +0000 (UTC) Received: from CO9EHSMHS009.bigfish.com (unknown [10.236.132.229]) by mail17-co9.bigfish.com (Postfix) with ESMTP id 972BC100269; Wed, 10 Jul 2013 15:21:04 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by CO9EHSMHS009.bigfish.com (10.236.130.19) with Microsoft SMTP Server (TLS) id 14.1.225.23; Wed, 10 Jul 2013 15:21:02 +0000 Received: from tx30smr01.am.freescale.net (10.81.153.31) by 039-SN1MMR1-005.039d.mgd.msft.net (10.84.1.17) with Microsoft SMTP Server (TLS) id 14.3.136.1; Wed, 10 Jul 2013 15:23:09 +0000 Received: from S2101-09.ap.freescale.net ([10.192.185.201]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id r6AFKpOl005241; Wed, 10 Jul 2013 08:20:54 -0700 From: Shawn Guo To: Subject: [PATCH 1/3] ARM: imx: add common clock support for fixup div Date: Wed, 10 Jul 2013 23:22:00 +0800 Message-ID: <1373469722-32514-2-git-send-email-shawn.guo@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1373469722-32514-1-git-send-email-shawn.guo@linaro.org> References: <1373469722-32514-1-git-send-email-shawn.guo@linaro.org> MIME-Version: 1.0 X-OriginatorOrg: sigmatel.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130710_112127_854479_193D62A5 X-CRM114-Status: GOOD ( 19.15 ) X-Spam-Score: -4.2 (----) Cc: Shawn Guo , Liu Ying , kernel@pengutronix.de X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Liu Ying One register may have several fields to control some clocks. It is possible that the read/write values of some fields may map to different real functional values, so writing to the other fields in the same register may break a working clock tree. A real case is the aclk_podf field in the register 'CCM Serial Clock Multiplexer Register 1' of i.MX6Q/SDL SoC. This patch introduces a fixup hook for divider clock which is called before writing a value to clock registers to support this kind of divider clocks. Signed-off-by: Liu Ying Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 3 +- arch/arm/mach-imx/clk-fixup-div.c | 129 +++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk.h | 4 ++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/clk-fixup-div.c diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index e20f22d..92b91a2 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -15,7 +15,8 @@ imx5-pm-$(CONFIG_PM) += pm-imx5.o obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o $(imx5-pm-y) obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ - clk-pfd.o clk-busy.o clk.o + clk-pfd.o clk-busy.o clk.o \ + clk-fixup-div.o obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o diff --git a/arch/arm/mach-imx/clk-fixup-div.c b/arch/arm/mach-imx/clk-fixup-div.c new file mode 100644 index 0000000..21db020 --- /dev/null +++ b/arch/arm/mach-imx/clk-fixup-div.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include "clk.h" + +#define to_clk_div(_hw) container_of(_hw, struct clk_divider, hw) +#define div_mask(d) ((1 << (d->width)) - 1) + +/** + * struct clk_fixup_div - imx integer fixup divider clock + * @divider: the parent class + * @ops: pointer to clk_ops of parent class + * @fixup: a hook to fixup the write value + * + * The imx fixup divider clock is a subclass of basic clk_divider + * with an addtional fixup hook. + */ +struct clk_fixup_div { + struct clk_divider divider; + const struct clk_ops *ops; + void (*fixup)(u32 *val); +}; + +static inline struct clk_fixup_div *to_clk_fixup_div(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_div(hw); + + return container_of(divider, struct clk_fixup_div, divider); +} + +static unsigned long clk_fixup_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); + + return fixup_div->ops->recalc_rate(&fixup_div->divider.hw, parent_rate); +} + +static long clk_fixup_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); + + return fixup_div->ops->round_rate(&fixup_div->divider.hw, rate, prate); +} + +static int clk_fixup_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); + struct clk_divider *div = to_clk_div(hw); + unsigned int divider, value; + unsigned long flags = 0; + u32 val; + + divider = parent_rate / rate; + + /* Zero based divider */ + value = divider - 1; + + if (value > div_mask(div)) + value = div_mask(div); + + spin_lock_irqsave(div->lock, flags); + + val = readl(div->reg); + val &= ~(div_mask(div) << div->shift); + val |= value << div->shift; + fixup_div->fixup(&val); + writel(val, div->reg); + + spin_unlock_irqrestore(div->lock, flags); + + return 0; +} + +static const struct clk_ops clk_fixup_div_ops = { + .recalc_rate = clk_fixup_div_recalc_rate, + .round_rate = clk_fixup_div_round_rate, + .set_rate = clk_fixup_div_set_rate, +}; + +struct clk *imx_clk_fixup_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, + void (*fixup)(u32 *val)) +{ + struct clk_fixup_div *fixup_div; + struct clk *clk; + struct clk_init_data init; + + if (!fixup) + return ERR_PTR(-EINVAL); + + fixup_div = kzalloc(sizeof(*fixup_div), GFP_KERNEL); + if (!fixup_div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_fixup_div_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = parent ? &parent : NULL; + init.num_parents = parent ? 1 : 0; + + fixup_div->divider.reg = reg; + fixup_div->divider.shift = shift; + fixup_div->divider.width = width; + fixup_div->divider.lock = &imx_ccm_lock; + fixup_div->divider.hw.init = &init; + fixup_div->ops = &clk_divider_ops; + fixup_div->fixup = fixup; + + clk = clk_register(NULL, &fixup_div->divider.hw); + if (IS_ERR(clk)) + kfree(fixup_div); + + return clk; +} diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 0e4e8bb..51eb3853 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -49,6 +49,10 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, u8 width, void __iomem *busy_reg, u8 busy_shift, const char **parent_names, int num_parents); +struct clk *imx_clk_fixup_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width, + void (*fixup)(u32 *val)); + static inline struct clk *imx_clk_fixed(const char *name, int rate) { return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);