clk.c revision 1.4 1 1.4 jmcneill /* $NetBSD: clk.c,v 1.4 2018/04/28 15:20:33 jmcneill 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.4 jmcneill __KERNEL_RCSID(0, "$NetBSD: clk.c,v 1.4 2018/04/28 15:20:33 jmcneill Exp $");
31 1.1 jmcneill
32 1.1 jmcneill #include <sys/param.h>
33 1.4 jmcneill #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.4 jmcneill static struct sysctllog *clk_log;
39 1.4 jmcneill static const struct sysctlnode *clk_node;
40 1.4 jmcneill
41 1.4 jmcneill static int
42 1.4 jmcneill create_clk_node(void)
43 1.4 jmcneill {
44 1.4 jmcneill const struct sysctlnode *hw_node;
45 1.4 jmcneill int error;
46 1.4 jmcneill
47 1.4 jmcneill if (clk_node)
48 1.4 jmcneill return 0;
49 1.4 jmcneill
50 1.4 jmcneill error = sysctl_createv(&clk_log, 0, NULL, &hw_node,
51 1.4 jmcneill CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
52 1.4 jmcneill NULL, 0, NULL, 0, CTL_HW, CTL_EOL);
53 1.4 jmcneill if (error)
54 1.4 jmcneill return error;
55 1.4 jmcneill
56 1.4 jmcneill error = sysctl_createv(&clk_log, 0, &hw_node, &clk_node,
57 1.4 jmcneill CTLFLAG_PERMANENT, CTLTYPE_NODE, "clk", NULL,
58 1.4 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
59 1.4 jmcneill if (error)
60 1.4 jmcneill return error;
61 1.4 jmcneill
62 1.4 jmcneill return 0;
63 1.4 jmcneill }
64 1.4 jmcneill
65 1.4 jmcneill static int
66 1.4 jmcneill create_domain_node(struct clk_domain *domain)
67 1.4 jmcneill {
68 1.4 jmcneill int error;
69 1.4 jmcneill
70 1.4 jmcneill if (domain->node)
71 1.4 jmcneill return 0;
72 1.4 jmcneill
73 1.4 jmcneill error = create_clk_node();
74 1.4 jmcneill if (error)
75 1.4 jmcneill return error;
76 1.4 jmcneill
77 1.4 jmcneill error = sysctl_createv(&clk_log, 0, &clk_node, &domain->node,
78 1.4 jmcneill 0, CTLTYPE_NODE, domain->name, NULL,
79 1.4 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
80 1.4 jmcneill if (error)
81 1.4 jmcneill return error;
82 1.4 jmcneill
83 1.4 jmcneill return 0;
84 1.4 jmcneill }
85 1.4 jmcneill
86 1.4 jmcneill static int
87 1.4 jmcneill clk_sysctl_rate_helper(SYSCTLFN_ARGS)
88 1.4 jmcneill {
89 1.4 jmcneill struct sysctlnode node;
90 1.4 jmcneill struct clk *clk;
91 1.4 jmcneill uint64_t rate;
92 1.4 jmcneill
93 1.4 jmcneill node = *rnode;
94 1.4 jmcneill clk = node.sysctl_data;
95 1.4 jmcneill node.sysctl_data = &rate;
96 1.4 jmcneill
97 1.4 jmcneill rate = clk_get_rate(clk);
98 1.4 jmcneill
99 1.4 jmcneill return sysctl_lookup(SYSCTLFN_CALL(&node));
100 1.4 jmcneill }
101 1.4 jmcneill
102 1.4 jmcneill static int
103 1.4 jmcneill clk_sysctl_parent_helper(SYSCTLFN_ARGS)
104 1.4 jmcneill {
105 1.4 jmcneill struct sysctlnode node;
106 1.4 jmcneill struct clk *clk, *clk_parent;
107 1.4 jmcneill
108 1.4 jmcneill node = *rnode;
109 1.4 jmcneill clk = node.sysctl_data;
110 1.4 jmcneill
111 1.4 jmcneill clk_parent = clk_get_parent(clk);
112 1.4 jmcneill if (clk_parent && clk_parent->name)
113 1.4 jmcneill node.sysctl_data = __UNCONST(clk_parent->name);
114 1.4 jmcneill else
115 1.4 jmcneill node.sysctl_data = __UNCONST("?");
116 1.4 jmcneill
117 1.4 jmcneill return sysctl_lookup(SYSCTLFN_CALL(&node));
118 1.4 jmcneill }
119 1.4 jmcneill
120 1.4 jmcneill static int
121 1.4 jmcneill clk_sysctl_parent_domain_helper(SYSCTLFN_ARGS)
122 1.4 jmcneill {
123 1.4 jmcneill struct sysctlnode node;
124 1.4 jmcneill struct clk *clk, *clk_parent;
125 1.4 jmcneill
126 1.4 jmcneill node = *rnode;
127 1.4 jmcneill clk = node.sysctl_data;
128 1.4 jmcneill
129 1.4 jmcneill clk_parent = clk_get_parent(clk);
130 1.4 jmcneill if (clk_parent && clk_parent->domain && clk_parent->domain->name)
131 1.4 jmcneill node.sysctl_data = __UNCONST(clk_parent->domain->name);
132 1.4 jmcneill else
133 1.4 jmcneill node.sysctl_data = __UNCONST("?");
134 1.4 jmcneill
135 1.4 jmcneill return sysctl_lookup(SYSCTLFN_CALL(&node));
136 1.4 jmcneill }
137 1.4 jmcneill
138 1.4 jmcneill int
139 1.4 jmcneill clk_attach(struct clk *clk)
140 1.4 jmcneill {
141 1.4 jmcneill const struct sysctlnode *node;
142 1.4 jmcneill struct clk_domain *domain = clk->domain;
143 1.4 jmcneill int error;
144 1.4 jmcneill
145 1.4 jmcneill KASSERT(domain != NULL);
146 1.4 jmcneill
147 1.4 jmcneill if (!domain->name || !clk->name) {
148 1.4 jmcneill /* Names are required to create sysctl nodes */
149 1.4 jmcneill return 0;
150 1.4 jmcneill }
151 1.4 jmcneill
152 1.4 jmcneill error = create_domain_node(domain);
153 1.4 jmcneill if (error != 0)
154 1.4 jmcneill goto sysctl_failed;
155 1.4 jmcneill
156 1.4 jmcneill error = sysctl_createv(&clk_log, 0, &domain->node, &node,
157 1.4 jmcneill CTLFLAG_PRIVATE, CTLTYPE_NODE, clk->name, NULL,
158 1.4 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
159 1.4 jmcneill if (error)
160 1.4 jmcneill goto sysctl_failed;
161 1.4 jmcneill
162 1.4 jmcneill error = sysctl_createv(&clk_log, 0, &node, NULL,
163 1.4 jmcneill CTLFLAG_PRIVATE, CTLTYPE_QUAD, "rate", NULL,
164 1.4 jmcneill clk_sysctl_rate_helper, 0, (void *)clk, 0,
165 1.4 jmcneill CTL_CREATE, CTL_EOL);
166 1.4 jmcneill if (error)
167 1.4 jmcneill goto sysctl_failed;
168 1.4 jmcneill
169 1.4 jmcneill error = sysctl_createv(&clk_log, 0, &node, NULL,
170 1.4 jmcneill CTLFLAG_PRIVATE, CTLTYPE_STRING, "parent", NULL,
171 1.4 jmcneill clk_sysctl_parent_helper, 0, (void *)clk, 0,
172 1.4 jmcneill CTL_CREATE, CTL_EOL);
173 1.4 jmcneill if (error)
174 1.4 jmcneill goto sysctl_failed;
175 1.4 jmcneill
176 1.4 jmcneill error = sysctl_createv(&clk_log, 0, &node, NULL,
177 1.4 jmcneill CTLFLAG_PRIVATE, CTLTYPE_STRING, "parent_domain", NULL,
178 1.4 jmcneill clk_sysctl_parent_domain_helper, 0, (void *)clk, 0,
179 1.4 jmcneill CTL_CREATE, CTL_EOL);
180 1.4 jmcneill if (error)
181 1.4 jmcneill goto sysctl_failed;
182 1.4 jmcneill
183 1.4 jmcneill sysctl_failed:
184 1.4 jmcneill if (error)
185 1.4 jmcneill aprint_error("%s: failed to create sysctl node for %s: %d\n",
186 1.4 jmcneill domain->name, clk->name, error);
187 1.4 jmcneill return error;
188 1.4 jmcneill }
189 1.4 jmcneill
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.1 jmcneill if (clk->flags & CLK_SET_RATE_PARENT) {
212 1.1 jmcneill return clk_set_rate(clk_get_parent(clk), rate);
213 1.2 jmcneill } else if (clk->domain->funcs->set_rate) {
214 1.2 jmcneill return clk->domain->funcs->set_rate(clk->domain->priv,
215 1.2 jmcneill clk, rate);
216 1.1 jmcneill } else {
217 1.2 jmcneill return EINVAL;
218 1.1 jmcneill }
219 1.1 jmcneill }
220 1.1 jmcneill
221 1.3 bouyer u_int
222 1.3 bouyer clk_round_rate(struct clk *clk, u_int rate)
223 1.3 bouyer {
224 1.3 bouyer if (clk->domain->funcs->round_rate) {
225 1.3 bouyer return clk->domain->funcs->round_rate(clk->domain->priv,
226 1.3 bouyer clk, rate);
227 1.3 bouyer }
228 1.3 bouyer return 0;
229 1.3 bouyer }
230 1.3 bouyer
231 1.1 jmcneill int
232 1.1 jmcneill clk_enable(struct clk *clk)
233 1.1 jmcneill {
234 1.2 jmcneill if (clk->domain->funcs->enable)
235 1.2 jmcneill return clk->domain->funcs->enable(clk->domain->priv, clk);
236 1.2 jmcneill else
237 1.2 jmcneill return 0;
238 1.1 jmcneill }
239 1.1 jmcneill
240 1.1 jmcneill int
241 1.1 jmcneill clk_disable(struct clk *clk)
242 1.1 jmcneill {
243 1.2 jmcneill if (clk->domain->funcs->disable)
244 1.2 jmcneill return clk->domain->funcs->disable(clk->domain->priv, clk);
245 1.2 jmcneill else
246 1.2 jmcneill return EINVAL;
247 1.1 jmcneill }
248 1.1 jmcneill
249 1.1 jmcneill int
250 1.1 jmcneill clk_set_parent(struct clk *clk, struct clk *parent_clk)
251 1.1 jmcneill {
252 1.2 jmcneill if (clk->domain->funcs->set_parent)
253 1.2 jmcneill return clk->domain->funcs->set_parent(clk->domain->priv,
254 1.2 jmcneill clk, parent_clk);
255 1.2 jmcneill else
256 1.2 jmcneill return EINVAL;
257 1.1 jmcneill }
258 1.1 jmcneill
259 1.1 jmcneill struct clk *
260 1.1 jmcneill clk_get_parent(struct clk *clk)
261 1.1 jmcneill {
262 1.4 jmcneill if (clk->domain->funcs->get_parent)
263 1.4 jmcneill return clk->domain->funcs->get_parent(clk->domain->priv, clk);
264 1.4 jmcneill else
265 1.4 jmcneill return NULL;
266 1.1 jmcneill }
267