diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2017-09-05 05:32:40 -0400 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2017-12-21 21:07:11 -0500 |
commit | 063578dc5f407f67d149133818efabe457daafda (patch) | |
tree | cf1ab0b9a47d56e7601b1fef2ae598aaae29cf25 | |
parent | 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff) |
clk: axi-clkgen: Correctly handle nocount bit in recalc_rate()
If the nocount bit is set the divider is bypassed and the settings for the
divider count should be ignored and a divider value of 1 should be assumed.
Handle this correctly in the driver recalc_rate() callback.
While the driver sets up the part so that the read back dividers values
yield the correct result the power-on reset settings of the part might not
reflect this and hence calling e.g. clk_get_rate() without prior calls to
clk_set_rate() will yield the wrong result.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-rw-r--r-- | drivers/clk/clk-axi-clkgen.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 5e918e7afaba..95a6e9834392 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c | |||
@@ -40,6 +40,10 @@ | |||
40 | #define MMCM_REG_FILTER1 0x4e | 40 | #define MMCM_REG_FILTER1 0x4e |
41 | #define MMCM_REG_FILTER2 0x4f | 41 | #define MMCM_REG_FILTER2 0x4f |
42 | 42 | ||
43 | #define MMCM_CLKOUT_NOCOUNT BIT(6) | ||
44 | |||
45 | #define MMCM_CLK_DIV_NOCOUNT BIT(12) | ||
46 | |||
43 | struct axi_clkgen { | 47 | struct axi_clkgen { |
44 | void __iomem *base; | 48 | void __iomem *base; |
45 | struct clk_hw clk_hw; | 49 | struct clk_hw clk_hw; |
@@ -315,12 +319,27 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, | |||
315 | unsigned int reg; | 319 | unsigned int reg; |
316 | unsigned long long tmp; | 320 | unsigned long long tmp; |
317 | 321 | ||
318 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®); | 322 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_2, ®); |
319 | dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); | 323 | if (reg & MMCM_CLKOUT_NOCOUNT) { |
324 | dout = 1; | ||
325 | } else { | ||
326 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®); | ||
327 | dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); | ||
328 | } | ||
329 | |||
320 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®); | 330 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®); |
321 | d = (reg & 0x3f) + ((reg >> 6) & 0x3f); | 331 | if (reg & MMCM_CLK_DIV_NOCOUNT) |
322 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®); | 332 | d = 1; |
323 | m = (reg & 0x3f) + ((reg >> 6) & 0x3f); | 333 | else |
334 | d = (reg & 0x3f) + ((reg >> 6) & 0x3f); | ||
335 | |||
336 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB2, ®); | ||
337 | if (reg & MMCM_CLKOUT_NOCOUNT) { | ||
338 | m = 1; | ||
339 | } else { | ||
340 | axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®); | ||
341 | m = (reg & 0x3f) + ((reg >> 6) & 0x3f); | ||
342 | } | ||
324 | 343 | ||
325 | if (d == 0 || dout == 0) | 344 | if (d == 0 || dout == 0) |
326 | return 0; | 345 | return 0; |