Skip to content

Commit

Permalink
Merge tag 'clk-fixes-for-linus' of git://git.linaro.org/people/mike.t…
Browse files Browse the repository at this point in the history
…urquette/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
  • Loading branch information
Linus Torvalds committed Mar 8, 2014
2 parents abfba60 + d912019 commit 7bffc48
Showing 1 changed file with 34 additions and 2 deletions.
36 changes: 34 additions & 2 deletions drivers/clk/shmobile/clk-rcar-gen2.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ struct rcar_gen2_cpg {
void __iomem *reg;
};

#define CPG_FRQCRB 0x00000004
#define CPG_FRQCRB_KICK BIT(31)
#define CPG_SDCKCR 0x00000074
#define CPG_PLL0CR 0x000000d8
#define CPG_FRQCRC 0x000000e0
Expand All @@ -45,6 +47,7 @@ struct rcar_gen2_cpg {
struct cpg_z_clk {
struct clk_hw hw;
void __iomem *reg;
void __iomem *kick_reg;
};

#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
Expand Down Expand Up @@ -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);
unsigned int mult;
u32 val;
u32 val, kick;
unsigned int i;

mult = div_u64((u64)rate * 32, parent_rate);
mult = clamp(mult, 1U, 32U);

if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
return -EBUSY;

val = clk_readl(zclk->reg);
val &= ~CPG_FRQCRC_ZFC_MASK;
val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
clk_writel(val, zclk->reg);

return 0;
/*
* 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;

cpu_relax();
}

return -ETIMEDOUT;
}

static const struct clk_ops cpg_z_clk_ops = {
Expand All @@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
init.num_parents = 1;

zclk->reg = cpg->reg + CPG_FRQCRC;
zclk->kick_reg = cpg->reg + CPG_FRQCRB;
zclk->hw.init = &init;

clk = clk_register(NULL, &zclk->hw);
Expand Down

0 comments on commit 7bffc48

Please sign in to comment.