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