diff options
| -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); |
