xref: /rk3399_rockchip-uboot/drivers/clk/clk-uclass.c (revision 693b63de6ef39c1e4f9a33a2b9e90249a44311f8)
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.
50b2881acSPhilipp 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>
140b2881acSPhilipp 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 }
1060b2881acSPhilipp Tomsich 
1070b2881acSPhilipp Tomsich static int clk_set_default_parents(struct udevice *dev)
1080b2881acSPhilipp Tomsich {
1090b2881acSPhilipp Tomsich 	struct clk clk, parent_clk;
1100b2881acSPhilipp Tomsich 	int index;
1110b2881acSPhilipp Tomsich 	int num_parents;
1120b2881acSPhilipp Tomsich 	int ret;
1130b2881acSPhilipp Tomsich 
1140b2881acSPhilipp Tomsich 	num_parents = dev_count_phandle_with_args(dev, "assigned-clock-parents",
1150b2881acSPhilipp Tomsich 						  "#clock-cells");
1160b2881acSPhilipp Tomsich 	if (num_parents < 0) {
1170b2881acSPhilipp Tomsich 		debug("%s: could not read assigned-clock-parents for %p\n",
1180b2881acSPhilipp Tomsich 		      __func__, dev);
1190b2881acSPhilipp Tomsich 		return 0;
1200b2881acSPhilipp Tomsich 	}
1210b2881acSPhilipp Tomsich 
1220b2881acSPhilipp Tomsich 	for (index = 0; index < num_parents; index++) {
1230b2881acSPhilipp Tomsich 		ret = clk_get_by_indexed_prop(dev, "assigned-clock-parents",
1240b2881acSPhilipp Tomsich 					      index, &parent_clk);
1250b2881acSPhilipp Tomsich 		if (ret) {
1260b2881acSPhilipp Tomsich 			debug("%s: could not get parent clock %d for %s\n",
1270b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
1280b2881acSPhilipp Tomsich 			return ret;
1290b2881acSPhilipp Tomsich 		}
1300b2881acSPhilipp Tomsich 
1310b2881acSPhilipp Tomsich 		ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
1320b2881acSPhilipp Tomsich 					      index, &clk);
1330b2881acSPhilipp Tomsich 		if (ret) {
1340b2881acSPhilipp Tomsich 			debug("%s: could not get assigned clock %d for %s\n",
1350b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
1360b2881acSPhilipp Tomsich 			return ret;
1370b2881acSPhilipp Tomsich 		}
1380b2881acSPhilipp Tomsich 
1390b2881acSPhilipp Tomsich 		ret = clk_set_parent(&clk, &parent_clk);
1400b2881acSPhilipp Tomsich 
1410b2881acSPhilipp Tomsich 		/*
1420b2881acSPhilipp Tomsich 		 * Not all drivers may support clock-reparenting (as of now).
1430b2881acSPhilipp Tomsich 		 * Ignore errors due to this.
1440b2881acSPhilipp Tomsich 		 */
1450b2881acSPhilipp Tomsich 		if (ret == -ENOSYS)
1460b2881acSPhilipp Tomsich 			continue;
1470b2881acSPhilipp Tomsich 
1480b2881acSPhilipp Tomsich 		if (ret) {
1490b2881acSPhilipp Tomsich 			debug("%s: failed to reparent clock %d for %s\n",
1500b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
1510b2881acSPhilipp Tomsich 			return ret;
1520b2881acSPhilipp Tomsich 		}
1530b2881acSPhilipp Tomsich 	}
1540b2881acSPhilipp Tomsich 
1550b2881acSPhilipp Tomsich 	return 0;
1560b2881acSPhilipp Tomsich }
1570b2881acSPhilipp Tomsich 
1580b2881acSPhilipp Tomsich static int clk_set_default_rates(struct udevice *dev)
1590b2881acSPhilipp Tomsich {
1600b2881acSPhilipp Tomsich 	struct clk clk;
1610b2881acSPhilipp Tomsich 	int index;
1620b2881acSPhilipp Tomsich 	int num_rates;
1630b2881acSPhilipp Tomsich 	int size;
1640b2881acSPhilipp Tomsich 	int ret = 0;
1650b2881acSPhilipp Tomsich 	u32 *rates = NULL;
1660b2881acSPhilipp Tomsich 
1670b2881acSPhilipp Tomsich 	size = dev_read_size(dev, "assigned-clock-rates");
1680b2881acSPhilipp Tomsich 	if (size < 0)
1690b2881acSPhilipp Tomsich 		return 0;
1700b2881acSPhilipp Tomsich 
1710b2881acSPhilipp Tomsich 	num_rates = size / sizeof(u32);
1720b2881acSPhilipp Tomsich 	rates = calloc(num_rates, sizeof(u32));
1730b2881acSPhilipp Tomsich 	if (!rates)
1740b2881acSPhilipp Tomsich 		return -ENOMEM;
1750b2881acSPhilipp Tomsich 
1760b2881acSPhilipp Tomsich 	ret = dev_read_u32_array(dev, "assigned-clock-rates", rates, num_rates);
1770b2881acSPhilipp Tomsich 	if (ret)
1780b2881acSPhilipp Tomsich 		goto fail;
1790b2881acSPhilipp Tomsich 
1800b2881acSPhilipp Tomsich 	for (index = 0; index < num_rates; index++) {
1810b2881acSPhilipp Tomsich 		ret = clk_get_by_indexed_prop(dev, "assigned-clocks",
1820b2881acSPhilipp Tomsich 					      index, &clk);
1830b2881acSPhilipp Tomsich 		if (ret) {
1840b2881acSPhilipp Tomsich 			debug("%s: could not get assigned clock %d for %s\n",
1850b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
1860b2881acSPhilipp Tomsich 			continue;
1870b2881acSPhilipp Tomsich 		}
1880b2881acSPhilipp Tomsich 
1890b2881acSPhilipp Tomsich 		ret = clk_set_rate(&clk, rates[index]);
1900b2881acSPhilipp Tomsich 		if (ret < 0) {
1910b2881acSPhilipp Tomsich 			debug("%s: failed to set rate on clock %d for %s\n",
1920b2881acSPhilipp Tomsich 			      __func__, index, dev_read_name(dev));
193*693b63deSFinley Xiao 			continue;
1940b2881acSPhilipp Tomsich 		}
1950b2881acSPhilipp Tomsich 	}
1960b2881acSPhilipp Tomsich 
1970b2881acSPhilipp Tomsich fail:
1980b2881acSPhilipp Tomsich 	free(rates);
1990b2881acSPhilipp Tomsich 	return ret;
2000b2881acSPhilipp Tomsich }
2010b2881acSPhilipp Tomsich 
2020b2881acSPhilipp Tomsich int clk_set_defaults(struct udevice *dev)
2030b2881acSPhilipp Tomsich {
2040b2881acSPhilipp Tomsich 	int ret;
2050b2881acSPhilipp Tomsich 
2060b2881acSPhilipp Tomsich 	/* If this is running pre-reloc state, don't take any action. */
2070b2881acSPhilipp Tomsich 	if (!(gd->flags & GD_FLG_RELOC))
2080b2881acSPhilipp Tomsich 		return 0;
2090b2881acSPhilipp Tomsich 
2100b2881acSPhilipp Tomsich 	debug("%s(%s)\n", __func__, dev_read_name(dev));
2110b2881acSPhilipp Tomsich 
2120b2881acSPhilipp Tomsich 	ret = clk_set_default_parents(dev);
2130b2881acSPhilipp Tomsich 	if (ret)
2140b2881acSPhilipp Tomsich 		return ret;
2150b2881acSPhilipp Tomsich 
2160b2881acSPhilipp Tomsich 	ret = clk_set_default_rates(dev);
2170b2881acSPhilipp Tomsich 	if (ret < 0)
2180b2881acSPhilipp Tomsich 		return ret;
2190b2881acSPhilipp Tomsich 
2200b2881acSPhilipp Tomsich 	return 0;
2210b2881acSPhilipp 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