1 /* $NetBSD: jh71x0_clkc.c,v 1.4 2024/09/18 08:31:50 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.4 2024/09/18 08:31:50 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