jh71x0_clkc.c revision 1.2 1 1.2 skrll /* $NetBSD: jh71x0_clkc.c,v 1.2 2024/08/04 08:16:26 skrll Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.1 skrll * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 1.1 skrll * All rights reserved.
6 1.1 skrll *
7 1.1 skrll * This code is derived from software contributed to The NetBSD Foundation
8 1.1 skrll * by Nick Hudson
9 1.1 skrll *
10 1.1 skrll * Redistribution and use in source and binary forms, with or without
11 1.1 skrll * modification, are permitted provided that the following conditions
12 1.1 skrll * are met:
13 1.1 skrll * 1. Redistributions of source code must retain the above copyright
14 1.1 skrll * notice, this list of conditions and the following disclaimer.
15 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 skrll * notice, this list of conditions and the following disclaimer in the
17 1.1 skrll * documentation and/or other materials provided with the distribution.
18 1.1 skrll *
19 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 skrll * POSSIBILITY OF SUCH DAMAGE.
30 1.1 skrll */
31 1.1 skrll
32 1.1 skrll #include <sys/cdefs.h>
33 1.2 skrll __KERNEL_RCSID(0, "$NetBSD: jh71x0_clkc.c,v 1.2 2024/08/04 08:16:26 skrll Exp $");
34 1.1 skrll
35 1.1 skrll #include <sys/param.h>
36 1.1 skrll
37 1.1 skrll #include <sys/bus.h>
38 1.1 skrll #include <sys/device.h>
39 1.1 skrll
40 1.1 skrll #include <dev/clk/clk_backend.h>
41 1.1 skrll
42 1.1 skrll #include <dev/fdt/fdtvar.h>
43 1.1 skrll
44 1.1 skrll #include <riscv/starfive/jh71x0_clkc.h>
45 1.1 skrll
46 1.1 skrll #define RD4(sc, reg) \
47 1.1 skrll bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
48 1.1 skrll #define WR4(sc, reg, val) \
49 1.1 skrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
50 1.1 skrll
51 1.1 skrll
52 1.1 skrll static void
53 1.1 skrll jh71x0_clkc_update(struct jh71x0_clkc_softc * const sc,
54 1.1 skrll struct jh71x0_clkc_clk *jcc, uint32_t set, uint32_t clr)
55 1.1 skrll {
56 1.1 skrll // lock
57 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
58 1.1 skrll val &= ~clr;
59 1.1 skrll val |= set;
60 1.1 skrll WR4(sc, jcc->jcc_reg, val);
61 1.1 skrll }
62 1.1 skrll
63 1.1 skrll /*
64 1.1 skrll * FIXED_FACTOR operations
65 1.1 skrll */
66 1.1 skrll
67 1.1 skrll static u_int
68 1.1 skrll jh71x0_clkc_fixed_factor_get_parent_rate(struct clk *clk)
69 1.1 skrll {
70 1.1 skrll struct clk *clk_parent = clk_get_parent(clk);
71 1.1 skrll if (clk_parent == NULL)
72 1.1 skrll return 0;
73 1.1 skrll
74 1.1 skrll return clk_get_rate(clk_parent);
75 1.1 skrll }
76 1.1 skrll
77 1.1 skrll u_int
78 1.1 skrll jh71x0_clkc_fixed_factor_get_rate(struct jh71x0_clkc_softc *sc,
79 1.1 skrll struct jh71x0_clkc_clk *jcc)
80 1.1 skrll {
81 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FIXED_FACTOR);
82 1.1 skrll
83 1.1 skrll struct jh71x0_clkc_fixed_factor * const jcff = &jcc->jcc_ffactor;
84 1.1 skrll struct clk *clk = &jcc->jcc_clk;
85 1.1 skrll
86 1.1 skrll uint64_t rate = jh71x0_clkc_fixed_factor_get_parent_rate(clk);
87 1.1 skrll if (rate == 0)
88 1.1 skrll return 0;
89 1.1 skrll
90 1.1 skrll rate *= jcff->jcff_mult;
91 1.1 skrll rate /= jcff->jcff_div;
92 1.1 skrll
93 1.1 skrll return rate;
94 1.1 skrll }
95 1.1 skrll
96 1.1 skrll static int
97 1.1 skrll jh71x0_clkc_fixed_factor_set_parent_rate(struct clk *clk, u_int rate)
98 1.1 skrll {
99 1.1 skrll struct clk *clk_parent = clk_get_parent(clk);
100 1.1 skrll if (clk_parent == NULL)
101 1.1 skrll return ENXIO;
102 1.1 skrll
103 1.1 skrll return clk_set_rate(clk_parent, rate);
104 1.1 skrll }
105 1.1 skrll
106 1.1 skrll int
107 1.1 skrll jh71x0_clkc_fixed_factor_set_rate(struct jh71x0_clkc_softc *sc,
108 1.1 skrll struct jh71x0_clkc_clk *jcc, u_int rate)
109 1.1 skrll {
110 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FIXED_FACTOR);
111 1.1 skrll
112 1.1 skrll struct jh71x0_clkc_fixed_factor * const jcff = &jcc->jcc_ffactor;
113 1.1 skrll struct clk *clk = &jcc->jcc_clk;
114 1.1 skrll
115 1.1 skrll
116 1.1 skrll uint64_t tmp = rate;
117 1.1 skrll tmp *= jcff->jcff_div;
118 1.1 skrll tmp /= jcff->jcff_mult;
119 1.1 skrll
120 1.1 skrll return jh71x0_clkc_fixed_factor_set_parent_rate(clk, tmp);
121 1.1 skrll }
122 1.1 skrll
123 1.1 skrll const char *
124 1.1 skrll jh71x0_clkc_fixed_factor_get_parent(struct jh71x0_clkc_softc *sc,
125 1.1 skrll struct jh71x0_clkc_clk *jcc)
126 1.1 skrll {
127 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FIXED_FACTOR);
128 1.1 skrll
129 1.1 skrll struct jh71x0_clkc_fixed_factor * const jcff = &jcc->jcc_ffactor;
130 1.1 skrll
131 1.1 skrll return jcff->jcff_parent;
132 1.1 skrll }
133 1.1 skrll
134 1.1 skrll
135 1.1 skrll /*
136 1.1 skrll * MUX operations
137 1.1 skrll */
138 1.1 skrll
139 1.1 skrll int
140 1.1 skrll jh71x0_clkc_mux_set_parent(struct jh71x0_clkc_softc *sc,
141 1.1 skrll struct jh71x0_clkc_clk *jcc, const char *name)
142 1.1 skrll {
143 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUX);
144 1.1 skrll
145 1.1 skrll struct jh71x0_clkc_mux * const jcm = &jcc->jcc_mux;
146 1.1 skrll
147 1.1 skrll size_t i;
148 1.1 skrll for (i = 0; i < jcm->jcm_nparents; i++) {
149 1.1 skrll if (jcm->jcm_parents[i] != NULL &&
150 1.1 skrll strcmp(jcm->jcm_parents[i], name) == 0)
151 1.1 skrll break;
152 1.1 skrll }
153 1.1 skrll if (i >= jcm->jcm_nparents)
154 1.1 skrll return EINVAL;
155 1.1 skrll
156 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
157 1.1 skrll val &= ~JH71X0_CLK_MUX_MASK;
158 1.1 skrll val |= __SHIFTIN(i, JH71X0_CLK_MUX_MASK);
159 1.1 skrll WR4(sc, jcc->jcc_reg, val);
160 1.1 skrll
161 1.1 skrll return 0;
162 1.1 skrll }
163 1.1 skrll
164 1.1 skrll
165 1.1 skrll const char *
166 1.1 skrll jh71x0_clkc_mux_get_parent(struct jh71x0_clkc_softc *sc,
167 1.1 skrll struct jh71x0_clkc_clk *jcc)
168 1.1 skrll {
169 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_MUX);
170 1.1 skrll
171 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
172 1.1 skrll size_t pindex = __SHIFTOUT(val, JH71X0_CLK_MUX_MASK);
173 1.1 skrll
174 1.1 skrll if (pindex >= jcc->jcc_mux.jcm_nparents)
175 1.1 skrll return NULL;
176 1.1 skrll
177 1.1 skrll return jcc->jcc_mux.jcm_parents[pindex];
178 1.1 skrll }
179 1.1 skrll
180 1.1 skrll
181 1.1 skrll /*
182 1.1 skrll * GATE operations
183 1.1 skrll */
184 1.1 skrll
185 1.1 skrll int
186 1.1 skrll jh71x0_clkc_gate_enable(struct jh71x0_clkc_softc *sc,
187 1.1 skrll struct jh71x0_clkc_clk *jcc, int enable)
188 1.1 skrll {
189 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_GATE);
190 1.1 skrll
191 1.1 skrll jh71x0_clkc_update(sc, jcc,
192 1.1 skrll (enable ? JH71X0_CLK_ENABLE : 0), JH71X0_CLK_ENABLE);
193 1.1 skrll
194 1.1 skrll return 0;
195 1.1 skrll }
196 1.1 skrll
197 1.1 skrll const char *
198 1.1 skrll jh71x0_clkc_gate_get_parent(struct jh71x0_clkc_softc *sc,
199 1.1 skrll struct jh71x0_clkc_clk *jcc)
200 1.1 skrll {
201 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_GATE);
202 1.1 skrll
203 1.1 skrll struct jh71x0_clkc_gate *jcc_gate = &jcc->jcc_gate;
204 1.1 skrll
205 1.1 skrll return jcc_gate->jcg_parent;
206 1.1 skrll }
207 1.1 skrll
208 1.1 skrll
209 1.1 skrll /*
210 1.1 skrll * DIVIDER operations
211 1.1 skrll */
212 1.1 skrll
213 1.1 skrll u_int
214 1.1 skrll jh71x0_clkc_div_get_rate(struct jh71x0_clkc_softc *sc,
215 1.1 skrll struct jh71x0_clkc_clk *jcc)
216 1.1 skrll {
217 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_DIV);
218 1.1 skrll
219 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
220 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
221 1.1 skrll
222 1.1 skrll if (clk_parent == NULL)
223 1.1 skrll return 0;
224 1.1 skrll
225 1.1 skrll u_int rate = clk_get_rate(clk_parent);
226 1.1 skrll if (rate == 0)
227 1.1 skrll return 0;
228 1.1 skrll
229 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
230 1.1 skrll uint32_t div = __SHIFTOUT(val, JH71X0_CLK_DIV_MASK);
231 1.1 skrll
232 1.1 skrll return rate / div;
233 1.1 skrll }
234 1.1 skrll
235 1.1 skrll int
236 1.1 skrll jh71x0_clkc_div_set_rate(struct jh71x0_clkc_softc *sc,
237 1.1 skrll struct jh71x0_clkc_clk *jcc, u_int new_rate)
238 1.1 skrll {
239 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_DIV);
240 1.1 skrll
241 1.1 skrll struct jh71x0_clkc_div * const jcc_div = &jcc->jcc_div;
242 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
243 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
244 1.1 skrll
245 1.1 skrll if (clk_parent == NULL)
246 1.1 skrll return ENXIO;
247 1.1 skrll
248 1.1 skrll if (jcc_div->jcd_maxdiv == 0)
249 1.1 skrll return ENXIO;
250 1.1 skrll
251 1.1 skrll u_int parent_rate = clk_get_rate(clk_parent);
252 1.1 skrll
253 1.1 skrll if (parent_rate == 0) {
254 1.1 skrll return (new_rate == 0) ? 0 : ERANGE;
255 1.1 skrll }
256 1.1 skrll u_int ratio = howmany(parent_rate, new_rate);
257 1.1 skrll u_int div = uimin(ratio, jcc_div->jcd_maxdiv);
258 1.1 skrll
259 1.1 skrll jh71x0_clkc_update(sc, jcc,
260 1.1 skrll __SHIFTIN(div, JH71X0_CLK_DIV_MASK), JH71X0_CLK_DIV_MASK);
261 1.1 skrll
262 1.1 skrll return 0;
263 1.1 skrll }
264 1.1 skrll
265 1.1 skrll const char *
266 1.1 skrll jh71x0_clkc_div_get_parent(struct jh71x0_clkc_softc *sc,
267 1.1 skrll struct jh71x0_clkc_clk *jcc)
268 1.1 skrll {
269 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_DIV);
270 1.1 skrll
271 1.1 skrll struct jh71x0_clkc_div *jcc_div = &jcc->jcc_div;
272 1.1 skrll
273 1.1 skrll return jcc_div->jcd_parent;
274 1.1 skrll }
275 1.1 skrll
276 1.1 skrll
277 1.1 skrll /*
278 1.1 skrll * FRACTIONAL DIVIDER operations
279 1.1 skrll */
280 1.1 skrll
281 1.1 skrll u_int
282 1.1 skrll jh71x0_clkc_fracdiv_get_rate(struct jh71x0_clkc_softc *sc,
283 1.1 skrll struct jh71x0_clkc_clk *jcc)
284 1.1 skrll {
285 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FRACDIV);
286 1.1 skrll
287 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
288 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
289 1.1 skrll
290 1.1 skrll if (clk_parent == NULL)
291 1.1 skrll return 0;
292 1.1 skrll
293 1.1 skrll
294 1.1 skrll u_int rate = clk_get_rate(clk_parent);
295 1.1 skrll if (rate == 0)
296 1.1 skrll return 0;
297 1.1 skrll
298 1.1 skrll uint32_t val = RD4(sc, jcc->jcc_reg);
299 1.1 skrll unsigned long div100 =
300 1.1 skrll 100UL * __SHIFTOUT(val, JH71X0_CLK_INT_MASK) +
301 1.2 skrll __SHIFTOUT(val, JH71X0_CLK_FRAC_MASK);
302 1.1 skrll
303 1.1 skrll return (div100 >= JH71X0_CLK_FRAC_MIN) ? 100UL * rate / div100 : 0;
304 1.1 skrll }
305 1.1 skrll
306 1.1 skrll int
307 1.1 skrll jh71x0_clkc_fracdiv_set_rate(struct jh71x0_clkc_softc *sc,
308 1.1 skrll struct jh71x0_clkc_clk *jcc, u_int new_rate)
309 1.1 skrll {
310 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FRACDIV);
311 1.1 skrll
312 1.1 skrll // struct jh71x0_clkc_fracdiv * const jcc_fracdiv = &jcc->jcc_fracdiv;
313 1.1 skrll struct clk * const clk = &jcc->jcc_clk;
314 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
315 1.1 skrll
316 1.1 skrll if (clk_parent == NULL)
317 1.1 skrll return ENXIO;
318 1.1 skrll
319 1.1 skrll #if 0
320 1.1 skrll if (jcc_div->jcd_maxdiv == 0)
321 1.1 skrll return ENXIO;
322 1.1 skrll
323 1.1 skrll u_int parent_rate = clk_get_rate(clk_parent);
324 1.1 skrll
325 1.1 skrll if (parent_rate == 0) {
326 1.1 skrll return (new_rate == 0) ? 0 : ERANGE;
327 1.1 skrll }
328 1.1 skrll u_int ratio = howmany(parent_rate, new_rate);
329 1.1 skrll u_int div = uimin(ratio, jcc_div->jcd_maxdiv);
330 1.1 skrll
331 1.1 skrll jh71x0_clkc_update(sc, jcc,
332 1.1 skrll __SHIFTIN(div, JH71X0_CLK_DIV_MASK), JH71X0_CLK_DIV_MASK);
333 1.1 skrll #endif
334 1.1 skrll
335 1.1 skrll return 0;
336 1.1 skrll }
337 1.1 skrll
338 1.1 skrll const char *
339 1.1 skrll jh71x0_clkc_fracdiv_get_parent(struct jh71x0_clkc_softc *sc,
340 1.1 skrll struct jh71x0_clkc_clk *jcc)
341 1.1 skrll {
342 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_FRACDIV);
343 1.1 skrll
344 1.1 skrll struct jh71x0_clkc_fracdiv *jcc_fracdiv = &jcc->jcc_fracdiv;
345 1.1 skrll
346 1.1 skrll return jcc_fracdiv->jcd_parent;
347 1.1 skrll }
348 1.1 skrll
349 1.1 skrll
350 1.1 skrll /*
351 1.1 skrll * INV operations
352 1.1 skrll */
353 1.1 skrll const char *
354 1.1 skrll jh71x0_clkc_inv_get_parent(struct jh71x0_clkc_softc *sc,
355 1.1 skrll struct jh71x0_clkc_clk *jcc)
356 1.1 skrll {
357 1.1 skrll KASSERT(jcc->jcc_type == JH71X0CLK_INV);
358 1.1 skrll
359 1.1 skrll struct jh71x0_clkc_inv * const jci = &jcc->jcc_inv;
360 1.1 skrll
361 1.1 skrll return jci->jci_parent;
362 1.1 skrll }
363 1.1 skrll
364 1.1 skrll
365 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_gate_ops = {
366 1.1 skrll .jcco_enable = jh71x0_clkc_gate_enable,
367 1.1 skrll .jcco_getparent = jh71x0_clkc_gate_get_parent,
368 1.1 skrll };
369 1.1 skrll
370 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_div_ops = {
371 1.1 skrll .jcco_setrate = jh71x0_clkc_div_set_rate,
372 1.1 skrll .jcco_getrate = jh71x0_clkc_div_get_rate,
373 1.1 skrll .jcco_getparent = jh71x0_clkc_div_get_parent,
374 1.1 skrll };
375 1.1 skrll
376 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_fracdiv_ops = {
377 1.1 skrll .jcco_setrate = jh71x0_clkc_fracdiv_set_rate,
378 1.1 skrll .jcco_getrate = jh71x0_clkc_fracdiv_get_rate,
379 1.1 skrll .jcco_getparent = jh71x0_clkc_fracdiv_get_parent,
380 1.1 skrll };
381 1.1 skrll
382 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_ffactor_ops = {
383 1.1 skrll .jcco_setrate = jh71x0_clkc_fixed_factor_set_rate,
384 1.1 skrll .jcco_getrate = jh71x0_clkc_fixed_factor_get_rate,
385 1.1 skrll .jcco_getparent = jh71x0_clkc_fixed_factor_get_parent,
386 1.1 skrll };
387 1.1 skrll
388 1.1 skrll
389 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_mux_ops = {
390 1.1 skrll .jcco_setparent = jh71x0_clkc_mux_set_parent,
391 1.1 skrll .jcco_getparent = jh71x0_clkc_mux_get_parent,
392 1.1 skrll };
393 1.1 skrll
394 1.1 skrll
395 1.1 skrll struct jh71x0_clkc_clkops jh71x0_clkc_inv_ops = {
396 1.1 skrll .jcco_getparent = jh71x0_clkc_inv_get_parent,
397 1.1 skrll };
398 1.1 skrll
399 1.1 skrll static struct clk *
400 1.1 skrll jh71x0_clkc_get(void *priv, const char *name)
401 1.1 skrll {
402 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
403 1.1 skrll
404 1.1 skrll for (u_int id = 0; id < sc->sc_nclks; id++) {
405 1.1 skrll struct jh71x0_clkc_clk * const jcc = &sc->sc_clk[id];
406 1.1 skrll
407 1.1 skrll if (strcmp(name, jcc->jcc_clk.name) == 0) {
408 1.1 skrll return &jcc->jcc_clk;
409 1.1 skrll }
410 1.1 skrll }
411 1.1 skrll
412 1.1 skrll return NULL;
413 1.1 skrll }
414 1.1 skrll
415 1.1 skrll static void
416 1.1 skrll jh71x0_clkc_put(void *priv, struct clk *clk)
417 1.1 skrll {
418 1.1 skrll }
419 1.1 skrll
420 1.1 skrll
421 1.1 skrll static int
422 1.1 skrll jh71x0_clkc_set_rate(void *priv, struct clk *clk, u_int rate)
423 1.1 skrll {
424 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
425 1.1 skrll struct jh71x0_clkc_clk * const jcc =
426 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
427 1.1 skrll
428 1.1 skrll if (clk->flags & CLK_SET_RATE_PARENT) {
429 1.1 skrll struct clk *clk_parent = clk_get_parent(clk);
430 1.1 skrll if (clk_parent == NULL) {
431 1.1 skrll aprint_debug("%s: no parent for %s\n", __func__,
432 1.1 skrll jcc->jcc_clk.name);
433 1.1 skrll return ENXIO;
434 1.1 skrll }
435 1.1 skrll return clk_set_rate(clk_parent, rate);
436 1.1 skrll }
437 1.1 skrll
438 1.1 skrll if (jcc->jcc_ops->jcco_setrate)
439 1.1 skrll return jcc->jcc_ops->jcco_setrate(sc, jcc, rate);
440 1.1 skrll
441 1.1 skrll return ENXIO;
442 1.1 skrll }
443 1.1 skrll
444 1.1 skrll static u_int
445 1.1 skrll jh71x0_clkc_get_rate(void *priv, struct clk *clk)
446 1.1 skrll {
447 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
448 1.1 skrll struct jh71x0_clkc_clk * const jcc =
449 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
450 1.1 skrll
451 1.1 skrll if (jcc->jcc_ops->jcco_getrate)
452 1.1 skrll return jcc->jcc_ops->jcco_getrate(sc, jcc);
453 1.1 skrll
454 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
455 1.1 skrll if (clk_parent == NULL) {
456 1.1 skrll aprint_debug("%s: no parent for %s\n", __func__,
457 1.1 skrll jcc->jcc_clk.name);
458 1.1 skrll return 0;
459 1.1 skrll }
460 1.1 skrll
461 1.1 skrll return clk_get_rate(clk_parent);
462 1.1 skrll }
463 1.1 skrll
464 1.1 skrll static int
465 1.1 skrll jh71x0_clkc_enable(void *priv, struct clk *clk)
466 1.1 skrll {
467 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
468 1.1 skrll struct jh71x0_clkc_clk * const jcc =
469 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
470 1.1 skrll
471 1.1 skrll struct clk * const clk_parent = clk_get_parent(clk);
472 1.1 skrll if (clk_parent != NULL) {
473 1.1 skrll int error = clk_enable(clk_parent);
474 1.1 skrll if (error != 0)
475 1.1 skrll return error;
476 1.1 skrll }
477 1.1 skrll
478 1.1 skrll switch (jcc->jcc_type) {
479 1.1 skrll case JH71X0CLK_GATE:
480 1.1 skrll jh71x0_clkc_update(sc, jcc, JH71X0_CLK_ENABLE, 0);
481 1.1 skrll break;
482 1.1 skrll
483 1.1 skrll case JH71X0CLK_DIV: {
484 1.1 skrll struct jh71x0_clkc_div * const jcc_div = &jcc->jcc_div;
485 1.1 skrll if (jcc_div->jcd_flags & JH71X0CLKC_DIV_GATE) {
486 1.1 skrll jh71x0_clkc_update(sc, jcc, JH71X0_CLK_ENABLE, 0);
487 1.1 skrll break;
488 1.1 skrll }
489 1.1 skrll break;
490 1.1 skrll }
491 1.1 skrll
492 1.1 skrll case JH71X0CLK_FIXED_FACTOR:
493 1.1 skrll case JH71X0CLK_MUX:
494 1.1 skrll case JH71X0CLK_INV:
495 1.1 skrll break;
496 1.1 skrll
497 1.1 skrll default:
498 1.1 skrll printf("%s: type %d\n", __func__, jcc->jcc_type);
499 1.1 skrll return ENXIO;
500 1.1 skrll }
501 1.1 skrll return 0;
502 1.1 skrll }
503 1.1 skrll
504 1.1 skrll static int
505 1.1 skrll jh71x0_clkc_disable(void *priv, struct clk *clk)
506 1.1 skrll {
507 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
508 1.1 skrll struct jh71x0_clkc_clk * const jcc =
509 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
510 1.1 skrll
511 1.1 skrll switch (jcc->jcc_type) {
512 1.1 skrll case JH71X0CLK_GATE:
513 1.1 skrll jh71x0_clkc_update(sc, jcc, JH71X0_CLK_ENABLE, 0);
514 1.1 skrll return 0;
515 1.1 skrll
516 1.1 skrll default:
517 1.1 skrll return ENXIO;
518 1.1 skrll }
519 1.1 skrll }
520 1.1 skrll
521 1.1 skrll
522 1.1 skrll
523 1.1 skrll static struct jh71x0_clkc_clk *
524 1.1 skrll jh71x0_clkc_clock_find(struct jh71x0_clkc_softc *sc, const char *name)
525 1.1 skrll {
526 1.1 skrll for (size_t id = 0; id < sc->sc_nclks; id++) {
527 1.1 skrll struct jh71x0_clkc_clk * const jcc = &sc->sc_clk[id];
528 1.1 skrll
529 1.1 skrll if (jcc->jcc_clk.name == NULL)
530 1.1 skrll continue;
531 1.1 skrll if (strcmp(jcc->jcc_clk.name, name) == 0)
532 1.1 skrll return jcc;
533 1.1 skrll }
534 1.1 skrll
535 1.1 skrll return NULL;
536 1.1 skrll }
537 1.1 skrll
538 1.1 skrll
539 1.1 skrll
540 1.1 skrll static int
541 1.1 skrll jh71x0_clkc_set_parent(void *priv, struct clk *clk,
542 1.1 skrll struct clk *clk_parent)
543 1.1 skrll {
544 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
545 1.1 skrll struct jh71x0_clkc_clk * const jcc =
546 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
547 1.1 skrll
548 1.1 skrll if (jcc->jcc_ops->jcco_setparent == NULL)
549 1.1 skrll return EINVAL;
550 1.1 skrll
551 1.1 skrll return jcc->jcc_ops->jcco_setparent(sc, jcc, clk_parent->name);
552 1.1 skrll }
553 1.1 skrll
554 1.1 skrll
555 1.1 skrll static struct clk *
556 1.1 skrll jh71x0_clkc_get_parent(void *priv, struct clk *clk)
557 1.1 skrll {
558 1.1 skrll struct jh71x0_clkc_softc * const sc = priv;
559 1.1 skrll struct jh71x0_clkc_clk * const jcc =
560 1.1 skrll container_of(clk, struct jh71x0_clkc_clk, jcc_clk);
561 1.1 skrll
562 1.1 skrll if (jcc->jcc_ops->jcco_getparent == NULL)
563 1.1 skrll return NULL;
564 1.1 skrll
565 1.1 skrll const char *parent = jcc->jcc_ops->jcco_getparent(sc, jcc);
566 1.1 skrll if (parent == NULL)
567 1.1 skrll return NULL;
568 1.1 skrll
569 1.1 skrll struct jh71x0_clkc_clk *jcc_parent = jh71x0_clkc_clock_find(sc, parent);
570 1.1 skrll if (jcc_parent != NULL)
571 1.1 skrll return &jcc_parent->jcc_clk;
572 1.1 skrll
573 1.1 skrll /* No parent in this domain, try FDT */
574 1.1 skrll return fdtbus_clock_get(sc->sc_phandle, parent);
575 1.1 skrll }
576 1.1 skrll
577 1.1 skrll
578 1.1 skrll const struct clk_funcs jh71x0_clkc_funcs = {
579 1.1 skrll .get = jh71x0_clkc_get,
580 1.1 skrll .put = jh71x0_clkc_put,
581 1.1 skrll .set_rate = jh71x0_clkc_set_rate,
582 1.1 skrll .get_rate = jh71x0_clkc_get_rate,
583 1.1 skrll .enable = jh71x0_clkc_enable,
584 1.1 skrll .disable = jh71x0_clkc_disable,
585 1.1 skrll .set_parent = jh71x0_clkc_set_parent,
586 1.1 skrll .get_parent = jh71x0_clkc_get_parent,
587 1.1 skrll };
588 1.1 skrll
589