clk.c revision 1.2.12.3 1 1.2.12.3 pgoyette /* $NetBSD: clk.c,v 1.2.12.3 2018/06/25 07:25:49 pgoyette Exp $ */
2 1.1 jmcneill
3 1.1 jmcneill /*-
4 1.1 jmcneill * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.1 jmcneill * All rights reserved.
6 1.1 jmcneill *
7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without
8 1.1 jmcneill * modification, are permitted provided that the following conditions
9 1.1 jmcneill * are met:
10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright
11 1.1 jmcneill * notice, this list of conditions and the following disclaimer.
12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the
14 1.1 jmcneill * documentation and/or other materials provided with the distribution.
15 1.1 jmcneill *
16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 jmcneill * SUCH DAMAGE.
27 1.1 jmcneill */
28 1.1 jmcneill
29 1.1 jmcneill #include <sys/cdefs.h>
30 1.2.12.3 pgoyette __KERNEL_RCSID(0, "$NetBSD: clk.c,v 1.2.12.3 2018/06/25 07:25:49 pgoyette Exp $");
31 1.1 jmcneill
32 1.1 jmcneill #include <sys/param.h>
33 1.2.12.2 pgoyette #include <sys/sysctl.h>
34 1.1 jmcneill
35 1.1 jmcneill #include <dev/clk/clk.h>
36 1.1 jmcneill #include <dev/clk/clk_backend.h>
37 1.1 jmcneill
38 1.2.12.2 pgoyette static struct sysctllog *clk_log;
39 1.2.12.2 pgoyette static const struct sysctlnode *clk_node;
40 1.2.12.2 pgoyette
41 1.2.12.2 pgoyette static int
42 1.2.12.2 pgoyette create_clk_node(void)
43 1.2.12.2 pgoyette {
44 1.2.12.2 pgoyette const struct sysctlnode *hw_node;
45 1.2.12.2 pgoyette int error;
46 1.2.12.2 pgoyette
47 1.2.12.2 pgoyette if (clk_node)
48 1.2.12.2 pgoyette return 0;
49 1.2.12.2 pgoyette
50 1.2.12.2 pgoyette error = sysctl_createv(&clk_log, 0, NULL, &hw_node,
51 1.2.12.2 pgoyette CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
52 1.2.12.2 pgoyette NULL, 0, NULL, 0, CTL_HW, CTL_EOL);
53 1.2.12.2 pgoyette if (error)
54 1.2.12.2 pgoyette return error;
55 1.2.12.2 pgoyette
56 1.2.12.2 pgoyette error = sysctl_createv(&clk_log, 0, &hw_node, &clk_node,
57 1.2.12.2 pgoyette CTLFLAG_PERMANENT, CTLTYPE_NODE, "clk", NULL,
58 1.2.12.2 pgoyette NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
59 1.2.12.2 pgoyette if (error)
60 1.2.12.2 pgoyette return error;
61 1.2.12.2 pgoyette
62 1.2.12.2 pgoyette return 0;
63 1.2.12.2 pgoyette }
64 1.2.12.2 pgoyette
65 1.2.12.2 pgoyette static int
66 1.2.12.2 pgoyette create_domain_node(struct clk_domain *domain)
67 1.2.12.2 pgoyette {
68 1.2.12.2 pgoyette int error;
69 1.2.12.2 pgoyette
70 1.2.12.2 pgoyette if (domain->node)
71 1.2.12.2 pgoyette return 0;
72 1.2.12.2 pgoyette
73 1.2.12.2 pgoyette error = create_clk_node();
74 1.2.12.2 pgoyette if (error)
75 1.2.12.2 pgoyette return error;
76 1.2.12.2 pgoyette
77 1.2.12.2 pgoyette error = sysctl_createv(&clk_log, 0, &clk_node, &domain->node,
78 1.2.12.2 pgoyette 0, CTLTYPE_NODE, domain->name, NULL,
79 1.2.12.2 pgoyette NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
80 1.2.12.2 pgoyette if (error)
81 1.2.12.2 pgoyette return error;
82 1.2.12.2 pgoyette
83 1.2.12.2 pgoyette return 0;
84 1.2.12.2 pgoyette }
85 1.2.12.2 pgoyette
86 1.2.12.2 pgoyette static int
87 1.2.12.2 pgoyette clk_sysctl_rate_helper(SYSCTLFN_ARGS)
88 1.2.12.2 pgoyette {
89 1.2.12.2 pgoyette struct sysctlnode node;
90 1.2.12.2 pgoyette struct clk *clk;
91 1.2.12.2 pgoyette uint64_t rate;
92 1.2.12.2 pgoyette
93 1.2.12.2 pgoyette node = *rnode;
94 1.2.12.2 pgoyette clk = node.sysctl_data;
95 1.2.12.2 pgoyette node.sysctl_data = &rate;
96 1.2.12.2 pgoyette
97 1.2.12.2 pgoyette rate = clk_get_rate(clk);
98 1.2.12.2 pgoyette
99 1.2.12.2 pgoyette return sysctl_lookup(SYSCTLFN_CALL(&node));
100 1.2.12.2 pgoyette }
101 1.2.12.2 pgoyette
102 1.2.12.2 pgoyette static int
103 1.2.12.2 pgoyette clk_sysctl_parent_helper(SYSCTLFN_ARGS)
104 1.2.12.2 pgoyette {
105 1.2.12.2 pgoyette struct sysctlnode node;
106 1.2.12.2 pgoyette struct clk *clk, *clk_parent;
107 1.2.12.2 pgoyette
108 1.2.12.2 pgoyette node = *rnode;
109 1.2.12.2 pgoyette clk = node.sysctl_data;
110 1.2.12.2 pgoyette
111 1.2.12.2 pgoyette clk_parent = clk_get_parent(clk);
112 1.2.12.2 pgoyette if (clk_parent && clk_parent->name)
113 1.2.12.2 pgoyette node.sysctl_data = __UNCONST(clk_parent->name);
114 1.2.12.2 pgoyette else
115 1.2.12.2 pgoyette node.sysctl_data = __UNCONST("?");
116 1.2.12.2 pgoyette
117 1.2.12.2 pgoyette return sysctl_lookup(SYSCTLFN_CALL(&node));
118 1.2.12.2 pgoyette }
119 1.2.12.2 pgoyette
120 1.2.12.2 pgoyette static int
121 1.2.12.2 pgoyette clk_sysctl_parent_domain_helper(SYSCTLFN_ARGS)
122 1.2.12.2 pgoyette {
123 1.2.12.2 pgoyette struct sysctlnode node;
124 1.2.12.2 pgoyette struct clk *clk, *clk_parent;
125 1.2.12.2 pgoyette
126 1.2.12.2 pgoyette node = *rnode;
127 1.2.12.2 pgoyette clk = node.sysctl_data;
128 1.2.12.2 pgoyette
129 1.2.12.2 pgoyette clk_parent = clk_get_parent(clk);
130 1.2.12.2 pgoyette if (clk_parent && clk_parent->domain && clk_parent->domain->name)
131 1.2.12.2 pgoyette node.sysctl_data = __UNCONST(clk_parent->domain->name);
132 1.2.12.2 pgoyette else
133 1.2.12.2 pgoyette node.sysctl_data = __UNCONST("?");
134 1.2.12.2 pgoyette
135 1.2.12.2 pgoyette return sysctl_lookup(SYSCTLFN_CALL(&node));
136 1.2.12.2 pgoyette }
137 1.2.12.2 pgoyette
138 1.2.12.2 pgoyette int
139 1.2.12.2 pgoyette clk_attach(struct clk *clk)
140 1.2.12.2 pgoyette {
141 1.2.12.2 pgoyette const struct sysctlnode *node;
142 1.2.12.2 pgoyette struct clk_domain *domain = clk->domain;
143 1.2.12.2 pgoyette int error;
144 1.2.12.2 pgoyette
145 1.2.12.2 pgoyette KASSERT(domain != NULL);
146 1.2.12.2 pgoyette
147 1.2.12.2 pgoyette if (!domain->name || !clk->name) {
148 1.2.12.2 pgoyette /* Names are required to create sysctl nodes */
149 1.2.12.2 pgoyette return 0;
150 1.2.12.2 pgoyette }
151 1.2.12.2 pgoyette
152 1.2.12.2 pgoyette error = create_domain_node(domain);
153 1.2.12.2 pgoyette if (error != 0)
154 1.2.12.2 pgoyette goto sysctl_failed;
155 1.2.12.2 pgoyette
156 1.2.12.2 pgoyette error = sysctl_createv(&clk_log, 0, &domain->node, &node,
157 1.2.12.2 pgoyette CTLFLAG_PRIVATE, CTLTYPE_NODE, clk->name, NULL,
158 1.2.12.2 pgoyette NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
159 1.2.12.2 pgoyette if (error)
160 1.2.12.2 pgoyette goto sysctl_failed;
161 1.2.12.2 pgoyette
162 1.2.12.2 pgoyette error = sysctl_createv(&clk_log, 0, &node, NULL,
163 1.2.12.2 pgoyette CTLFLAG_PRIVATE, CTLTYPE_QUAD, "rate", NULL,
164 1.2.12.2 pgoyette clk_sysctl_rate_helper, 0, (void *)clk, 0,
165 1.2.12.2 pgoyette CTL_CREATE, CTL_EOL);
166 1.2.12.2 pgoyette if (error)
167 1.2.12.2 pgoyette goto sysctl_failed;
168 1.2.12.2 pgoyette
169 1.2.12.2 pgoyette error = sysctl_createv(&clk_log, 0, &node, NULL,
170 1.2.12.2 pgoyette CTLFLAG_PRIVATE, CTLTYPE_STRING, "parent", NULL,
171 1.2.12.2 pgoyette clk_sysctl_parent_helper, 0, (void *)clk, 0,
172 1.2.12.2 pgoyette CTL_CREATE, CTL_EOL);
173 1.2.12.2 pgoyette if (error)
174 1.2.12.2 pgoyette goto sysctl_failed;
175 1.2.12.2 pgoyette
176 1.2.12.2 pgoyette error = sysctl_createv(&clk_log, 0, &node, NULL,
177 1.2.12.2 pgoyette CTLFLAG_PRIVATE, CTLTYPE_STRING, "parent_domain", NULL,
178 1.2.12.2 pgoyette clk_sysctl_parent_domain_helper, 0, (void *)clk, 0,
179 1.2.12.2 pgoyette CTL_CREATE, CTL_EOL);
180 1.2.12.2 pgoyette if (error)
181 1.2.12.2 pgoyette goto sysctl_failed;
182 1.2.12.2 pgoyette
183 1.2.12.2 pgoyette sysctl_failed:
184 1.2.12.2 pgoyette if (error)
185 1.2.12.2 pgoyette aprint_error("%s: failed to create sysctl node for %s: %d\n",
186 1.2.12.2 pgoyette domain->name, clk->name, error);
187 1.2.12.2 pgoyette return error;
188 1.2.12.2 pgoyette }
189 1.2.12.2 pgoyette
190 1.1 jmcneill struct clk *
191 1.2 jmcneill clk_get(struct clk_domain *domain, const char *name)
192 1.1 jmcneill {
193 1.2 jmcneill return domain->funcs->get(domain->priv, name);
194 1.1 jmcneill }
195 1.1 jmcneill
196 1.1 jmcneill void
197 1.1 jmcneill clk_put(struct clk *clk)
198 1.1 jmcneill {
199 1.2 jmcneill return clk->domain->funcs->put(clk->domain->priv, clk);
200 1.1 jmcneill }
201 1.1 jmcneill
202 1.1 jmcneill u_int
203 1.1 jmcneill clk_get_rate(struct clk *clk)
204 1.1 jmcneill {
205 1.2 jmcneill return clk->domain->funcs->get_rate(clk->domain->priv, clk);
206 1.1 jmcneill }
207 1.1 jmcneill
208 1.1 jmcneill int
209 1.1 jmcneill clk_set_rate(struct clk *clk, u_int rate)
210 1.1 jmcneill {
211 1.2.12.3 pgoyette if (clk->flags & CLK_SET_RATE_PARENT)
212 1.1 jmcneill return clk_set_rate(clk_get_parent(clk), rate);
213 1.2.12.3 pgoyette
214 1.2.12.3 pgoyette if (clk->domain->funcs->set_rate)
215 1.2 jmcneill return clk->domain->funcs->set_rate(clk->domain->priv,
216 1.2 jmcneill clk, rate);
217 1.2.12.3 pgoyette
218 1.2.12.3 pgoyette if (clk_get_rate(clk) == rate)
219 1.2.12.3 pgoyette return 0;
220 1.2.12.3 pgoyette
221 1.2.12.3 pgoyette return EINVAL;
222 1.1 jmcneill }
223 1.1 jmcneill
224 1.2.12.1 pgoyette u_int
225 1.2.12.1 pgoyette clk_round_rate(struct clk *clk, u_int rate)
226 1.2.12.1 pgoyette {
227 1.2.12.1 pgoyette if (clk->domain->funcs->round_rate) {
228 1.2.12.1 pgoyette return clk->domain->funcs->round_rate(clk->domain->priv,
229 1.2.12.1 pgoyette clk, rate);
230 1.2.12.1 pgoyette }
231 1.2.12.1 pgoyette return 0;
232 1.2.12.1 pgoyette }
233 1.2.12.1 pgoyette
234 1.1 jmcneill int
235 1.1 jmcneill clk_enable(struct clk *clk)
236 1.1 jmcneill {
237 1.2 jmcneill if (clk->domain->funcs->enable)
238 1.2 jmcneill return clk->domain->funcs->enable(clk->domain->priv, clk);
239 1.2 jmcneill else
240 1.2 jmcneill return 0;
241 1.1 jmcneill }
242 1.1 jmcneill
243 1.1 jmcneill int
244 1.1 jmcneill clk_disable(struct clk *clk)
245 1.1 jmcneill {
246 1.2 jmcneill if (clk->domain->funcs->disable)
247 1.2 jmcneill return clk->domain->funcs->disable(clk->domain->priv, clk);
248 1.2 jmcneill else
249 1.2 jmcneill return EINVAL;
250 1.1 jmcneill }
251 1.1 jmcneill
252 1.1 jmcneill int
253 1.1 jmcneill clk_set_parent(struct clk *clk, struct clk *parent_clk)
254 1.1 jmcneill {
255 1.2 jmcneill if (clk->domain->funcs->set_parent)
256 1.2 jmcneill return clk->domain->funcs->set_parent(clk->domain->priv,
257 1.2 jmcneill clk, parent_clk);
258 1.2 jmcneill else
259 1.2 jmcneill return EINVAL;
260 1.1 jmcneill }
261 1.1 jmcneill
262 1.1 jmcneill struct clk *
263 1.1 jmcneill clk_get_parent(struct clk *clk)
264 1.1 jmcneill {
265 1.2.12.2 pgoyette if (clk->domain->funcs->get_parent)
266 1.2.12.2 pgoyette return clk->domain->funcs->get_parent(clk->domain->priv, clk);
267 1.2.12.2 pgoyette else
268 1.2.12.2 pgoyette return NULL;
269 1.1 jmcneill }
270