exynos5422_clock.c revision 1.1 1 /* $NetBSD: exynos5422_clock.c,v 1.1 2015/12/05 13:32:27 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include "locators.h"
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: exynos5422_clock.c,v 1.1 2015/12/05 13:32:27 jmcneill Exp $");
33
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/device.h>
37 #include <sys/intr.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/atomic.h>
41
42 #include <dev/clk/clk_backend.h>
43
44 #include <arm/samsung/exynos_reg.h>
45 #include <arm/samsung/exynos_var.h>
46 #include <arm/samsung/exynos_clock.h>
47
48 static struct clk *exynos5422_clock_get(void *, const char *);
49 static void exynos5422_clock_put(void *, struct clk *);
50 static u_int exynos5422_clock_get_rate(void *, struct clk *);
51 static int exynos5422_clock_set_rate(void *, struct clk *, u_int);
52 static int exynos5422_clock_enable(void *, struct clk *);
53 static int exynos5422_clock_disable(void *, struct clk *);
54 static int exynos5422_clock_set_parent(void *, struct clk *, struct clk *);
55 static struct clk *exynos5422_clock_get_parent(void *, struct clk *);
56
57 static const struct clk_funcs exynos5422_clock_funcs = {
58 .get = exynos5422_clock_get,
59 .put = exynos5422_clock_put,
60 .get_rate = exynos5422_clock_get_rate,
61 .set_rate = exynos5422_clock_set_rate,
62 .enable = exynos5422_clock_enable,
63 .disable = exynos5422_clock_disable,
64 .set_parent = exynos5422_clock_set_parent,
65 .get_parent = exynos5422_clock_get_parent,
66 };
67
68 #define CLK_FIXED(_name, _rate) { \
69 .base = { .name = (_name) }, .type = EXYNOS_CLK_FIXED, \
70 .u = { .fixed = { .rate = (_rate) } } \
71 }
72
73 #define CLK_PLL(_name, _parent, _base) { \
74 .base = { .name = (_name) }, .type = EXYNOS_CLK_PLL, \
75 .parent = (_parent), \
76 .u = { \
77 .pll = { \
78 .con0_reg = (_base) + PLL_CON0_OFFSET, \
79 .lock_reg = (_base) + PLL_LOCK_OFFSET, \
80 } \
81 } \
82 }
83
84 #define CLK_MUXF(_name, _alias, _reg, _bits, _f, _p) { \
85 .base = { .name = (_name), .flags = (_f) }, \
86 .type = EXYNOS_CLK_MUX, \
87 .alias = (_alias), \
88 .u = { \
89 .mux = { \
90 .nparents = __arraycount(_p), \
91 .parents = (_p), \
92 .reg = (_reg), \
93 .bits = (_bits) \
94 } \
95 } \
96 }
97
98 #define CLK_MUXA(_name, _alias, _reg, _bits, _p) \
99 CLK_MUXF(_name, _alias, _reg, _bits, 0, _p)
100
101 #define CLK_MUX(_name, _reg, _bits, _p) \
102 CLK_MUXF(_name, NULL, _reg, _bits, 0, _p)
103
104 #define CLK_DIV(_name, _parent, _reg, _bits) { \
105 .base = { .name = (_name) }, .type = EXYNOS_CLK_DIV, \
106 .parent = (_parent), \
107 .u = { \
108 .div = { \
109 .reg = (_reg), \
110 .bits = (_bits) \
111 } \
112 } \
113 }
114
115 #define CLK_GATE(_name, _parent, _reg, _bits, _f) { \
116 .base = { .name = (_name), .flags = (_f) }, \
117 .type = EXYNOS_CLK_GATE, \
118 .parent = (_parent), \
119 .u = { \
120 .gate = { \
121 .reg = (_reg), \
122 .bits = (_bits) \
123 } \
124 } \
125 }
126
127 #define EXYNOS5422_APLL_BASE 0x00000
128 #define EXYNOS5422_CPLL_BASE 0x10020
129 #define EXYNOS5422_DPLL_BASE 0x10030
130 #define EXYNOS5422_EPLL_BASE 0x10040
131 #define EXYNOS5422_RPLL_BASE 0x10050
132 #define EXYNOS5422_IPLL_BASE 0x10060
133 #define EXYNOS5422_SPLL_BASE 0x10070
134 #define EXYNOS5422_VPLL_BASE 0x10080
135 #define EXYNOS5422_MPLL_BASE 0x10090
136 #define EXYNOS5422_BPLL_BASE 0x20010
137 #define EXYNOS5422_KPLL_BASE 0x28000
138
139 #define EXYNOS5422_SRC_CPU 0x00200
140 #define EXYNOS5422_SRC_TOP0 0x10200
141 #define EXYNOS5422_SRC_TOP1 0x10204
142 #define EXYNOS5422_SRC_TOP2 0x10208
143 #define EXYNOS5422_SRC_TOP3 0x1020c
144 #define EXYNOS5422_SRC_TOP4 0x10210
145 #define EXYNOS5422_SRC_TOP5 0x10214
146 #define EXYNOS5422_SRC_TOP6 0x10218
147 #define EXYNOS5422_SRC_TOP7 0x1021c
148 #define EXYNOS5422_SRC_DISP10 0x1022c
149 #define EXYNOS5422_SRC_MAU 0x10240
150 #define EXYNOS5422_SRC_FSYS 0x10244
151 #define EXYNOS5422_SRC_PERIC0 0x10250
152 #define EXYNOS5422_SRC_PERIC1 0x10254
153 #define EXYNOS5422_SRC_ISP 0x10270
154 #define EXYNOS5422_SRC_TOP10 0x10280
155 #define EXYNOS5422_SRC_TOP11 0x10280
156 #define EXYNOS5422_SRC_TOP12 0x10280
157
158 #define EXYNOS5422_DIV_FSYS1 0x1054c
159
160 #define EXYNOS5422_GATE_TOP_SCLK_FSYS 0x10840
161
162 static const char *mout_cpll_p[] = { "fin_pll", "fout_cpll" };
163 static const char *mout_dpll_p[] = { "fin_pll", "fout_dpll" };
164 static const char *mout_mpll_p[] = { "fin_pll", "fout_mpll" };
165 static const char *mout_spll_p[] = { "fin_pll", "fout_spll" };
166 static const char *mout_ipll_p[] = { "fin_pll", "fout_ipll" };
167 static const char *mout_epll_p[] = { "fin_pll", "fout_epll" };
168 static const char *mout_rpll_p[] = { "fin_pll", "fout_rpll" };
169 static const char *mout_group2_p[] =
170 { "fin_pll", "sclk_cpll", "sclk_dpll", "sclk_mpll",
171 "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
172
173 static struct exynos_clk exynos5422_clocks[] = {
174 CLK_FIXED("fin_pll", EXYNOS_F_IN_FREQ),
175
176 CLK_PLL("fout_apll", "fin_pll", EXYNOS5422_APLL_BASE),
177 CLK_PLL("fout_cpll", "fin_pll", EXYNOS5422_CPLL_BASE),
178 CLK_PLL("fout_dpll", "fin_pll", EXYNOS5422_DPLL_BASE),
179 CLK_PLL("fout_epll", "fin_pll", EXYNOS5422_EPLL_BASE),
180 CLK_PLL("fout_rpll", "fin_pll", EXYNOS5422_RPLL_BASE),
181 CLK_PLL("fout_ipll", "fin_pll", EXYNOS5422_IPLL_BASE),
182 CLK_PLL("fout_spll", "fin_pll", EXYNOS5422_SPLL_BASE),
183 CLK_PLL("fout_vpll", "fin_pll", EXYNOS5422_VPLL_BASE),
184 CLK_PLL("fout_mpll", "fin_pll", EXYNOS5422_MPLL_BASE),
185 CLK_PLL("fout_bpll", "fin_pll", EXYNOS5422_BPLL_BASE),
186 CLK_PLL("fout_kpll", "fin_pll", EXYNOS5422_KPLL_BASE),
187
188 CLK_MUXA("sclk_cpll", "mout_cpll", EXYNOS5422_SRC_TOP6, __BIT(28),
189 mout_cpll_p),
190 CLK_MUXA("sclk_dpll", "mout_dpll", EXYNOS5422_SRC_TOP6, __BIT(24),
191 mout_dpll_p),
192 CLK_MUXA("sclk_mpll", "mout_mpll", EXYNOS5422_SRC_TOP6, __BIT(0),
193 mout_mpll_p),
194 CLK_MUXA("sclk_spll", "mout_spll", EXYNOS5422_SRC_TOP6, __BIT(8),
195 mout_spll_p),
196 CLK_MUXA("sclk_ipll", "mout_ipll", EXYNOS5422_SRC_TOP6, __BIT(12),
197 mout_ipll_p),
198 CLK_MUXF("sclk_epll", "mout_epll", EXYNOS5422_SRC_TOP6, __BIT(20),
199 CLK_SET_RATE_PARENT, mout_epll_p),
200 CLK_MUXF("sclk_rpll", "mout_rpll", EXYNOS5422_SRC_TOP6, __BIT(16),
201 CLK_SET_RATE_PARENT, mout_rpll_p),
202
203 CLK_MUX("mout_mmc0", EXYNOS5422_SRC_FSYS, __BITS(10,8),
204 mout_group2_p),
205 CLK_MUX("mout_mmc1", EXYNOS5422_SRC_FSYS, __BITS(14,12),
206 mout_group2_p),
207 CLK_MUX("mout_mmc2", EXYNOS5422_SRC_FSYS, __BITS(18,16),
208 mout_group2_p),
209
210 CLK_DIV("dout_mmc0", "mout_mmc0", EXYNOS5422_DIV_FSYS1, __BITS(9,0)),
211 CLK_DIV("dout_mmc1", "mout_mmc1", EXYNOS5422_DIV_FSYS1, __BITS(19,10)),
212 CLK_DIV("dout_mmc2", "mout_mmc2", EXYNOS5422_DIV_FSYS1, __BITS(29,20)),
213
214 CLK_GATE("sclk_mmc0", "dout_mmc0", EXYNOS5422_GATE_TOP_SCLK_FSYS,
215 __BIT(0), CLK_SET_RATE_PARENT),
216 CLK_GATE("sclk_mmc1", "dout_mmc1", EXYNOS5422_GATE_TOP_SCLK_FSYS,
217 __BIT(1), CLK_SET_RATE_PARENT),
218 CLK_GATE("sclk_mmc2", "dout_mmc2", EXYNOS5422_GATE_TOP_SCLK_FSYS,
219 __BIT(2), CLK_SET_RATE_PARENT),
220 };
221
222 static int exynos5422_clock_match(device_t, cfdata_t, void *);
223 static void exynos5422_clock_attach(device_t, device_t, void *);
224
225 struct exynos5422_clock_softc {
226 device_t sc_dev;
227 bus_space_tag_t sc_bst;
228 bus_space_handle_t sc_bsh;
229 };
230
231 static void exynos5422_clock_print_header(void);
232 static void exynos5422_clock_print(struct exynos5422_clock_softc *,
233 struct exynos_clk *);
234
235 CFATTACH_DECL_NEW(exynos5422_clock, sizeof(struct exynos5422_clock_softc),
236 exynos5422_clock_match, exynos5422_clock_attach, NULL, NULL);
237
238 #define CLOCK_READ(sc, reg) \
239 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
240 #define CLOCK_WRITE(sc, reg, val) \
241 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
242
243 static int
244 exynos5422_clock_match(device_t parent, cfdata_t cf, void *aux)
245 {
246 return IS_EXYNOS5422_P();
247 }
248
249 static void
250 exynos5422_clock_attach(device_t parent, device_t self, void *aux)
251 {
252 struct exynos5422_clock_softc * const sc = device_private(self);
253 struct exyo_attach_args * const exyo = aux;
254 const struct exyo_locators *loc = &exyo->exyo_loc;
255
256 sc->sc_dev = self;
257 sc->sc_bst = exyo->exyo_core_bst;
258 bus_space_subregion(exyo->exyo_core_bst, exyo->exyo_core_bsh,
259 loc->loc_offset, loc->loc_size, &sc->sc_bsh);
260
261 aprint_naive("\n");
262 aprint_normal(": Exynos5422 Clock Controller\n");
263
264 clk_backend_register("exynos5422", &exynos5422_clock_funcs, sc);
265
266 exynos5422_clock_print_header();
267 for (u_int n = 0; n < __arraycount(exynos5422_clocks); n++) {
268 exynos5422_clock_print(sc, &exynos5422_clocks[n]);
269 }
270 }
271
272 static struct exynos_clk *
273 exynos5422_clock_find(const char *name)
274 {
275 u_int n;
276
277 for (n = 0; n < __arraycount(exynos5422_clocks); n++) {
278 if (strcmp(exynos5422_clocks[n].base.name, name) == 0) {
279 return &exynos5422_clocks[n];
280 }
281 }
282
283 return NULL;
284 }
285
286 static void
287 exynos5422_clock_print_header(void)
288 {
289 printf(" %-10s %2s %-10s %-5s %10s\n",
290 "clock", "", "parent", "type", "rate");
291 printf(" %-10s %2s %-10s %-5s %10s\n",
292 "=====", "", "======", "====", "====");
293 }
294
295 static void
296 exynos5422_clock_print(struct exynos5422_clock_softc *sc,
297 struct exynos_clk *eclk)
298 {
299 struct exynos_clk *eclk_parent;
300 struct clk *clk_parent;
301 const char *type = "?";
302
303 switch (eclk->type) {
304 case EXYNOS_CLK_FIXED:
305 type = "fixed";
306 break;
307 case EXYNOS_CLK_PLL:
308 type = "pll";
309 break;
310 case EXYNOS_CLK_MUX:
311 type = "mux";
312 break;
313 case EXYNOS_CLK_DIV:
314 type = "div";
315 break;
316 case EXYNOS_CLK_GATE:
317 type = "gate";
318 break;
319 }
320
321 clk_parent = exynos5422_clock_get_parent(sc, &eclk->base);
322 eclk_parent = (struct exynos_clk *)clk_parent;
323
324 printf(" %-10s %2s %-10s %-5s %10d Hz\n",
325 eclk->base.name,
326 eclk_parent ? "<-" : "",
327 eclk_parent ? eclk_parent->base.name : "",
328 type, clk_get_rate(&eclk->base));
329 }
330
331 static u_int
332 exynos5422_clock_get_rate_pll(struct exynos5422_clock_softc *sc,
333 struct exynos_clk *eclk)
334 {
335 struct exynos_pll_clk *epll = &eclk->u.pll;
336 struct exynos_clk *clk_parent;
337
338 KASSERT(eclk->type == EXYNOS_CLK_PLL);
339
340 clk_parent = exynos5422_clock_find(eclk->parent);
341 KASSERT(clk_parent != NULL);
342 const u_int rate_parent = exynos5422_clock_get_rate(sc,
343 &clk_parent->base);
344
345 const uint32_t v = CLOCK_READ(sc, epll->con0_reg);
346
347 return PLL_FREQ(rate_parent, v);
348 }
349
350 static int
351 exynos5422_clock_set_rate_pll(struct exynos5422_clock_softc *sc,
352 struct exynos_clk *eclk, u_int rate)
353 {
354 /* TODO */
355 return EOPNOTSUPP;
356 }
357
358 static int
359 exynos5422_clock_set_parent_mux(struct exynos5422_clock_softc *sc,
360 struct exynos_clk *eclk, struct exynos_clk *eclk_parent)
361 {
362 struct exynos_mux_clk *emux = &eclk->u.mux;
363 const char *pname = eclk_parent->base.name;
364 u_int sel;
365
366 KASSERT(eclk->type == EXYNOS_CLK_MUX);
367
368 for (sel = 0; sel < emux->nparents; sel++) {
369 if (strcmp(pname, emux->parents[sel]) == 0) {
370 break;
371 }
372 }
373 if (sel == emux->nparents) {
374 return EINVAL;
375 }
376
377 uint32_t v = CLOCK_READ(sc, emux->reg);
378 v &= ~emux->bits;
379 v |= __SHIFTIN(sel, emux->bits);
380 CLOCK_WRITE(sc, emux->reg, v);
381
382 return 0;
383 }
384
385 static struct exynos_clk *
386 exynos5422_clock_get_parent_mux(struct exynos5422_clock_softc *sc,
387 struct exynos_clk *eclk)
388 {
389 struct exynos_mux_clk *emux = &eclk->u.mux;
390
391 KASSERT(eclk->type == EXYNOS_CLK_MUX);
392
393 const uint32_t v = CLOCK_READ(sc, emux->reg);
394 const u_int sel = __SHIFTOUT(v, emux->bits);
395
396 KASSERT(sel < emux->nparents);
397
398 return exynos5422_clock_find(emux->parents[sel]);
399 }
400
401 static u_int
402 exynos5422_clock_get_rate_div(struct exynos5422_clock_softc *sc,
403 struct exynos_clk *eclk)
404 {
405 struct exynos_mux_clk *emux = &eclk->u.mux;
406 struct clk *clk_parent;
407
408 KASSERT(eclk->type == EXYNOS_CLK_DIV);
409
410 clk_parent = exynos5422_clock_get_parent(sc, &eclk->base);
411 const u_int parent_rate = exynos5422_clock_get_rate(sc, clk_parent);
412
413 const uint32_t v = CLOCK_READ(sc, emux->reg);
414 const u_int div = __SHIFTOUT(v, emux->bits);
415
416 return parent_rate / (div + 1);
417 }
418
419 static int
420 exynos5422_clock_set_rate_div(struct exynos5422_clock_softc *sc,
421 struct exynos_clk *eclk, u_int rate)
422 {
423 struct exynos_mux_clk *emux = &eclk->u.mux;
424 struct clk *clk_parent;
425 int tmp_div, new_div = -1;
426 u_int tmp_rate;
427
428 KASSERT(eclk->type == EXYNOS_CLK_DIV);
429
430 clk_parent = exynos5422_clock_get_parent(sc, &eclk->base);
431 const u_int parent_rate = exynos5422_clock_get_rate(sc, clk_parent);
432
433 for (tmp_div = 0; tmp_div < popcount32(emux->bits); tmp_div++) {
434 tmp_rate = parent_rate / (tmp_div + 1);
435 if (tmp_rate <= rate) {
436 new_div = tmp_div;
437 break;
438 }
439 }
440 if (new_div == -1)
441 return EINVAL;
442
443 uint32_t v = CLOCK_READ(sc, emux->reg);
444 v &= ~emux->bits;
445 v |= __SHIFTIN(new_div, emux->bits);
446 CLOCK_WRITE(sc, emux->reg, v);
447
448 return 0;
449 }
450
451 static int
452 exynos5422_clock_enable_gate(struct exynos5422_clock_softc *sc,
453 struct exynos_clk *eclk, bool enable)
454 {
455 struct exynos_gate_clk *egate = &eclk->u.gate;
456
457 KASSERT(eclk->type == EXYNOS_CLK_GATE);
458
459 uint32_t v = CLOCK_READ(sc, egate->reg);
460 if (enable) {
461 v |= egate->bits;
462 } else {
463 v &= ~egate->bits;
464 }
465 CLOCK_WRITE(sc, egate->reg, v);
466
467 return 0;
468 }
469
470 /*
471 * clk api
472 */
473
474 static struct clk *
475 exynos5422_clock_get(void *priv, const char *name)
476 {
477 struct exynos_clk *eclk;
478
479 eclk = exynos5422_clock_find(name);
480 if (eclk == NULL)
481 return NULL;
482
483 atomic_inc_uint(&eclk->refcnt);
484
485 return &eclk->base;
486 }
487
488 static void
489 exynos5422_clock_put(void *priv, struct clk *clk)
490 {
491 struct exynos_clk *eclk = (struct exynos_clk *)clk;
492
493 KASSERT(eclk->refcnt > 0);
494
495 atomic_dec_uint(&eclk->refcnt);
496 }
497
498 static u_int
499 exynos5422_clock_get_rate(void *priv, struct clk *clk)
500 {
501 struct exynos_clk *eclk = (struct exynos_clk *)clk;
502 struct clk *clk_parent;
503
504 switch (eclk->type) {
505 case EXYNOS_CLK_FIXED:
506 return eclk->u.fixed.rate;
507 case EXYNOS_CLK_PLL:
508 return exynos5422_clock_get_rate_pll(priv, eclk);
509 case EXYNOS_CLK_MUX:
510 case EXYNOS_CLK_GATE:
511 clk_parent = exynos5422_clock_get_parent(priv, clk);
512 return exynos5422_clock_get_rate(priv, clk_parent);
513 case EXYNOS_CLK_DIV:
514 return exynos5422_clock_get_rate_div(priv, eclk);
515 default:
516 panic("exynos5422: unknown eclk type %d", eclk->type);
517 }
518 }
519
520 static int
521 exynos5422_clock_set_rate(void *priv, struct clk *clk, u_int rate)
522 {
523 struct exynos_clk *eclk = (struct exynos_clk *)clk;
524
525 switch (eclk->type) {
526 case EXYNOS_CLK_FIXED:
527 return EIO;
528 case EXYNOS_CLK_PLL:
529 return exynos5422_clock_set_rate_pll(priv, eclk, rate);
530 case EXYNOS_CLK_MUX:
531 return EIO;
532 case EXYNOS_CLK_DIV:
533 return exynos5422_clock_set_rate_div(priv, eclk, rate);
534 case EXYNOS_CLK_GATE:
535 return EINVAL;
536 default:
537 panic("exynos5422: unknown eclk type %d", eclk->type);
538 }
539 }
540
541 static int
542 exynos5422_clock_enable(void *priv, struct clk *clk)
543 {
544 struct exynos_clk *eclk = (struct exynos_clk *)clk;
545
546 switch (eclk->type) {
547 case EXYNOS_CLK_FIXED:
548 return 0; /* always on */
549 case EXYNOS_CLK_PLL:
550 return 0; /* XXX */
551 case EXYNOS_CLK_MUX:
552 case EXYNOS_CLK_DIV:
553 return 0;
554 case EXYNOS_CLK_GATE:
555 return exynos5422_clock_enable_gate(priv, eclk, true);
556 default:
557 panic("exynos5422: unknown eclk type %d", eclk->type);
558 }
559 }
560
561 static int
562 exynos5422_clock_disable(void *priv, struct clk *clk)
563 {
564 struct exynos_clk *eclk = (struct exynos_clk *)clk;
565
566 switch (eclk->type) {
567 case EXYNOS_CLK_FIXED:
568 return EINVAL; /* always on */
569 case EXYNOS_CLK_PLL:
570 return EINVAL; /* XXX */
571 case EXYNOS_CLK_MUX:
572 case EXYNOS_CLK_DIV:
573 return EINVAL;
574 case EXYNOS_CLK_GATE:
575 return exynos5422_clock_enable_gate(priv, eclk, false);
576 default:
577 panic("exynos5422: unknown eclk type %d", eclk->type);
578 }
579 }
580
581 static int
582 exynos5422_clock_set_parent(void *priv, struct clk *clk, struct clk *clk_parent)
583 {
584 struct exynos_clk *eclk = (struct exynos_clk *)clk;
585 struct exynos_clk *eclk_parent = (struct exynos_clk *)clk_parent;
586
587 switch (eclk->type) {
588 case EXYNOS_CLK_FIXED:
589 case EXYNOS_CLK_PLL:
590 case EXYNOS_CLK_DIV:
591 case EXYNOS_CLK_GATE:
592 return EINVAL;
593 case EXYNOS_CLK_MUX:
594 return exynos5422_clock_set_parent_mux(priv, eclk, eclk_parent);
595 default:
596 panic("exynos5422: unknown eclk type %d", eclk->type);
597 }
598 }
599
600 static struct clk *
601 exynos5422_clock_get_parent(void *priv, struct clk *clk)
602 {
603 struct exynos_clk *eclk = (struct exynos_clk *)clk;
604 struct exynos_clk *eclk_parent = NULL;
605
606 switch (eclk->type) {
607 case EXYNOS_CLK_FIXED:
608 case EXYNOS_CLK_PLL:
609 case EXYNOS_CLK_DIV:
610 case EXYNOS_CLK_GATE:
611 if (eclk->parent != NULL) {
612 eclk_parent = exynos5422_clock_find(eclk->parent);
613 }
614 break;
615 case EXYNOS_CLK_MUX:
616 eclk_parent = exynos5422_clock_get_parent_mux(priv, eclk);
617 break;
618 default:
619 panic("exynos5422: unknown eclk type %d", eclk->type);
620 }
621
622 return &eclk_parent->base;
623 }
624