From f9f28cdf21679792c30d9f5eebd01b7e04fe658f Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 19 Apr 2014 10:58:22 +0800 Subject: [PATCH] ARM: imx: add shared gate clock support It's quite common on i.MX that one gate bit controls the gating of multiple clocks, i.e. this is a shared gate. The patch adds the function imx_clk_gate2_shared() for such case. The clocks controlled by the same gate bits should call this function with a pointer to a single share count variable, so that the gate bits will only be operated on the first enabling and the last disabling of these shared gate clocks. Thanks to Gerhard Sittig for this idea. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-gate2.c | 13 ++++++++++++- arch/arm/mach-imx/clk.h | 13 +++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c index 0803df9d9c7e..4ba587da89d2 100644 --- a/arch/arm/mach-imx/clk-gate2.c +++ b/arch/arm/mach-imx/clk-gate2.c @@ -33,6 +33,7 @@ struct clk_gate2 { u8 bit_idx; u8 flags; spinlock_t *lock; + unsigned int *share_count; }; #define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw) @@ -45,10 +46,14 @@ static int clk_gate2_enable(struct clk_hw *hw) spin_lock_irqsave(gate->lock, flags); + if (gate->share_count && (*gate->share_count)++ > 0) + goto out; + reg = readl(gate->reg); reg |= 3 << gate->bit_idx; writel(reg, gate->reg); +out: spin_unlock_irqrestore(gate->lock, flags); return 0; @@ -62,10 +67,14 @@ static void clk_gate2_disable(struct clk_hw *hw) spin_lock_irqsave(gate->lock, flags); + if (gate->share_count && --(*gate->share_count) > 0) + goto out; + reg = readl(gate->reg); reg &= ~(3 << gate->bit_idx); writel(reg, gate->reg); +out: spin_unlock_irqrestore(gate->lock, flags); } @@ -91,7 +100,8 @@ static struct clk_ops clk_gate2_ops = { struct clk *clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, - u8 clk_gate2_flags, spinlock_t *lock) + u8 clk_gate2_flags, spinlock_t *lock, + unsigned int *share_count) { struct clk_gate2 *gate; struct clk *clk; @@ -106,6 +116,7 @@ struct clk *clk_register_gate2(struct device *dev, const char *name, gate->bit_idx = bit_idx; gate->flags = clk_gate2_flags; gate->lock = lock; + gate->share_count = share_count; init.name = name; init.ops = &clk_gate2_ops; diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 048c5ad8a80b..e29f6ebe9f39 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -28,7 +28,8 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, struct clk *clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, - u8 clk_gate_flags, spinlock_t *lock); + u8 clk_gate_flags, spinlock_t *lock, + unsigned int *share_count); struct clk * imx_obtain_fixed_clock( const char *name, unsigned long rate); @@ -37,7 +38,15 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, - shift, 0, &imx_ccm_lock); + shift, 0, &imx_ccm_lock, NULL); +} + +static inline struct clk *imx_clk_gate2_shared(const char *name, + const char *parent, void __iomem *reg, u8 shift, + unsigned int *share_count) +{ + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &imx_ccm_lock, share_count); } struct clk *imx_clk_pfd(const char *name, const char *parent_name, -- 2.11.0