Home | History | Annotate | Line # | Download | only in samsung
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