aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEddie James <eajames@linux.vnet.ibm.com>2018-03-08 15:57:20 -0500
committerStephen Boyd <sboyd@kernel.org>2018-03-15 14:13:49 -0400
commit8a53fc511c5ec81347b981b438f68c3dde421608 (patch)
tree918902c319d8490b2c99b182f6d26b1f5450ab68
parentd90c76bb61128ed9022b9418c31c4749764b6cd9 (diff)
clk: aspeed: Prevent reset if clock is enabled
According to the Aspeed specification, the reset and enable sequence should be done when the clock is stopped. The specification doesn't define behavior if the reset is done while the clock is enabled. From testing on the AST2500, the LPC Controller has problems if the clock is reset while enabled. Therefore, check whether the clock is enabled or not before performing the reset and enable sequence in the Aspeed clock driver. Reported-by: Lei Yu <mine260309@gmail.com> Signed-off-by: Eddie James <eajames@linux.vnet.ibm.com> Fixes: 15ed8ce5f84e ("clk: aspeed: Register gated clocks") Reviewed-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r--drivers/clk/clk-aspeed.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index 168777175cd1..5eb50c31e455 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -205,6 +205,18 @@ static const struct aspeed_clk_soc_data ast2400_data = {
205 .calc_pll = aspeed_ast2400_calc_pll, 205 .calc_pll = aspeed_ast2400_calc_pll,
206}; 206};
207 207
208static int aspeed_clk_is_enabled(struct clk_hw *hw)
209{
210 struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
211 u32 clk = BIT(gate->clock_idx);
212 u32 enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk;
213 u32 reg;
214
215 regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, &reg);
216
217 return ((reg & clk) == enval) ? 1 : 0;
218}
219
208static int aspeed_clk_enable(struct clk_hw *hw) 220static int aspeed_clk_enable(struct clk_hw *hw)
209{ 221{
210 struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw); 222 struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
@@ -215,6 +227,11 @@ static int aspeed_clk_enable(struct clk_hw *hw)
215 227
216 spin_lock_irqsave(gate->lock, flags); 228 spin_lock_irqsave(gate->lock, flags);
217 229
230 if (aspeed_clk_is_enabled(hw)) {
231 spin_unlock_irqrestore(gate->lock, flags);
232 return 0;
233 }
234
218 if (gate->reset_idx >= 0) { 235 if (gate->reset_idx >= 0) {
219 /* Put IP in reset */ 236 /* Put IP in reset */
220 regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst); 237 regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst);
@@ -255,18 +272,6 @@ static void aspeed_clk_disable(struct clk_hw *hw)
255 spin_unlock_irqrestore(gate->lock, flags); 272 spin_unlock_irqrestore(gate->lock, flags);
256} 273}
257 274
258static int aspeed_clk_is_enabled(struct clk_hw *hw)
259{
260 struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
261 u32 clk = BIT(gate->clock_idx);
262 u32 enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk;
263 u32 reg;
264
265 regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, &reg);
266
267 return ((reg & clk) == enval) ? 1 : 0;
268}
269
270static const struct clk_ops aspeed_clk_gate_ops = { 275static const struct clk_ops aspeed_clk_gate_ops = {
271 .enable = aspeed_clk_enable, 276 .enable = aspeed_clk_enable,
272 .disable = aspeed_clk_disable, 277 .disable = aspeed_clk_disable,