From patchwork Tue Apr 10 13:45:38 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 151578 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 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 5251EB6FE9 for ; Wed, 11 Apr 2012 00:00:57 +1000 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1SHbaz-0002yU-LH; Tue, 10 Apr 2012 13:58:57 +0000 Received: from 173-166-109-252-newengland.hfc.comcastbusiness.net ([173.166.109.252] helo=bombadil.infradead.org) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1SHbP6-0005ua-Px for linux-arm-kernel@merlin.infradead.org; Tue, 10 Apr 2012 13:46:40 +0000 Received: from metis.ext.pengutronix.de ([2001:6f8:1178:4:290:27ff:fe1d:cc33]) by bombadil.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1SHbP5-0001qW-BI for linux-arm-kernel@lists.infradead.org; Tue, 10 Apr 2012 13:46:40 +0000 Received: from dude.hi.pengutronix.de ([2001:6f8:1178:2:21e:67ff:fe11:9c5c]) by metis.ext.pengutronix.de with esmtp (Exim 4.72) (envelope-from ) id 1SHbOc-0005iE-Mr; Tue, 10 Apr 2012 15:46:10 +0200 Received: from sha by dude.hi.pengutronix.de with local (Exim 4.77) (envelope-from ) id 1SHbOb-0003Cn-K2; Tue, 10 Apr 2012 15:46:09 +0200 From: Sascha Hauer To: Subject: [PATCH 25/40] ARM: imx: add common clock support for clk busy Date: Tue, 10 Apr 2012 15:45:38 +0200 Message-Id: <1334065553-7565-26-git-send-email-s.hauer@pengutronix.de> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1334065553-7565-1-git-send-email-s.hauer@pengutronix.de> References: <1334065553-7565-1-git-send-email-s.hauer@pengutronix.de> X-SA-Exim-Connect-IP: 2001:6f8:1178:2:21e:67ff:fe11:9c5c X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-arm-kernel@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20120410_094639_772316_A0F93898 X-CRM114-Status: GOOD ( 18.37 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on bombadil.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 T_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] Cc: Shawn Guo , Fabio Estevam X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org From: Shawn Guo Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 2 +- arch/arm/mach-imx/clk-busy.c | 167 ++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-imx/clk.h | 8 ++ 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/clk-busy.c diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 4d6be8d..ae0a779 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o pm-i obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ - clk-pfd.o + clk-pfd.o clk-busy.o # Support for CMOS sensor interface obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o diff --git a/arch/arm/mach-imx/clk-busy.c b/arch/arm/mach-imx/clk-busy.c new file mode 100644 index 0000000..9450f0b --- /dev/null +++ b/arch/arm/mach-imx/clk-busy.c @@ -0,0 +1,167 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * 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 +#include "clk.h" + +static int clk_busy_wait(void __iomem *reg, u8 shift) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + + while (readl_relaxed(reg) & (1 << shift)) + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} + +struct clk_busy_divider { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + struct clk_divider div; + const struct clk_ops *div_ops; +}; + +#define to_clk_busy_divider(_hw) container_of(_hw, struct clk_busy_divider, hw) + +static unsigned long clk_busy_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + + return busy->div_ops->recalc_rate(&busy->div.hw, parent_rate); +} + +static long clk_busy_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + + return busy->div_ops->round_rate(&busy->div.hw, rate, prate); +} + +static int clk_busy_divider_set_rate(struct clk_hw *hw, unsigned long rate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + int ret; + + ret = busy->div_ops->set_rate(&busy->div.hw, rate); + if (!ret) + ret = clk_busy_wait(busy->reg, busy->shift); + + return ret; +} + +static struct clk_ops clk_busy_divider_ops = { + .recalc_rate = clk_busy_divider_recalc_rate, + .round_rate = clk_busy_divider_round_rate, + .set_rate = clk_busy_divider_set_rate, +}; + +struct clk *imx_clk_busy_divider(const char *name, char *parent_name, + void __iomem *reg, u8 shift, u8 width, + void __iomem *busy_reg, u8 busy_shift) +{ + struct clk_busy_divider *busy; + struct clk *clk; + + busy = kzalloc(sizeof(*busy), GFP_KERNEL); + if (!busy) + return NULL; + + busy->reg = busy_reg; + busy->shift = busy_shift; + + busy->div.reg = reg; + busy->div.shift = shift; + busy->div.width = width; + busy->div.lock = &imx_ccm_lock; + busy->div_ops = &clk_divider_ops; + + clk = clk_register(NULL, name, &clk_busy_divider_ops, &busy->hw, + &parent_name, 1, CLK_SET_RATE_PARENT); + if (!clk) + kfree(busy); + + busy->div.hw.clk = clk; + + return clk; +} + +struct clk_busy_mux { + struct clk_hw hw; + void __iomem *reg; + u8 shift; + struct clk_mux mux; + const struct clk_ops *mux_ops; +}; + +#define to_clk_busy_mux(_hw) container_of(_hw, struct clk_busy_mux, hw) + +static u8 clk_busy_mux_get_parent(struct clk_hw *hw) +{ + struct clk_busy_mux *busy = to_clk_busy_mux(hw); + + return busy->mux_ops->get_parent(&busy->mux.hw); +} + +static int clk_busy_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_busy_mux *busy = to_clk_busy_mux(hw); + int ret; + + ret = busy->mux_ops->set_parent(&busy->mux.hw, index); + if (!ret) + ret = clk_busy_wait(busy->reg, busy->shift); + + return ret; +} + +struct clk_ops clk_busy_mux_ops = { + .get_parent = clk_busy_mux_get_parent, + .set_parent = clk_busy_mux_set_parent, +}; + +struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, + u8 width, void __iomem *busy_reg, u8 busy_shift, + char **parent_names, int num_parents) +{ + struct clk_busy_mux *busy; + struct clk *clk; + + busy = kzalloc(sizeof(*busy), GFP_KERNEL); + if (!busy) + return NULL; + + busy->reg = busy_reg; + busy->shift = busy_shift; + + busy->mux.reg = reg; + busy->mux.shift = shift; + busy->mux.width = width; + busy->mux.lock = &imx_ccm_lock; + busy->mux_ops = &clk_mux_ops; + + clk = clk_register(NULL, name, &clk_busy_mux_ops, &busy->hw, + parent_names, num_parents, 0); + if (!clk) + kfree(busy); + + busy->mux.hw.clk = clk; + + return clk; +} diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 50f5638..53ab2f5 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -44,6 +44,10 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent, reg, shift, width, 0, &imx_ccm_lock); } +struct clk *imx_clk_busy_divider(const char *name, char *parent_name, + void __iomem *reg, u8 shift, u8 width, + void __iomem *busy_reg, u8 busy_shift); + static inline struct clk *imx_clk_gate(const char *name, const char *parent, void __iomem *reg, u8 shift) { @@ -65,6 +69,10 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, width, 0, &imx_ccm_lock); } +struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, + u8 width, void __iomem *busy_reg, u8 busy_shift, + char **parent_names, int num_parents); + static inline struct clk *imx_clk_fixed_factor(const char *name, const char *parent, unsigned int mult, unsigned int div) {