1 /*
2  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  */
10 
11 #include <linux/clk-provider.h>
12 #include <linux/clkdev.h>
13 #include <linux/clk/at91_pmc.h>
14 #include <linux/of.h>
15 #include <linux/of_address.h>
16 #include <linux/io.h>
17 
18 #include "pmc.h"
19 
20 #define PERIPHERAL_MAX		64
21 
22 #define PERIPHERAL_AT91RM9200	0
23 #define PERIPHERAL_AT91SAM9X5	1
24 
25 #define PERIPHERAL_ID_MIN	2
26 #define PERIPHERAL_ID_MAX	31
27 #define PERIPHERAL_MASK(id)	(1 << ((id) & PERIPHERAL_ID_MAX))
28 
29 #define PERIPHERAL_RSHIFT_MASK	0x3
30 #define PERIPHERAL_RSHIFT(val)	(((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
31 
32 #define PERIPHERAL_MAX_SHIFT	3
33 
34 struct clk_peripheral {
35 	struct clk_hw hw;
36 	struct at91_pmc *pmc;
37 	u32 id;
38 };
39 
40 #define to_clk_peripheral(hw) container_of(hw, struct clk_peripheral, hw)
41 
42 struct clk_sam9x5_peripheral {
43 	struct clk_hw hw;
44 	struct at91_pmc *pmc;
45 	struct clk_range range;
46 	u32 id;
47 	u32 div;
48 	bool auto_div;
49 };
50 
51 #define to_clk_sam9x5_peripheral(hw) \
52 	container_of(hw, struct clk_sam9x5_peripheral, hw)
53 
54 static int clk_peripheral_enable(struct clk_hw *hw)
55 {
56 	struct clk_peripheral *periph = to_clk_peripheral(hw);
57 	struct at91_pmc *pmc = periph->pmc;
58 	int offset = AT91_PMC_PCER;
59 	u32 id = periph->id;
60 
61 	if (id < PERIPHERAL_ID_MIN)
62 		return 0;
63 	if (id > PERIPHERAL_ID_MAX)
64 		offset = AT91_PMC_PCER1;
65 	pmc_write(pmc, offset, PERIPHERAL_MASK(id));
66 	return 0;
67 }
68 
69 static void clk_peripheral_disable(struct clk_hw *hw)
70 {
71 	struct clk_peripheral *periph = to_clk_peripheral(hw);
72 	struct at91_pmc *pmc = periph->pmc;
73 	int offset = AT91_PMC_PCDR;
74 	u32 id = periph->id;
75 
76 	if (id < PERIPHERAL_ID_MIN)
77 		return;
78 	if (id > PERIPHERAL_ID_MAX)
79 		offset = AT91_PMC_PCDR1;
80 	pmc_write(pmc, offset, PERIPHERAL_MASK(id));
81 }
82 
83 static int clk_peripheral_is_enabled(struct clk_hw *hw)
84 {
85 	struct clk_peripheral *periph = to_clk_peripheral(hw);
86 	struct at91_pmc *pmc = periph->pmc;
87 	int offset = AT91_PMC_PCSR;
88 	u32 id = periph->id;
89 
90 	if (id < PERIPHERAL_ID_MIN)
91 		return 1;
92 	if (id > PERIPHERAL_ID_MAX)
93 		offset = AT91_PMC_PCSR1;
94 	return !!(pmc_read(pmc, offset) & PERIPHERAL_MASK(id));
95 }
96 
97 static const struct clk_ops peripheral_ops = {
98 	.enable = clk_peripheral_enable,
99 	.disable = clk_peripheral_disable,
100 	.is_enabled = clk_peripheral_is_enabled,
101 };
102 
103 static struct clk * __init
104 at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
105 			     const char *parent_name, u32 id)
106 {
107 	struct clk_peripheral *periph;
108 	struct clk *clk = NULL;
109 	struct clk_init_data init;
110 
111 	if (!pmc || !name || !parent_name || id > PERIPHERAL_ID_MAX)
112 		return ERR_PTR(-EINVAL);
113 
114 	periph = kzalloc(sizeof(*periph), GFP_KERNEL);
115 	if (!periph)
116 		return ERR_PTR(-ENOMEM);
117 
118 	init.name = name;
119 	init.ops = &peripheral_ops;
120 	init.parent_names = (parent_name ? &parent_name : NULL);
121 	init.num_parents = (parent_name ? 1 : 0);
122 	init.flags = 0;
123 
124 	periph->id = id;
125 	periph->hw.init = &init;
126 	periph->pmc = pmc;
127 
128 	clk = clk_register(NULL, &periph->hw);
129 	if (IS_ERR(clk))
130 		kfree(periph);
131 
132 	return clk;
133 }
134 
135 static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
136 {
137 	struct clk_hw *parent;
138 	unsigned long parent_rate;
139 	int shift = 0;
140 
141 	if (!periph->auto_div)
142 		return;
143 
144 	if (periph->range.max) {
145 		parent = clk_hw_get_parent_by_index(&periph->hw, 0);
146 		parent_rate = clk_hw_get_rate(parent);
147 		if (!parent_rate)
148 			return;
149 
150 		for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
151 			if (parent_rate >> shift <= periph->range.max)
152 				break;
153 		}
154 	}
155 
156 	periph->auto_div = false;
157 	periph->div = shift;
158 }
159 
160 static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
161 {
162 	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
163 	struct at91_pmc *pmc = periph->pmc;
164 	u32 tmp;
165 
166 	if (periph->id < PERIPHERAL_ID_MIN)
167 		return 0;
168 
169 	pmc_lock(pmc);
170 	pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
171 	tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_DIV_MASK;
172 	pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_DIV(periph->div)
173 					 | AT91_PMC_PCR_CMD
174 					 | AT91_PMC_PCR_EN);
175 	pmc_unlock(pmc);
176 	return 0;
177 }
178 
179 static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
180 {
181 	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
182 	struct at91_pmc *pmc = periph->pmc;
183 	u32 tmp;
184 
185 	if (periph->id < PERIPHERAL_ID_MIN)
186 		return;
187 
188 	pmc_lock(pmc);
189 	pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
190 	tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_EN;
191 	pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD);
192 	pmc_unlock(pmc);
193 }
194 
195 static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
196 {
197 	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
198 	struct at91_pmc *pmc = periph->pmc;
199 	int ret;
200 
201 	if (periph->id < PERIPHERAL_ID_MIN)
202 		return 1;
203 
204 	pmc_lock(pmc);
205 	pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
206 	ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN);
207 	pmc_unlock(pmc);
208 
209 	return ret;
210 }
211 
212 static unsigned long
213 clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
214 				  unsigned long parent_rate)
215 {
216 	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
217 	struct at91_pmc *pmc = periph->pmc;
218 	u32 tmp;
219 
220 	if (periph->id < PERIPHERAL_ID_MIN)
221 		return parent_rate;
222 
223 	pmc_lock(pmc);
224 	pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK));
225 	tmp = pmc_read(pmc, AT91_PMC_PCR);
226 	pmc_unlock(pmc);
227 
228 	if (tmp & AT91_PMC_PCR_EN) {
229 		periph->div = PERIPHERAL_RSHIFT(tmp);
230 		periph->auto_div = false;
231 	} else {
232 		clk_sam9x5_peripheral_autodiv(periph);
233 	}
234 
235 	return parent_rate >> periph->div;
236 }
237 
238 static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
239 					     unsigned long rate,
240 					     unsigned long *parent_rate)
241 {
242 	int shift = 0;
243 	unsigned long best_rate;
244 	unsigned long best_diff;
245 	unsigned long cur_rate = *parent_rate;
246 	unsigned long cur_diff;
247 	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
248 
249 	if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
250 		return *parent_rate;
251 
252 	if (periph->range.max) {
253 		for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
254 			cur_rate = *parent_rate >> shift;
255 			if (cur_rate <= periph->range.max)
256 				break;
257 		}
258 	}
259 
260 	if (rate >= cur_rate)
261 		return cur_rate;
262 
263 	best_diff = cur_rate - rate;
264 	best_rate = cur_rate;
265 	for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
266 		cur_rate = *parent_rate >> shift;
267 		if (cur_rate < rate)
268 			cur_diff = rate - cur_rate;
269 		else
270 			cur_diff = cur_rate - rate;
271 
272 		if (cur_diff < best_diff) {
273 			best_diff = cur_diff;
274 			best_rate = cur_rate;
275 		}
276 
277 		if (!best_diff || cur_rate < rate)
278 			break;
279 	}
280 
281 	return best_rate;
282 }
283 
284 static int clk_sam9x5_peripheral_set_rate(struct clk_hw *hw,
285 					  unsigned long rate,
286 					  unsigned long parent_rate)
287 {
288 	int shift;
289 	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
290 	if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
291 		if (parent_rate == rate)
292 			return 0;
293 		else
294 			return -EINVAL;
295 	}
296 
297 	if (periph->range.max && rate > periph->range.max)
298 		return -EINVAL;
299 
300 	for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
301 		if (parent_rate >> shift == rate) {
302 			periph->auto_div = false;
303 			periph->div = shift;
304 			return 0;
305 		}
306 	}
307 
308 	return -EINVAL;
309 }
310 
311 static const struct clk_ops sam9x5_peripheral_ops = {
312 	.enable = clk_sam9x5_peripheral_enable,
313 	.disable = clk_sam9x5_peripheral_disable,
314 	.is_enabled = clk_sam9x5_peripheral_is_enabled,
315 	.recalc_rate = clk_sam9x5_peripheral_recalc_rate,
316 	.round_rate = clk_sam9x5_peripheral_round_rate,
317 	.set_rate = clk_sam9x5_peripheral_set_rate,
318 };
319 
320 static struct clk * __init
321 at91_clk_register_sam9x5_peripheral(struct at91_pmc *pmc, const char *name,
322 				    const char *parent_name, u32 id,
323 				    const struct clk_range *range)
324 {
325 	struct clk_sam9x5_peripheral *periph;
326 	struct clk *clk = NULL;
327 	struct clk_init_data init;
328 
329 	if (!pmc || !name || !parent_name)
330 		return ERR_PTR(-EINVAL);
331 
332 	periph = kzalloc(sizeof(*periph), GFP_KERNEL);
333 	if (!periph)
334 		return ERR_PTR(-ENOMEM);
335 
336 	init.name = name;
337 	init.ops = &sam9x5_peripheral_ops;
338 	init.parent_names = (parent_name ? &parent_name : NULL);
339 	init.num_parents = (parent_name ? 1 : 0);
340 	init.flags = 0;
341 
342 	periph->id = id;
343 	periph->hw.init = &init;
344 	periph->div = 0;
345 	periph->pmc = pmc;
346 	periph->auto_div = true;
347 	periph->range = *range;
348 
349 	clk = clk_register(NULL, &periph->hw);
350 	if (IS_ERR(clk))
351 		kfree(periph);
352 	else
353 		clk_sam9x5_peripheral_autodiv(periph);
354 
355 	return clk;
356 }
357 
358 static void __init
359 of_at91_clk_periph_setup(struct device_node *np, struct at91_pmc *pmc, u8 type)
360 {
361 	int num;
362 	u32 id;
363 	struct clk *clk;
364 	const char *parent_name;
365 	const char *name;
366 	struct device_node *periphclknp;
367 
368 	parent_name = of_clk_get_parent_name(np, 0);
369 	if (!parent_name)
370 		return;
371 
372 	num = of_get_child_count(np);
373 	if (!num || num > PERIPHERAL_MAX)
374 		return;
375 
376 	for_each_child_of_node(np, periphclknp) {
377 		if (of_property_read_u32(periphclknp, "reg", &id))
378 			continue;
379 
380 		if (id >= PERIPHERAL_MAX)
381 			continue;
382 
383 		if (of_property_read_string(np, "clock-output-names", &name))
384 			name = periphclknp->name;
385 
386 		if (type == PERIPHERAL_AT91RM9200) {
387 			clk = at91_clk_register_peripheral(pmc, name,
388 							   parent_name, id);
389 		} else {
390 			struct clk_range range = CLK_RANGE(0, 0);
391 
392 			of_at91_get_clk_range(periphclknp,
393 					      "atmel,clk-output-range",
394 					      &range);
395 
396 			clk = at91_clk_register_sam9x5_peripheral(pmc, name,
397 								  parent_name,
398 								  id, &range);
399 		}
400 
401 		if (IS_ERR(clk))
402 			continue;
403 
404 		of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk);
405 	}
406 }
407 
408 void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
409 					   struct at91_pmc *pmc)
410 {
411 	of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91RM9200);
412 }
413 
414 void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
415 					   struct at91_pmc *pmc)
416 {
417 	of_at91_clk_periph_setup(np, pmc, PERIPHERAL_AT91SAM9X5);
418 }
419