xref: /rk3399_rockchip-uboot/drivers/clk/clk-uclass.c (revision 0b2881acbd7a4f32aaa8600efd9712e95698fe28)
1f26c8a8eSSimon Glass /*
2f26c8a8eSSimon Glass  * Copyright (C) 2015 Google, Inc
3f26c8a8eSSimon Glass  * Written by Simon Glass <sjg@chromium.org>
4135aa950SStephen Warren  * Copyright (c) 2016, NVIDIA CORPORATION.
5*0b2881acSPhilipp Tomsich  * Copyright (c) 2018, Theobroma Systems Design und Consulting GmbH
6f26c8a8eSSimon Glass  *
7f26c8a8eSSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
8f26c8a8eSSimon Glass  */
9f26c8a8eSSimon Glass 
10f26c8a8eSSimon Glass #include <common.h>
11f26c8a8eSSimon Glass #include <clk.h>
12135aa950SStephen Warren #include <clk-uclass.h>
13f26c8a8eSSimon Glass #include <dm.h>
14*0b2881acSPhilipp Tomsich #include <dm/read.h>
157423daa6SSimon Glass #include <dt-structs.h>
16f26c8a8eSSimon Glass #include <errno.h>
17f26c8a8eSSimon Glass 
187c101424SMario Six static inline const struct clk_ops *clk_dev_ops(struct udevice *dev)
19f26c8a8eSSimon Glass {
207c101424SMario Six 	return (const struct clk_ops *)dev->driver->ops;
21f26c8a8eSSimon Glass }
22f26c8a8eSSimon Glass 
23e70cc438SSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL)
247423daa6SSimon Glass # if CONFIG_IS_ENABLED(OF_PLATDATA)
257423daa6SSimon Glass int clk_get_by_index_platdata(struct udevice *dev, int index,
263a40acd4SSimon Glass 			      struct phandle_1_arg *cells, struct clk *clk)
277423daa6SSimon Glass {
287423daa6SSimon Glass 	int ret;
297423daa6SSimon Glass 
307423daa6SSimon Glass 	if (index != 0)
317423daa6SSimon Glass 		return -ENOSYS;
327423daa6SSimon Glass 	ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
337423daa6SSimon Glass 	if (ret)
347423daa6SSimon Glass 		return ret;
35f9faa230SSimon Glass 	clk->id = cells[0].arg[0];
367423daa6SSimon Glass 
377423daa6SSimon Glass 	return 0;
387423daa6SSimon Glass }
397423daa6SSimon Glass # else
40135aa950SStephen Warren static int clk_of_xlate_default(struct clk *clk,
41a4e0ef50SSimon Glass 				struct ofnode_phandle_args *args)
42135aa950SStephen Warren {
43135aa950SStephen Warren 	debug("%s(clk=%p)\n", __func__, clk);
44135aa950SStephen Warren 
45135aa950SStephen Warren 	if (args->args_count > 1) {
46135aa950SStephen Warren 		debug("Invaild args_count: %d\n", args->args_count);
47135aa950SStephen Warren 		return -EINVAL;
48135aa950SStephen Warren 	}
49135aa950SStephen Warren 
50135aa950SStephen Warren 	if (args->args_count)
51135aa950SStephen Warren 		clk->id = args->args[0];
52135aa950SStephen Warren 	else
53135aa950SStephen Warren 		clk->id = 0;
54135aa950SStephen Warren 
55135aa950SStephen Warren 	return 0;
56135aa950SStephen Warren }
57135aa950SStephen Warren 
582ae83ee4SPhilipp Tomsich static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
592ae83ee4SPhilipp Tomsich 				   int index, struct clk *clk)
60135aa950SStephen Warren {
61135aa950SStephen Warren 	int ret;
62aa9bb094SSimon Glass 	struct ofnode_phandle_args args;
63135aa950SStephen Warren 	struct udevice *dev_clk;
647c101424SMario Six 	const struct clk_ops *ops;
65135aa950SStephen Warren 
66135aa950SStephen Warren 	debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk);
67135aa950SStephen Warren 
68135aa950SStephen Warren 	assert(clk);
6982a8a669SPatrice Chotard 	clk->dev = NULL;
7082a8a669SPatrice Chotard 
712ae83ee4SPhilipp Tomsich 	ret = dev_read_phandle_with_args(dev, prop_name, "#clock-cells", 0,
72aa9bb094SSimon Glass 					 index, &args);
73e70cc438SSimon Glass 	if (ret) {
74e70cc438SSimon Glass 		debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
75e70cc438SSimon Glass 		      __func__, ret);
76e70cc438SSimon Glass 		return ret;
77e70cc438SSimon Glass 	}
78e70cc438SSimon Glass 
79aa9bb094SSimon Glass 	ret = uclass_get_device_by_ofnode(UCLASS_CLK, args.node, &dev_clk);
80e70cc438SSimon Glass 	if (ret) {
81e70cc438SSimon Glass 		debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
82e70cc438SSimon Glass 		      __func__, ret);
83e70cc438SSimon Glass 		return ret;
84e70cc438SSimon Glass 	}
853f56b132SWenyou Yang 
863f56b132SWenyou Yang 	clk->dev = dev_clk;
873f56b132SWenyou Yang 
88135aa950SStephen Warren 	ops = clk_dev_ops(dev_clk);
89135aa950SStephen Warren 
90135aa950SStephen Warren 	if (ops->of_xlate)
91aa9bb094SSimon Glass 		ret = ops->of_xlate(clk, &args);
92135aa950SStephen Warren 	else
93aa9bb094SSimon Glass 		ret = clk_of_xlate_default(clk, &args);
94135aa950SStephen Warren 	if (ret) {
95135aa950SStephen Warren 		debug("of_xlate() failed: %d\n", ret);
96135aa950SStephen Warren 		return ret;
97135aa950SStephen Warren 	}
98135aa950SStephen Warren 
99135aa950SStephen Warren 	return clk_request(dev_clk, clk);
100135aa950SStephen Warren }
1012ae83ee4SPhilipp Tomsich 
1022ae83ee4SPhilipp Tomsich int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
1032ae83ee4SPhilipp Tomsich {
1042ae83ee4SPhilipp Tomsich 	return clk_get_by_indexed_prop(dev, "clocks", index, clk);
1052ae83ee4SPhilipp Tomsich }
106*0b2881acSPhilipp Tomsich 
107*0b2881acSPhilipp Tomsich static int clk_set_default_parents(struct udevice *dev)
108*0b2881acSPhilipp Tomsich {
109*0b2881acSPhilipp Tomsich 	struct clk clk, parent_clk;
110*0b2881acSPhilipp Tomsich 	int index;
111*0b2881acSPhilipp Tomsich 	int num_parents;
112*0b2881acSPhilipp Tomsich 	int ret;
113*0b2881acSPhilipp Tomsich 
114*0b2881acSPhilipp Tomsich 	num_parents = dev_count_phandle_with_args(dev, "assigned-clock-parents",
115*0b2881acSPhilipp Tomsich 						  "#clock-cells");
116*0b2881acSPhilipp Tomsich 	if (num_parents < 0) {
117*0b2881acSPhilipp Tomsich 		debug("%s: could not read assigned-clock-parents for %p\n",
118*0b2881acSPhilipp Tomsich 		      __func__, dev);
119*0b2881acSPhilipp Tomsich 		return 0;
120*0b2881acSPhilipp Tomsich 	}
121*0b2881acSPhilipp Tomsich 
122*0b2881acSPhilipp Tomsich 	for (index = 0; index < num_parents; index++) {
123*0b2881acSPhilipp Tomsich 		ret = clk_get_by_indexed_prop(dev, "assigned-clock-parents",
124*0b2881acSPhilipp Tomsich 					      index, &parent_clk);
125*0b2881acSPhilipp Tomsich 		if (ret) {
126*0b2881acSPhilipp Tomsich 			debug("%s: could not get parent clock %d for %s\n",
127*0b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
128*0b2881acSPhilipp Tomsich 			return ret;
129*0b2881acSPhilipp Tomsich 		}
130*0b2881acSPhilipp Tomsich 
131*0b2881acSPhilipp Tomsich 		ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
132*0b2881acSPhilipp Tomsich 					      index, &clk);
133*0b2881acSPhilipp Tomsich 		if (ret) {
134*0b2881acSPhilipp Tomsich 			debug("%s: could not get assigned clock %d for %s\n",
135*0b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
136*0b2881acSPhilipp Tomsich 			return ret;
137*0b2881acSPhilipp Tomsich 		}
138*0b2881acSPhilipp Tomsich 
139*0b2881acSPhilipp Tomsich 		ret = clk_set_parent(&clk, &parent_clk);
140*0b2881acSPhilipp Tomsich 
141*0b2881acSPhilipp Tomsich 		/*
142*0b2881acSPhilipp Tomsich 		 * Not all drivers may support clock-reparenting (as of now).
143*0b2881acSPhilipp Tomsich 		 * Ignore errors due to this.
144*0b2881acSPhilipp Tomsich 		 */
145*0b2881acSPhilipp Tomsich 		if (ret == -ENOSYS)
146*0b2881acSPhilipp Tomsich 			continue;
147*0b2881acSPhilipp Tomsich 
148*0b2881acSPhilipp Tomsich 		if (ret) {
149*0b2881acSPhilipp Tomsich 			debug("%s: failed to reparent clock %d for %s\n",
150*0b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
151*0b2881acSPhilipp Tomsich 			return ret;
152*0b2881acSPhilipp Tomsich 		}
153*0b2881acSPhilipp Tomsich 	}
154*0b2881acSPhilipp Tomsich 
155*0b2881acSPhilipp Tomsich 	return 0;
156*0b2881acSPhilipp Tomsich }
157*0b2881acSPhilipp Tomsich 
158*0b2881acSPhilipp Tomsich static int clk_set_default_rates(struct udevice *dev)
159*0b2881acSPhilipp Tomsich {
160*0b2881acSPhilipp Tomsich 	struct clk clk;
161*0b2881acSPhilipp Tomsich 	int index;
162*0b2881acSPhilipp Tomsich 	int num_rates;
163*0b2881acSPhilipp Tomsich 	int size;
164*0b2881acSPhilipp Tomsich 	int ret = 0;
165*0b2881acSPhilipp Tomsich 	u32 *rates = NULL;
166*0b2881acSPhilipp Tomsich 
167*0b2881acSPhilipp Tomsich 	size = dev_read_size(dev, "assigned-clock-rates");
168*0b2881acSPhilipp Tomsich 	if (size < 0)
169*0b2881acSPhilipp Tomsich 		return 0;
170*0b2881acSPhilipp Tomsich 
171*0b2881acSPhilipp Tomsich 	num_rates = size / sizeof(u32);
172*0b2881acSPhilipp Tomsich 	rates = calloc(num_rates, sizeof(u32));
173*0b2881acSPhilipp Tomsich 	if (!rates)
174*0b2881acSPhilipp Tomsich 		return -ENOMEM;
175*0b2881acSPhilipp Tomsich 
176*0b2881acSPhilipp Tomsich 	ret = dev_read_u32_array(dev, "assigned-clock-rates", rates, num_rates);
177*0b2881acSPhilipp Tomsich 	if (ret)
178*0b2881acSPhilipp Tomsich 		goto fail;
179*0b2881acSPhilipp Tomsich 
180*0b2881acSPhilipp Tomsich 	for (index = 0; index < num_rates; index++) {
181*0b2881acSPhilipp Tomsich 		ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
182*0b2881acSPhilipp Tomsich 					      index, &clk);
183*0b2881acSPhilipp Tomsich 		if (ret) {
184*0b2881acSPhilipp Tomsich 			debug("%s: could not get assigned clock %d for %s\n",
185*0b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
186*0b2881acSPhilipp Tomsich 			continue;
187*0b2881acSPhilipp Tomsich 		}
188*0b2881acSPhilipp Tomsich 
189*0b2881acSPhilipp Tomsich 		ret = clk_set_rate(&clk, rates[index]);
190*0b2881acSPhilipp Tomsich 		if (ret < 0) {
191*0b2881acSPhilipp Tomsich 			debug("%s: failed to set rate on clock %d for %s\n",
192*0b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
193*0b2881acSPhilipp Tomsich 			break;
194*0b2881acSPhilipp Tomsich 		}
195*0b2881acSPhilipp Tomsich 	}
196*0b2881acSPhilipp Tomsich 
197*0b2881acSPhilipp Tomsich fail:
198*0b2881acSPhilipp Tomsich 	free(rates);
199*0b2881acSPhilipp Tomsich 	return ret;
200*0b2881acSPhilipp Tomsich }
201*0b2881acSPhilipp Tomsich 
202*0b2881acSPhilipp Tomsich int clk_set_defaults(struct udevice *dev)
203*0b2881acSPhilipp Tomsich {
204*0b2881acSPhilipp Tomsich 	int ret;
205*0b2881acSPhilipp Tomsich 
206*0b2881acSPhilipp Tomsich 	/* If this is running pre-reloc state, don't take any action. */
207*0b2881acSPhilipp Tomsich 	if (!(gd->flags & GD_FLG_RELOC))
208*0b2881acSPhilipp Tomsich 		return 0;
209*0b2881acSPhilipp Tomsich 
210*0b2881acSPhilipp Tomsich 	debug("%s(%s)\n", __func__, dev_read_name(dev));
211*0b2881acSPhilipp Tomsich 
212*0b2881acSPhilipp Tomsich 	ret = clk_set_default_parents(dev);
213*0b2881acSPhilipp Tomsich 	if (ret)
214*0b2881acSPhilipp Tomsich 		return ret;
215*0b2881acSPhilipp Tomsich 
216*0b2881acSPhilipp Tomsich 	ret = clk_set_default_rates(dev);
217*0b2881acSPhilipp Tomsich 	if (ret < 0)
218*0b2881acSPhilipp Tomsich 		return ret;
219*0b2881acSPhilipp Tomsich 
220*0b2881acSPhilipp Tomsich 	return 0;
221*0b2881acSPhilipp Tomsich }
2229e0758b7SMichal Simek # endif /* OF_PLATDATA */
223135aa950SStephen Warren 
224135aa950SStephen Warren int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
225135aa950SStephen Warren {
226135aa950SStephen Warren 	int index;
227135aa950SStephen Warren 
228135aa950SStephen Warren 	debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk);
22982a8a669SPatrice Chotard 	clk->dev = NULL;
230135aa950SStephen Warren 
231aa9bb094SSimon Glass 	index = dev_read_stringlist_search(dev, "clock-names", name);
232135aa950SStephen Warren 	if (index < 0) {
233b02e4044SSimon Glass 		debug("fdt_stringlist_search() failed: %d\n", index);
234135aa950SStephen Warren 		return index;
235135aa950SStephen Warren 	}
236135aa950SStephen Warren 
237135aa950SStephen Warren 	return clk_get_by_index(dev, index, clk);
238e70cc438SSimon Glass }
239b108d8a0SPatrice Chotard 
240b108d8a0SPatrice Chotard int clk_release_all(struct clk *clk, int count)
241b108d8a0SPatrice Chotard {
242b108d8a0SPatrice Chotard 	int i, ret;
243b108d8a0SPatrice Chotard 
244b108d8a0SPatrice Chotard 	for (i = 0; i < count; i++) {
245b108d8a0SPatrice Chotard 		debug("%s(clk[%d]=%p)\n", __func__, i, &clk[i]);
246b108d8a0SPatrice Chotard 
247b108d8a0SPatrice Chotard 		/* check if clock has been previously requested */
248b108d8a0SPatrice Chotard 		if (!clk[i].dev)
249b108d8a0SPatrice Chotard 			continue;
250b108d8a0SPatrice Chotard 
251b108d8a0SPatrice Chotard 		ret = clk_disable(&clk[i]);
252b108d8a0SPatrice Chotard 		if (ret && ret != -ENOSYS)
253b108d8a0SPatrice Chotard 			return ret;
254b108d8a0SPatrice Chotard 
255b108d8a0SPatrice Chotard 		ret = clk_free(&clk[i]);
256b108d8a0SPatrice Chotard 		if (ret && ret != -ENOSYS)
257b108d8a0SPatrice Chotard 			return ret;
258b108d8a0SPatrice Chotard 	}
259b108d8a0SPatrice Chotard 
260b108d8a0SPatrice Chotard 	return 0;
261b108d8a0SPatrice Chotard }
262b108d8a0SPatrice Chotard 
2637423daa6SSimon Glass #endif /* OF_CONTROL */
264135aa950SStephen Warren 
265135aa950SStephen Warren int clk_request(struct udevice *dev, struct clk *clk)
266135aa950SStephen Warren {
2677c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(dev);
268135aa950SStephen Warren 
269135aa950SStephen Warren 	debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk);
270135aa950SStephen Warren 
271135aa950SStephen Warren 	clk->dev = dev;
272135aa950SStephen Warren 
273135aa950SStephen Warren 	if (!ops->request)
274135aa950SStephen Warren 		return 0;
275135aa950SStephen Warren 
276135aa950SStephen Warren 	return ops->request(clk);
277135aa950SStephen Warren }
278135aa950SStephen Warren 
279135aa950SStephen Warren int clk_free(struct clk *clk)
280135aa950SStephen Warren {
2817c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
282135aa950SStephen Warren 
283135aa950SStephen Warren 	debug("%s(clk=%p)\n", __func__, clk);
284135aa950SStephen Warren 
285135aa950SStephen Warren 	if (!ops->free)
286135aa950SStephen Warren 		return 0;
287135aa950SStephen Warren 
288135aa950SStephen Warren 	return ops->free(clk);
289135aa950SStephen Warren }
290135aa950SStephen Warren 
291135aa950SStephen Warren ulong clk_get_rate(struct clk *clk)
292135aa950SStephen Warren {
2937c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
294135aa950SStephen Warren 
295135aa950SStephen Warren 	debug("%s(clk=%p)\n", __func__, clk);
296135aa950SStephen Warren 
297135aa950SStephen Warren 	if (!ops->get_rate)
298135aa950SStephen Warren 		return -ENOSYS;
299135aa950SStephen Warren 
300135aa950SStephen Warren 	return ops->get_rate(clk);
301135aa950SStephen Warren }
302135aa950SStephen Warren 
303135aa950SStephen Warren ulong clk_set_rate(struct clk *clk, ulong rate)
304135aa950SStephen Warren {
3057c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
306135aa950SStephen Warren 
307135aa950SStephen Warren 	debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
308135aa950SStephen Warren 
309135aa950SStephen Warren 	if (!ops->set_rate)
310135aa950SStephen Warren 		return -ENOSYS;
311135aa950SStephen Warren 
312135aa950SStephen Warren 	return ops->set_rate(clk, rate);
313135aa950SStephen Warren }
314135aa950SStephen Warren 
315724f9587SZiyuan Xu int clk_get_phase(struct clk *clk)
316724f9587SZiyuan Xu {
3177c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
318724f9587SZiyuan Xu 
319724f9587SZiyuan Xu 	if (!ops->get_phase)
320724f9587SZiyuan Xu 		return -ENOSYS;
321724f9587SZiyuan Xu 
322724f9587SZiyuan Xu 	return ops->get_phase(clk);
323724f9587SZiyuan Xu }
324724f9587SZiyuan Xu 
325724f9587SZiyuan Xu int clk_set_phase(struct clk *clk, int degrees)
326724f9587SZiyuan Xu {
3277c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
328724f9587SZiyuan Xu 
329724f9587SZiyuan Xu 	if (!ops->set_phase)
330724f9587SZiyuan Xu 		return -ENOSYS;
331724f9587SZiyuan Xu 
332724f9587SZiyuan Xu 	return ops->set_phase(clk, degrees);
333724f9587SZiyuan Xu }
334724f9587SZiyuan Xu 
3354686bbffSPhilipp Tomsich int clk_set_parent(struct clk *clk, struct clk *parent)
3364686bbffSPhilipp Tomsich {
3374686bbffSPhilipp Tomsich 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
3384686bbffSPhilipp Tomsich 
3394686bbffSPhilipp Tomsich 	debug("%s(clk=%p, parent=%p)\n", __func__, clk, parent);
3404686bbffSPhilipp Tomsich 
3414686bbffSPhilipp Tomsich 	if (!ops->set_parent)
3424686bbffSPhilipp Tomsich 		return -ENOSYS;
3434686bbffSPhilipp Tomsich 
3444686bbffSPhilipp Tomsich 	return ops->set_parent(clk, parent);
3454686bbffSPhilipp Tomsich }
3464686bbffSPhilipp Tomsich 
347135aa950SStephen Warren int clk_enable(struct clk *clk)
348135aa950SStephen Warren {
3497c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
350135aa950SStephen Warren 
351135aa950SStephen Warren 	debug("%s(clk=%p)\n", __func__, clk);
352135aa950SStephen Warren 
353135aa950SStephen Warren 	if (!ops->enable)
354135aa950SStephen Warren 		return -ENOSYS;
355135aa950SStephen Warren 
356135aa950SStephen Warren 	return ops->enable(clk);
357135aa950SStephen Warren }
358135aa950SStephen Warren 
359135aa950SStephen Warren int clk_disable(struct clk *clk)
360135aa950SStephen Warren {
3617c101424SMario Six 	const struct clk_ops *ops = clk_dev_ops(clk->dev);
362135aa950SStephen Warren 
363135aa950SStephen Warren 	debug("%s(clk=%p)\n", __func__, clk);
364135aa950SStephen Warren 
365135aa950SStephen Warren 	if (!ops->disable)
366135aa950SStephen Warren 		return -ENOSYS;
367135aa950SStephen Warren 
368135aa950SStephen Warren 	return ops->disable(clk);
369135aa950SStephen Warren }
370e70cc438SSimon Glass 
371f26c8a8eSSimon Glass UCLASS_DRIVER(clk) = {
372f26c8a8eSSimon Glass 	.id		= UCLASS_CLK,
373f26c8a8eSSimon Glass 	.name		= "clk",
374f26c8a8eSSimon Glass };
375