xref: /openbmc/linux/drivers/clk/versatile/clk-icst.c (revision a06c488d)
1 /*
2  * Driver for the ICST307 VCO clock found in the ARM Reference designs.
3  * We wrap the custom interface from <asm/hardware/icst.h> into the generic
4  * clock framework.
5  *
6  * Copyright (C) 2012-2015 Linus Walleij
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * TODO: when all ARM reference designs are migrated to generic clocks, the
13  * ICST clock code from the ARM tree should probably be merged into this
14  * file.
15  */
16 #include <linux/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/export.h>
19 #include <linux/err.h>
20 #include <linux/clk-provider.h>
21 #include <linux/io.h>
22 #include <linux/regmap.h>
23 #include <linux/mfd/syscon.h>
24 
25 #include "clk-icst.h"
26 
27 /* Magic unlocking token used on all Versatile boards */
28 #define VERSATILE_LOCK_VAL	0xA05F
29 
30 /**
31  * struct clk_icst - ICST VCO clock wrapper
32  * @hw: corresponding clock hardware entry
33  * @vcoreg: VCO register address
34  * @lockreg: VCO lock register address
35  * @params: parameters for this ICST instance
36  * @rate: current rate
37  */
38 struct clk_icst {
39 	struct clk_hw hw;
40 	struct regmap *map;
41 	u32 vcoreg_off;
42 	u32 lockreg_off;
43 	struct icst_params *params;
44 	unsigned long rate;
45 };
46 
47 #define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
48 
49 /**
50  * vco_get() - get ICST VCO settings from a certain ICST
51  * @icst: the ICST clock to get
52  * @vco: the VCO struct to return the value in
53  */
54 static int vco_get(struct clk_icst *icst, struct icst_vco *vco)
55 {
56 	u32 val;
57 	int ret;
58 
59 	ret = regmap_read(icst->map, icst->vcoreg_off, &val);
60 	if (ret)
61 		return ret;
62 	vco->v = val & 0x1ff;
63 	vco->r = (val >> 9) & 0x7f;
64 	vco->s = (val >> 16) & 03;
65 	return 0;
66 }
67 
68 /**
69  * vco_set() - commit changes to an ICST VCO
70  * @icst: the ICST clock to set
71  * @vco: the VCO struct to set the changes from
72  */
73 static int vco_set(struct clk_icst *icst, struct icst_vco vco)
74 {
75 	u32 val;
76 	int ret;
77 
78 	ret = regmap_read(icst->map, icst->vcoreg_off, &val);
79 	if (ret)
80 		return ret;
81 	val |= vco.v | (vco.r << 9) | (vco.s << 16);
82 
83 	/* This magic unlocks the VCO so it can be controlled */
84 	ret = regmap_write(icst->map, icst->lockreg_off, VERSATILE_LOCK_VAL);
85 	if (ret)
86 		return ret;
87 	ret = regmap_write(icst->map, icst->vcoreg_off, val);
88 	if (ret)
89 		return ret;
90 	/* This locks the VCO again */
91 	ret = regmap_write(icst->map, icst->lockreg_off, 0);
92 	if (ret)
93 		return ret;
94 	return 0;
95 }
96 
97 static unsigned long icst_recalc_rate(struct clk_hw *hw,
98 				      unsigned long parent_rate)
99 {
100 	struct clk_icst *icst = to_icst(hw);
101 	struct icst_vco vco;
102 	int ret;
103 
104 	if (parent_rate)
105 		icst->params->ref = parent_rate;
106 	ret = vco_get(icst, &vco);
107 	if (ret) {
108 		pr_err("ICST: could not get VCO setting\n");
109 		return 0;
110 	}
111 	icst->rate = icst_hz(icst->params, vco);
112 	return icst->rate;
113 }
114 
115 static long icst_round_rate(struct clk_hw *hw, unsigned long rate,
116 			    unsigned long *prate)
117 {
118 	struct clk_icst *icst = to_icst(hw);
119 	struct icst_vco vco;
120 
121 	vco = icst_hz_to_vco(icst->params, rate);
122 	return icst_hz(icst->params, vco);
123 }
124 
125 static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
126 			 unsigned long parent_rate)
127 {
128 	struct clk_icst *icst = to_icst(hw);
129 	struct icst_vco vco;
130 
131 	if (parent_rate)
132 		icst->params->ref = parent_rate;
133 	vco = icst_hz_to_vco(icst->params, rate);
134 	icst->rate = icst_hz(icst->params, vco);
135 	return vco_set(icst, vco);
136 }
137 
138 static const struct clk_ops icst_ops = {
139 	.recalc_rate = icst_recalc_rate,
140 	.round_rate = icst_round_rate,
141 	.set_rate = icst_set_rate,
142 };
143 
144 static struct clk *icst_clk_setup(struct device *dev,
145 				  const struct clk_icst_desc *desc,
146 				  const char *name,
147 				  const char *parent_name,
148 				  struct regmap *map)
149 {
150 	struct clk *clk;
151 	struct clk_icst *icst;
152 	struct clk_init_data init;
153 	struct icst_params *pclone;
154 
155 	icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL);
156 	if (!icst) {
157 		pr_err("could not allocate ICST clock!\n");
158 		return ERR_PTR(-ENOMEM);
159 	}
160 
161 	pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL);
162 	if (!pclone) {
163 		kfree(icst);
164 		pr_err("could not clone ICST params\n");
165 		return ERR_PTR(-ENOMEM);
166 	}
167 
168 	init.name = name;
169 	init.ops = &icst_ops;
170 	init.flags = CLK_IS_ROOT;
171 	init.parent_names = (parent_name ? &parent_name : NULL);
172 	init.num_parents = (parent_name ? 1 : 0);
173 	icst->map = map;
174 	icst->hw.init = &init;
175 	icst->params = pclone;
176 	icst->vcoreg_off = desc->vco_offset;
177 	icst->lockreg_off = desc->lock_offset;
178 
179 	clk = clk_register(dev, &icst->hw);
180 	if (IS_ERR(clk)) {
181 		kfree(pclone);
182 		kfree(icst);
183 	}
184 
185 	return clk;
186 }
187 
188 struct clk *icst_clk_register(struct device *dev,
189 			const struct clk_icst_desc *desc,
190 			const char *name,
191 			const char *parent_name,
192 			void __iomem *base)
193 {
194 	struct regmap_config icst_regmap_conf = {
195 		.reg_bits = 32,
196 		.val_bits = 32,
197 		.reg_stride = 4,
198 	};
199 	struct regmap *map;
200 
201 	map = regmap_init_mmio(dev, base, &icst_regmap_conf);
202 	if (IS_ERR(map)) {
203 		pr_err("could not initialize ICST regmap\n");
204 		return ERR_CAST(map);
205 	}
206 	return icst_clk_setup(dev, desc, name, parent_name, map);
207 }
208 EXPORT_SYMBOL_GPL(icst_clk_register);
209 
210 #ifdef CONFIG_OF
211 /*
212  * In a device tree, an memory-mapped ICST clock appear as a child
213  * of a syscon node. Assume this and probe it only as a child of a
214  * syscon.
215  */
216 
217 static const struct icst_params icst525_params = {
218 	.vco_max	= ICST525_VCO_MAX_5V,
219 	.vco_min	= ICST525_VCO_MIN,
220 	.vd_min		= 8,
221 	.vd_max		= 263,
222 	.rd_min		= 3,
223 	.rd_max		= 65,
224 	.s2div		= icst525_s2div,
225 	.idx2s		= icst525_idx2s,
226 };
227 
228 static const struct icst_params icst307_params = {
229 	.vco_max	= ICST307_VCO_MAX,
230 	.vco_min	= ICST307_VCO_MIN,
231 	.vd_min		= 4 + 8,
232 	.vd_max		= 511 + 8,
233 	.rd_min		= 1 + 2,
234 	.rd_max		= 127 + 2,
235 	.s2div		= icst307_s2div,
236 	.idx2s		= icst307_idx2s,
237 };
238 
239 static void __init of_syscon_icst_setup(struct device_node *np)
240 {
241 	struct device_node *parent;
242 	struct regmap *map;
243 	struct clk_icst_desc icst_desc;
244 	const char *name = np->name;
245 	const char *parent_name;
246 	struct clk *regclk;
247 
248 	/* We do not release this reference, we are using it perpetually */
249 	parent = of_get_parent(np);
250 	if (!parent) {
251 		pr_err("no parent node for syscon ICST clock\n");
252 		return;
253 	}
254 	map = syscon_node_to_regmap(parent);
255 	if (IS_ERR(map)) {
256 		pr_err("no regmap for syscon ICST clock parent\n");
257 		return;
258 	}
259 
260 	if (of_property_read_u32(np, "vco-offset", &icst_desc.vco_offset)) {
261 		pr_err("no VCO register offset for ICST clock\n");
262 		return;
263 	}
264 	if (of_property_read_u32(np, "lock-offset", &icst_desc.lock_offset)) {
265 		pr_err("no lock register offset for ICST clock\n");
266 		return;
267 	}
268 
269 	if (of_device_is_compatible(np, "arm,syscon-icst525"))
270 		icst_desc.params = &icst525_params;
271 	else if (of_device_is_compatible(np, "arm,syscon-icst307"))
272 		icst_desc.params = &icst307_params;
273 	else {
274 		pr_err("unknown ICST clock %s\n", name);
275 		return;
276 	}
277 
278 	/* Parent clock name is not the same as node parent */
279 	parent_name = of_clk_get_parent_name(np, 0);
280 
281 	regclk = icst_clk_setup(NULL, &icst_desc, name, parent_name, map);
282 	if (IS_ERR(regclk)) {
283 		pr_err("error setting up syscon ICST clock %s\n", name);
284 		return;
285 	}
286 	of_clk_add_provider(np, of_clk_src_simple_get, regclk);
287 	pr_debug("registered syscon ICST clock %s\n", name);
288 }
289 
290 CLK_OF_DECLARE(arm_syscon_icst525_clk,
291 	       "arm,syscon-icst525", of_syscon_icst_setup);
292 CLK_OF_DECLARE(arm_syscon_icst307_clk,
293 	       "arm,syscon-icst307", of_syscon_icst_setup);
294 
295 #endif
296