diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-08 13:51:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-08 13:51:30 -0500 |
commit | 7bffc48177ed461ab29cbae1102552a09601ef97 (patch) | |
tree | d9cbfb43ddb8503e25591064570b7bde43c92f22 /drivers/clk | |
parent | abfba60c7a81b12236a07da4cbaf75a0e30040cd (diff) | |
parent | d9120198ddef2c0b61ca6659ace41b7c1e7c8f08 (diff) |
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
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/shmobile/clk-rcar-gen2.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c index dd272a0d1446..99c27b1c625b 100644 --- a/drivers/clk/shmobile/clk-rcar-gen2.c +++ b/drivers/clk/shmobile/clk-rcar-gen2.c | |||
@@ -26,6 +26,8 @@ struct rcar_gen2_cpg { | |||
26 | void __iomem *reg; | 26 | void __iomem *reg; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | #define CPG_FRQCRB 0x00000004 | ||
30 | #define CPG_FRQCRB_KICK BIT(31) | ||
29 | #define CPG_SDCKCR 0x00000074 | 31 | #define CPG_SDCKCR 0x00000074 |
30 | #define CPG_PLL0CR 0x000000d8 | 32 | #define CPG_PLL0CR 0x000000d8 |
31 | #define CPG_FRQCRC 0x000000e0 | 33 | #define CPG_FRQCRC 0x000000e0 |
@@ -45,6 +47,7 @@ struct rcar_gen2_cpg { | |||
45 | struct cpg_z_clk { | 47 | struct cpg_z_clk { |
46 | struct clk_hw hw; | 48 | struct clk_hw hw; |
47 | void __iomem *reg; | 49 | void __iomem *reg; |
50 | void __iomem *kick_reg; | ||
48 | }; | 51 | }; |
49 | 52 | ||
50 | #define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) | 53 | #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 | { | 86 | { |
84 | struct cpg_z_clk *zclk = to_z_clk(hw); | 87 | struct cpg_z_clk *zclk = to_z_clk(hw); |
85 | unsigned int mult; | 88 | unsigned int mult; |
86 | u32 val; | 89 | u32 val, kick; |
90 | unsigned int i; | ||
87 | 91 | ||
88 | mult = div_u64((u64)rate * 32, parent_rate); | 92 | mult = div_u64((u64)rate * 32, parent_rate); |
89 | mult = clamp(mult, 1U, 32U); | 93 | mult = clamp(mult, 1U, 32U); |
90 | 94 | ||
95 | if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK) | ||
96 | return -EBUSY; | ||
97 | |||
91 | val = clk_readl(zclk->reg); | 98 | val = clk_readl(zclk->reg); |
92 | val &= ~CPG_FRQCRC_ZFC_MASK; | 99 | val &= ~CPG_FRQCRC_ZFC_MASK; |
93 | val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; | 100 | val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; |
94 | clk_writel(val, zclk->reg); | 101 | clk_writel(val, zclk->reg); |
95 | 102 | ||
96 | return 0; | 103 | /* |
104 | * Set KICK bit in FRQCRB to update hardware setting and wait for | ||
105 | * clock change completion. | ||
106 | */ | ||
107 | kick = clk_readl(zclk->kick_reg); | ||
108 | kick |= CPG_FRQCRB_KICK; | ||
109 | clk_writel(kick, zclk->kick_reg); | ||
110 | |||
111 | /* | ||
112 | * Note: There is no HW information about the worst case latency. | ||
113 | * | ||
114 | * Using experimental measurements, it seems that no more than | ||
115 | * ~10 iterations are needed, independently of the CPU rate. | ||
116 | * Since this value might be dependant of external xtal rate, pll1 | ||
117 | * rate or even the other emulation clocks rate, use 1000 as a | ||
118 | * "super" safe value. | ||
119 | */ | ||
120 | for (i = 1000; i; i--) { | ||
121 | if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) | ||
122 | return 0; | ||
123 | |||
124 | cpu_relax(); | ||
125 | } | ||
126 | |||
127 | return -ETIMEDOUT; | ||
97 | } | 128 | } |
98 | 129 | ||
99 | static const struct clk_ops cpg_z_clk_ops = { | 130 | 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 | init.num_parents = 1; | 151 | init.num_parents = 1; |
121 | 152 | ||
122 | zclk->reg = cpg->reg + CPG_FRQCRC; | 153 | zclk->reg = cpg->reg + CPG_FRQCRC; |
154 | zclk->kick_reg = cpg->reg + CPG_FRQCRB; | ||
123 | zclk->hw.init = &init; | 155 | zclk->hw.init = &init; |
124 | 156 | ||
125 | clk = clk_register(NULL, &zclk->hw); | 157 | clk = clk_register(NULL, &zclk->hw); |