Commit 7bffc481 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-fixes-for-linus' of git://git.linaro.org/people/mike.turquette/linux

Pull clk driver fix from Mike Turquette:
 "Single fix for a clock driver merged in 3.14-rc1.  Without this fix
  the CPU frequency cannot be scaled"

* tag 'clk-fixes-for-linus' of git://git.linaro.org/people/mike.turquette/linux:
  clk: shmobile: rcar-gen2: Use kick bit to allow Z clock frequency change
parents abfba60c d9120198
...@@ -26,6 +26,8 @@ struct rcar_gen2_cpg { ...@@ -26,6 +26,8 @@ struct rcar_gen2_cpg {
void __iomem *reg; void __iomem *reg;
}; };
#define CPG_FRQCRB 0x00000004
#define CPG_FRQCRB_KICK BIT(31)
#define CPG_SDCKCR 0x00000074 #define CPG_SDCKCR 0x00000074
#define CPG_PLL0CR 0x000000d8 #define CPG_PLL0CR 0x000000d8
#define CPG_FRQCRC 0x000000e0 #define CPG_FRQCRC 0x000000e0
...@@ -45,6 +47,7 @@ struct rcar_gen2_cpg { ...@@ -45,6 +47,7 @@ struct rcar_gen2_cpg {
struct cpg_z_clk { struct cpg_z_clk {
struct clk_hw hw; struct clk_hw hw;
void __iomem *reg; void __iomem *reg;
void __iomem *kick_reg;
}; };
#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) #define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
...@@ -83,17 +86,45 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -83,17 +86,45 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
{ {
struct cpg_z_clk *zclk = to_z_clk(hw); struct cpg_z_clk *zclk = to_z_clk(hw);
unsigned int mult; unsigned int mult;
u32 val; u32 val, kick;
unsigned int i;
mult = div_u64((u64)rate * 32, parent_rate); mult = div_u64((u64)rate * 32, parent_rate);
mult = clamp(mult, 1U, 32U); mult = clamp(mult, 1U, 32U);
if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
return -EBUSY;
val = clk_readl(zclk->reg); val = clk_readl(zclk->reg);
val &= ~CPG_FRQCRC_ZFC_MASK; val &= ~CPG_FRQCRC_ZFC_MASK;
val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
clk_writel(val, zclk->reg); clk_writel(val, zclk->reg);
/*
* Set KICK bit in FRQCRB to update hardware setting and wait for
* clock change completion.
*/
kick = clk_readl(zclk->kick_reg);
kick |= CPG_FRQCRB_KICK;
clk_writel(kick, zclk->kick_reg);
/*
* Note: There is no HW information about the worst case latency.
*
* Using experimental measurements, it seems that no more than
* ~10 iterations are needed, independently of the CPU rate.
* Since this value might be dependant of external xtal rate, pll1
* rate or even the other emulation clocks rate, use 1000 as a
* "super" safe value.
*/
for (i = 1000; i; i--) {
if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
return 0; return 0;
cpu_relax();
}
return -ETIMEDOUT;
} }
static const struct clk_ops cpg_z_clk_ops = { static const struct clk_ops cpg_z_clk_ops = {
...@@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg) ...@@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
init.num_parents = 1; init.num_parents = 1;
zclk->reg = cpg->reg + CPG_FRQCRC; zclk->reg = cpg->reg + CPG_FRQCRC;
zclk->kick_reg = cpg->reg + CPG_FRQCRB;
zclk->hw.init = &init; zclk->hw.init = &init;
clk = clk_register(NULL, &zclk->hw); clk = clk_register(NULL, &zclk->hw);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment