1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019 DENX Software Engineering
4  * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
5  */
6 
7 #define LOG_CATEGORY UCLASS_CLK
8 
9 #include <clk.h>
10 #include <clk-uclass.h>
11 #include <log.h>
12 #include <dm/device.h>
13 #include <dm/uclass.h>
14 #include <dm/lists.h>
15 #include <dm/device-internal.h>
16 
clk_register(struct clk * clk,const char * drv_name,const char * name,const char * parent_name)17 int clk_register(struct clk *clk, const char *drv_name,
18 		 const char *name, const char *parent_name)
19 {
20 	struct udevice *parent = NULL;
21 	struct driver *drv;
22 	int ret;
23 
24 	if (parent_name) {
25 		ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent);
26 		if (ret) {
27 			log_err("%s: failed to get %s device (parent of %s)\n",
28 				__func__, parent_name, name);
29 		} else {
30 			log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name,
31 				  parent->name, parent);
32 		}
33 	}
34 
35 	drv = lists_driver_lookup_name(drv_name);
36 	if (!drv) {
37 		log_err("%s: %s is not a valid driver name\n",
38 			__func__, drv_name);
39 		return -ENOENT;
40 	}
41 
42 	ret = device_bind(parent, drv, name, NULL, ofnode_null(), &clk->dev);
43 	if (ret) {
44 		log_err("%s: CLK: %s driver bind error [%d]!\n", __func__, name,
45 			ret);
46 		return ret;
47 	}
48 
49 	clk->enable_count = 0;
50 
51 	/* Store back pointer to clk from udevice */
52 	/* FIXME: This is not allowed...should be allocated by driver model */
53 	dev_set_uclass_priv(clk->dev, clk);
54 
55 	return 0;
56 }
57 
clk_generic_get_rate(struct clk * clk)58 ulong clk_generic_get_rate(struct clk *clk)
59 {
60 	return clk_get_parent_rate(clk);
61 }
62 
clk_hw_get_name(const struct clk * hw)63 const char *clk_hw_get_name(const struct clk *hw)
64 {
65 	assert(hw);
66 	assert(hw->dev);
67 
68 	return hw->dev->name;
69 }
70 
clk_dev_binded(struct clk * clk)71 bool clk_dev_binded(struct clk *clk)
72 {
73 	if (clk->dev && (dev_get_flags(clk->dev) & DM_FLAG_BOUND))
74 		return true;
75 
76 	return false;
77 }
78 
79 /* Helper functions for clock ops */
80 
ccf_clk_get_rate(struct clk * clk)81 ulong ccf_clk_get_rate(struct clk *clk)
82 {
83 	struct clk *c;
84 	int err = clk_get_by_id(clk->id, &c);
85 
86 	if (err)
87 		return err;
88 	return clk_get_rate(c);
89 }
90 
ccf_clk_set_rate(struct clk * clk,unsigned long rate)91 ulong ccf_clk_set_rate(struct clk *clk, unsigned long rate)
92 {
93 	struct clk *c;
94 	int err = clk_get_by_id(clk->id, &c);
95 
96 	if (err)
97 		return err;
98 	return clk_set_rate(c, rate);
99 }
100 
ccf_clk_set_parent(struct clk * clk,struct clk * parent)101 int ccf_clk_set_parent(struct clk *clk, struct clk *parent)
102 {
103 	struct clk *c, *p;
104 	int err = clk_get_by_id(clk->id, &c);
105 
106 	if (err)
107 		return err;
108 
109 	err = clk_get_by_id(parent->id, &p);
110 	if (err)
111 		return err;
112 
113 	return clk_set_parent(c, p);
114 }
115 
ccf_clk_endisable(struct clk * clk,bool enable)116 static int ccf_clk_endisable(struct clk *clk, bool enable)
117 {
118 	struct clk *c;
119 	int err = clk_get_by_id(clk->id, &c);
120 
121 	if (err)
122 		return err;
123 	return enable ? clk_enable(c) : clk_disable(c);
124 }
125 
ccf_clk_enable(struct clk * clk)126 int ccf_clk_enable(struct clk *clk)
127 {
128 	return ccf_clk_endisable(clk, true);
129 }
130 
ccf_clk_disable(struct clk * clk)131 int ccf_clk_disable(struct clk *clk)
132 {
133 	return ccf_clk_endisable(clk, false);
134 }
135 
136 const struct clk_ops ccf_clk_ops = {
137 	.set_rate = ccf_clk_set_rate,
138 	.get_rate = ccf_clk_get_rate,
139 	.set_parent = ccf_clk_set_parent,
140 	.enable = ccf_clk_enable,
141 	.disable = ccf_clk_disable,
142 };
143