diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2015-10-12 09:52:50 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-12-15 03:42:48 -0500 |
commit | 179c8fb3c2a6cc86cc746e6d071be00f611328de (patch) | |
tree | eb7fb7c6c342de2ac1d32d3e4cebb922ff42ca3d | |
parent | 2b749cb3a5153fc4c312e405ecca8a925e6632c8 (diff) |
clk: versatile-icst: convert to use regmap
Instead of passing around register bases, pass around a regmap
in this driver. This refactoring make things so much easier when
we later want to manage an ICST that is part of a syscon.
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc: linux-clk@vger.kernel.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/clk/versatile/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-icst.c | 88 |
2 files changed, 61 insertions, 28 deletions
diff --git a/drivers/clk/versatile/Kconfig b/drivers/clk/versatile/Kconfig index fc50b6264bed..e733385bca9f 100644 --- a/drivers/clk/versatile/Kconfig +++ b/drivers/clk/versatile/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config COMMON_CLK_VERSATILE | 1 | config COMMON_CLK_VERSATILE |
2 | bool "Clock driver for ARM Reference designs" | 2 | bool "Clock driver for ARM Reference designs" |
3 | depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64 || COMPILE_TEST | 3 | depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64 || COMPILE_TEST |
4 | select REGMAP_MMIO | ||
4 | ---help--- | 5 | ---help--- |
5 | Supports clocking on ARM Reference designs: | 6 | Supports clocking on ARM Reference designs: |
6 | - Integrator/AP and Integrator/CP | 7 | - Integrator/AP and Integrator/CP |
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 08c5ee976879..80e955ac6ef5 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c | |||
@@ -19,9 +19,13 @@ | |||
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/clk-provider.h> | 20 | #include <linux/clk-provider.h> |
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | #include <linux/regmap.h> | ||
22 | 23 | ||
23 | #include "clk-icst.h" | 24 | #include "clk-icst.h" |
24 | 25 | ||
26 | /* Magic unlocking token used on all Versatile boards */ | ||
27 | #define VERSATILE_LOCK_VAL 0xA05F | ||
28 | |||
25 | /** | 29 | /** |
26 | * struct clk_icst - ICST VCO clock wrapper | 30 | * struct clk_icst - ICST VCO clock wrapper |
27 | * @hw: corresponding clock hardware entry | 31 | * @hw: corresponding clock hardware entry |
@@ -32,8 +36,9 @@ | |||
32 | */ | 36 | */ |
33 | struct clk_icst { | 37 | struct clk_icst { |
34 | struct clk_hw hw; | 38 | struct clk_hw hw; |
35 | void __iomem *vcoreg; | 39 | struct regmap *map; |
36 | void __iomem *lockreg; | 40 | u32 vcoreg_off; |
41 | u32 lockreg_off; | ||
37 | struct icst_params *params; | 42 | struct icst_params *params; |
38 | unsigned long rate; | 43 | unsigned long rate; |
39 | }; | 44 | }; |
@@ -41,53 +46,67 @@ struct clk_icst { | |||
41 | #define to_icst(_hw) container_of(_hw, struct clk_icst, hw) | 46 | #define to_icst(_hw) container_of(_hw, struct clk_icst, hw) |
42 | 47 | ||
43 | /** | 48 | /** |
44 | * vco_get() - get ICST VCO settings from a certain register | 49 | * vco_get() - get ICST VCO settings from a certain ICST |
45 | * @vcoreg: register containing the VCO settings | 50 | * @icst: the ICST clock to get |
51 | * @vco: the VCO struct to return the value in | ||
46 | */ | 52 | */ |
47 | static struct icst_vco vco_get(void __iomem *vcoreg) | 53 | static int vco_get(struct clk_icst *icst, struct icst_vco *vco) |
48 | { | 54 | { |
49 | u32 val; | 55 | u32 val; |
50 | struct icst_vco vco; | 56 | int ret; |
51 | 57 | ||
52 | val = readl(vcoreg); | 58 | ret = regmap_read(icst->map, icst->vcoreg_off, &val); |
53 | vco.v = val & 0x1ff; | 59 | if (ret) |
54 | vco.r = (val >> 9) & 0x7f; | 60 | return ret; |
55 | vco.s = (val >> 16) & 03; | 61 | vco->v = val & 0x1ff; |
56 | return vco; | 62 | vco->r = (val >> 9) & 0x7f; |
63 | vco->s = (val >> 16) & 03; | ||
64 | return 0; | ||
57 | } | 65 | } |
58 | 66 | ||
59 | /** | 67 | /** |
60 | * vco_set() - commit changes to an ICST VCO | 68 | * vco_set() - commit changes to an ICST VCO |
61 | * @locreg: register to poke to unlock the VCO for writing | 69 | * @icst: the ICST clock to set |
62 | * @vcoreg: register containing the VCO settings | 70 | * @vco: the VCO struct to set the changes from |
63 | * @vco: ICST VCO parameters to commit | ||
64 | */ | 71 | */ |
65 | static void vco_set(void __iomem *lockreg, | 72 | static int vco_set(struct clk_icst *icst, struct icst_vco vco) |
66 | void __iomem *vcoreg, | ||
67 | struct icst_vco vco) | ||
68 | { | 73 | { |
69 | u32 val; | 74 | u32 val; |
75 | int ret; | ||
70 | 76 | ||
71 | val = readl(vcoreg) & ~0x7ffff; | 77 | ret = regmap_read(icst->map, icst->vcoreg_off, &val); |
78 | if (ret) | ||
79 | return ret; | ||
72 | val |= vco.v | (vco.r << 9) | (vco.s << 16); | 80 | val |= vco.v | (vco.r << 9) | (vco.s << 16); |
73 | 81 | ||
74 | /* This magic unlocks the VCO so it can be controlled */ | 82 | /* This magic unlocks the VCO so it can be controlled */ |
75 | writel(0xa05f, lockreg); | 83 | ret = regmap_write(icst->map, icst->lockreg_off, VERSATILE_LOCK_VAL); |
76 | writel(val, vcoreg); | 84 | if (ret) |
85 | return ret; | ||
86 | ret = regmap_write(icst->map, icst->vcoreg_off, val); | ||
87 | if (ret) | ||
88 | return ret; | ||
77 | /* This locks the VCO again */ | 89 | /* This locks the VCO again */ |
78 | writel(0, lockreg); | 90 | ret = regmap_write(icst->map, icst->lockreg_off, 0); |
91 | if (ret) | ||
92 | return ret; | ||
93 | return 0; | ||
79 | } | 94 | } |
80 | 95 | ||
81 | |||
82 | static unsigned long icst_recalc_rate(struct clk_hw *hw, | 96 | static unsigned long icst_recalc_rate(struct clk_hw *hw, |
83 | unsigned long parent_rate) | 97 | unsigned long parent_rate) |
84 | { | 98 | { |
85 | struct clk_icst *icst = to_icst(hw); | 99 | struct clk_icst *icst = to_icst(hw); |
86 | struct icst_vco vco; | 100 | struct icst_vco vco; |
101 | int ret; | ||
87 | 102 | ||
88 | if (parent_rate) | 103 | if (parent_rate) |
89 | icst->params->ref = parent_rate; | 104 | icst->params->ref = parent_rate; |
90 | vco = vco_get(icst->vcoreg); | 105 | ret = vco_get(icst, &vco); |
106 | if (ret) { | ||
107 | pr_err("ICST: could not get VCO setting\n"); | ||
108 | return 0; | ||
109 | } | ||
91 | icst->rate = icst_hz(icst->params, vco); | 110 | icst->rate = icst_hz(icst->params, vco); |
92 | return icst->rate; | 111 | return icst->rate; |
93 | } | 112 | } |
@@ -112,8 +131,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, | |||
112 | icst->params->ref = parent_rate; | 131 | icst->params->ref = parent_rate; |
113 | vco = icst_hz_to_vco(icst->params, rate); | 132 | vco = icst_hz_to_vco(icst->params, rate); |
114 | icst->rate = icst_hz(icst->params, vco); | 133 | icst->rate = icst_hz(icst->params, vco); |
115 | vco_set(icst->lockreg, icst->vcoreg, vco); | 134 | return vco_set(icst, vco); |
116 | return 0; | ||
117 | } | 135 | } |
118 | 136 | ||
119 | static const struct clk_ops icst_ops = { | 137 | static const struct clk_ops icst_ops = { |
@@ -132,6 +150,11 @@ struct clk *icst_clk_register(struct device *dev, | |||
132 | struct clk_icst *icst; | 150 | struct clk_icst *icst; |
133 | struct clk_init_data init; | 151 | struct clk_init_data init; |
134 | struct icst_params *pclone; | 152 | struct icst_params *pclone; |
153 | struct regmap_config icst_regmap_conf = { | ||
154 | .reg_bits = 32, | ||
155 | .val_bits = 32, | ||
156 | .reg_stride = 4, | ||
157 | }; | ||
135 | 158 | ||
136 | icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL); | 159 | icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL); |
137 | if (!icst) { | 160 | if (!icst) { |
@@ -151,10 +174,19 @@ struct clk *icst_clk_register(struct device *dev, | |||
151 | init.flags = CLK_IS_ROOT; | 174 | init.flags = CLK_IS_ROOT; |
152 | init.parent_names = (parent_name ? &parent_name : NULL); | 175 | init.parent_names = (parent_name ? &parent_name : NULL); |
153 | init.num_parents = (parent_name ? 1 : 0); | 176 | init.num_parents = (parent_name ? 1 : 0); |
177 | icst->map = regmap_init_mmio(dev, base, &icst_regmap_conf); | ||
178 | if (IS_ERR(icst->map)) { | ||
179 | int ret; | ||
180 | |||
181 | pr_err("could not initialize ICST regmap\n"); | ||
182 | ret = PTR_ERR(icst->map); | ||
183 | kfree(icst); | ||
184 | return ERR_PTR(ret); | ||
185 | } | ||
154 | icst->hw.init = &init; | 186 | icst->hw.init = &init; |
155 | icst->params = pclone; | 187 | icst->params = pclone; |
156 | icst->vcoreg = base + desc->vco_offset; | 188 | icst->vcoreg_off = desc->vco_offset; |
157 | icst->lockreg = base + desc->lock_offset; | 189 | icst->lockreg_off = desc->lock_offset; |
158 | 190 | ||
159 | clk = clk_register(dev, &icst->hw); | 191 | clk = clk_register(dev, &icst->hw); |
160 | if (IS_ERR(clk)) { | 192 | if (IS_ERR(clk)) { |