FILE
clk-cv18xx-ip.c
File preview with syntax highlighting.
linux-6.19.14/drivers/clk/sophgo/clk-cv18xx-ip.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com> 4 */ 5 6#include <linux/clk-provider.h> 7#include <linux/io.h> 8#include <linux/gcd.h> 9#include <linux/spinlock.h> 10 11#include "clk-cv18xx-ip.h" 12 13/* GATE */ 14static inline struct cv1800_clk_gate *hw_to_cv1800_clk_gate(struct clk_hw *hw) 15{ 16 struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); 17 18 return container_of(common, struct cv1800_clk_gate, common); 19} 20 21static int gate_enable(struct clk_hw *hw) 22{ 23 struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw); 24 25 return cv1800_clk_setbit(&gate->common, &gate->gate); 26} 27 28static void gate_disable(struct clk_hw *hw) 29{ 30 struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw); 31 32 cv1800_clk_clearbit(&gate->common, &gate->gate); 33} 34 35static int gate_is_enabled(struct clk_hw *hw) 36{ 37 struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw); 38 39 return cv1800_clk_checkbit(&gate->common, &gate->gate); 40} 41 42static unsigned long gate_recalc_rate(struct clk_hw *hw, 43 unsigned long parent_rate) 44{ 45 return parent_rate; 46} 47 48static int gate_determine_rate(struct clk_hw *hw, 49 struct clk_rate_request *req) 50{ 51 req->rate = req->best_parent_rate; 52 53 return 0; 54} 55 56static int gate_set_rate(struct clk_hw *hw, unsigned long rate, 57 unsigned long parent_rate) 58{ 59 return 0; 60} 61 62const struct clk_ops cv1800_clk_gate_ops = { 63 .disable = gate_disable, 64 .enable = gate_enable, 65 .is_enabled = gate_is_enabled, 66 67 .recalc_rate = gate_recalc_rate, 68 .determine_rate = gate_determine_rate, 69 .set_rate = gate_set_rate, 70}; 71 72/* DIV */ 73#define _DIV_EN_CLK_DIV_FACTOR_FIELD BIT(3) 74 75#define DIV_GET_EN_CLK_DIV_FACTOR(_reg) \ 76 FIELD_GET(_DIV_EN_CLK_DIV_FACTOR_FIELD, _reg) 77 78#define DIV_SET_EN_DIV_FACTOR(_reg) \ 79 _CV1800_SET_FIELD(_reg, 1, _DIV_EN_CLK_DIV_FACTOR_FIELD) 80 81static inline struct cv1800_clk_div *hw_to_cv1800_clk_div(struct clk_hw *hw) 82{ 83 struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); 84 85 return container_of(common, struct cv1800_clk_div, common); 86} 87 88static int div_enable(struct clk_hw *hw) 89{ 90 struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); 91 92 return cv1800_clk_setbit(&div->common, &div->gate); 93} 94 95static void div_disable(struct clk_hw *hw) 96{ 97 struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); 98 99 cv1800_clk_clearbit(&div->common, &div->gate); 100} 101 102static int div_is_enabled(struct clk_hw *hw) 103{ 104 struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); 105 106 return cv1800_clk_checkbit(&div->common, &div->gate); 107} 108 109static int div_helper_set_rate(struct cv1800_clk_common *common, 110 struct cv1800_clk_regfield *div, 111 unsigned long val) 112{ 113 unsigned long flags; 114 u32 reg; 115 116 if (div->width == 0) 117 return 0; 118 119 spin_lock_irqsave(common->lock, flags); 120 121 reg = readl(common->base + div->reg); 122 reg = cv1800_clk_regfield_set(reg, val, div); 123 if (div->initval > 0) 124 reg = DIV_SET_EN_DIV_FACTOR(reg); 125 126 writel(reg, common->base + div->reg); 127 128 spin_unlock_irqrestore(common->lock, flags); 129 130 return 0; 131} 132 133static u32 div_helper_get_clockdiv(struct cv1800_clk_common *common, 134 struct cv1800_clk_regfield *div) 135{ 136 u32 clockdiv = 1; 137 u32 reg; 138 139 if (!div || div->initval < 0 || (div->width == 0 && div->initval <= 0)) 140 return 1; 141 142 if (div->width == 0 && div->initval > 0) 143 return div->initval; 144 145 reg = readl(common->base + div->reg); 146 147 if (div->initval == 0 || DIV_GET_EN_CLK_DIV_FACTOR(reg)) 148 clockdiv = cv1800_clk_regfield_get(reg, div); 149 else if (div->initval > 0) 150 clockdiv = div->initval; 151 152 return clockdiv; 153} 154 155static u32 div_helper_round_rate(struct cv1800_clk_regfield *div, 156 struct clk_hw *hw, struct clk_hw *parent, 157 unsigned long rate, unsigned long *prate) 158{ 159 if (div->width == 0) { 160 if (div->initval <= 0) 161 return DIV_ROUND_UP_ULL(*prate, 1); 162 else 163 return DIV_ROUND_UP_ULL(*prate, div->initval); 164 } 165 166 return divider_round_rate_parent(hw, parent, rate, prate, NULL, 167 div->width, div->flags); 168} 169 170static long div_round_rate(struct clk_hw *parent, unsigned long *parent_rate, 171 unsigned long rate, int id, void *data) 172{ 173 struct cv1800_clk_div *div = data; 174 175 return div_helper_round_rate(&div->div, &div->common.hw, parent, 176 rate, parent_rate); 177} 178 179static bool div_is_better_rate(struct cv1800_clk_common *common, 180 unsigned long target, unsigned long now, 181 unsigned long best) 182{ 183 if (common->features & CLK_DIVIDER_ROUND_CLOSEST) 184 return abs_diff(target, now) < abs_diff(target, best); 185 186 return now <= target && now > best; 187} 188 189static int mux_helper_determine_rate(struct cv1800_clk_common *common, 190 struct clk_rate_request *req, 191 long (*round)(struct clk_hw *, 192 unsigned long *, 193 unsigned long, 194 int, 195 void *), 196 void *data) 197{ 198 unsigned long best_parent_rate = 0, best_rate = 0; 199 struct clk_hw *best_parent, *hw = &common->hw; 200 unsigned int i; 201 202 if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) { 203 unsigned long adj_parent_rate; 204 205 best_parent = clk_hw_get_parent(hw); 206 best_parent_rate = clk_hw_get_rate(best_parent); 207 208 best_rate = round(best_parent, &adj_parent_rate, 209 req->rate, -1, data); 210 211 goto find; 212 } 213 214 for (i = 0; i < clk_hw_get_num_parents(hw); i++) { 215 unsigned long tmp_rate, parent_rate; 216 struct clk_hw *parent; 217 218 parent = clk_hw_get_parent_by_index(hw, i); 219 if (!parent) 220 continue; 221 222 parent_rate = clk_hw_get_rate(parent); 223 224 tmp_rate = round(parent, &parent_rate, req->rate, i, data); 225 226 if (tmp_rate == req->rate) { 227 best_parent = parent; 228 best_parent_rate = parent_rate; 229 best_rate = tmp_rate; 230 goto find; 231 } 232 233 if (div_is_better_rate(common, req->rate, 234 tmp_rate, best_rate)) { 235 best_parent = parent; 236 best_parent_rate = parent_rate; 237 best_rate = tmp_rate; 238 } 239 } 240 241 if (best_rate == 0) 242 return -EINVAL; 243 244find: 245 req->best_parent_hw = best_parent; 246 req->best_parent_rate = best_parent_rate; 247 req->rate = best_rate; 248 return 0; 249} 250 251static int div_determine_rate(struct clk_hw *hw, 252 struct clk_rate_request *req) 253{ 254 struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); 255 256 return mux_helper_determine_rate(&div->common, req, 257 div_round_rate, div); 258} 259 260static unsigned long div_recalc_rate(struct clk_hw *hw, 261 unsigned long parent_rate) 262{ 263 struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); 264 unsigned long val; 265 266 val = div_helper_get_clockdiv(&div->common, &div->div); 267 if (val == 0) 268 return 0; 269 270 return divider_recalc_rate(hw, parent_rate, val, NULL, 271 div->div.flags, div->div.width); 272} 273 274static int div_set_rate(struct clk_hw *hw, unsigned long rate, 275 unsigned long parent_rate) 276{ 277 struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); 278 unsigned long val; 279 280 val = divider_get_val(rate, parent_rate, NULL, 281 div->div.width, div->div.flags); 282 283 return div_helper_set_rate(&div->common, &div->div, val); 284} 285 286const struct clk_ops cv1800_clk_div_ops = { 287 .disable = div_disable, 288 .enable = div_enable, 289 .is_enabled = div_is_enabled, 290 291 .determine_rate = div_determine_rate, 292 .recalc_rate = div_recalc_rate, 293 .set_rate = div_set_rate, 294}; 295 296static inline struct cv1800_clk_bypass_div * 297hw_to_cv1800_clk_bypass_div(struct clk_hw *hw) 298{ 299 struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); 300 301 return container_of(div, struct cv1800_clk_bypass_div, div); 302} 303 304static long bypass_div_round_rate(struct clk_hw *parent, 305 unsigned long *parent_rate, 306 unsigned long rate, int id, void *data) 307{ 308 struct cv1800_clk_bypass_div *div = data; 309 310 if (id == -1) { 311 if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) 312 return *parent_rate; 313 else 314 return div_round_rate(parent, parent_rate, rate, 315 -1, &div->div); 316 } 317 318 if (id == 0) 319 return *parent_rate; 320 321 return div_round_rate(parent, parent_rate, rate, id - 1, &div->div); 322} 323 324static int bypass_div_determine_rate(struct clk_hw *hw, 325 struct clk_rate_request *req) 326{ 327 struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); 328 329 return mux_helper_determine_rate(&div->div.common, req, 330 bypass_div_round_rate, div); 331} 332 333static unsigned long bypass_div_recalc_rate(struct clk_hw *hw, 334 unsigned long parent_rate) 335{ 336 struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); 337 338 if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) 339 return parent_rate; 340 341 return div_recalc_rate(hw, parent_rate); 342} 343 344static int bypass_div_set_rate(struct clk_hw *hw, unsigned long rate, 345 unsigned long parent_rate) 346{ 347 struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); 348 349 if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) 350 return 0; 351 352 return div_set_rate(hw, rate, parent_rate); 353} 354 355static u8 bypass_div_get_parent(struct clk_hw *hw) 356{ 357 struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); 358 359 if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) 360 return 0; 361 362 return 1; 363} 364 365static int bypass_div_set_parent(struct clk_hw *hw, u8 index) 366{ 367 struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); 368 369 if (index) 370 return cv1800_clk_clearbit(&div->div.common, &div->bypass); 371 372 return cv1800_clk_setbit(&div->div.common, &div->bypass); 373} 374 375const struct clk_ops cv1800_clk_bypass_div_ops = { 376 .disable = div_disable, 377 .enable = div_enable, 378 .is_enabled = div_is_enabled, 379 380 .determine_rate = bypass_div_determine_rate, 381 .recalc_rate = bypass_div_recalc_rate, 382 .set_rate = bypass_div_set_rate, 383 384 .set_parent = bypass_div_set_parent, 385 .get_parent = bypass_div_get_parent, 386}; 387 388/* MUX */ 389static inline struct cv1800_clk_mux *hw_to_cv1800_clk_mux(struct clk_hw *hw) 390{ 391 struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); 392 393 return container_of(common, struct cv1800_clk_mux, common); 394} 395 396static int mux_enable(struct clk_hw *hw) 397{ 398 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 399 400 return cv1800_clk_setbit(&mux->common, &mux->gate); 401} 402 403static void mux_disable(struct clk_hw *hw) 404{ 405 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 406 407 cv1800_clk_clearbit(&mux->common, &mux->gate); 408} 409 410static int mux_is_enabled(struct clk_hw *hw) 411{ 412 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 413 414 return cv1800_clk_checkbit(&mux->common, &mux->gate); 415} 416 417static long mux_round_rate(struct clk_hw *parent, unsigned long *parent_rate, 418 unsigned long rate, int id, void *data) 419{ 420 struct cv1800_clk_mux *mux = data; 421 422 return div_helper_round_rate(&mux->div, &mux->common.hw, parent, 423 rate, parent_rate); 424} 425 426static int mux_determine_rate(struct clk_hw *hw, 427 struct clk_rate_request *req) 428{ 429 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 430 431 return mux_helper_determine_rate(&mux->common, req, 432 mux_round_rate, mux); 433} 434 435static unsigned long mux_recalc_rate(struct clk_hw *hw, 436 unsigned long parent_rate) 437{ 438 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 439 unsigned long val; 440 441 val = div_helper_get_clockdiv(&mux->common, &mux->div); 442 if (val == 0) 443 return 0; 444 445 return divider_recalc_rate(hw, parent_rate, val, NULL, 446 mux->div.flags, mux->div.width); 447} 448 449static int mux_set_rate(struct clk_hw *hw, unsigned long rate, 450 unsigned long parent_rate) 451{ 452 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 453 unsigned long val; 454 455 val = divider_get_val(rate, parent_rate, NULL, 456 mux->div.width, mux->div.flags); 457 458 return div_helper_set_rate(&mux->common, &mux->div, val); 459} 460 461static u8 mux_get_parent(struct clk_hw *hw) 462{ 463 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 464 u32 reg = readl(mux->common.base + mux->mux.reg); 465 466 return cv1800_clk_regfield_get(reg, &mux->mux); 467} 468 469static int _mux_set_parent(struct cv1800_clk_mux *mux, u8 index) 470{ 471 u32 reg; 472 473 reg = readl(mux->common.base + mux->mux.reg); 474 reg = cv1800_clk_regfield_set(reg, index, &mux->mux); 475 writel(reg, mux->common.base + mux->mux.reg); 476 477 return 0; 478} 479 480static int mux_set_parent(struct clk_hw *hw, u8 index) 481{ 482 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 483 unsigned long flags; 484 485 spin_lock_irqsave(mux->common.lock, flags); 486 487 _mux_set_parent(mux, index); 488 489 spin_unlock_irqrestore(mux->common.lock, flags); 490 491 return 0; 492} 493 494const struct clk_ops cv1800_clk_mux_ops = { 495 .disable = mux_disable, 496 .enable = mux_enable, 497 .is_enabled = mux_is_enabled, 498 499 .determine_rate = mux_determine_rate, 500 .recalc_rate = mux_recalc_rate, 501 .set_rate = mux_set_rate, 502 503 .set_parent = mux_set_parent, 504 .get_parent = mux_get_parent, 505}; 506 507static inline struct cv1800_clk_bypass_mux * 508hw_to_cv1800_clk_bypass_mux(struct clk_hw *hw) 509{ 510 struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); 511 512 return container_of(mux, struct cv1800_clk_bypass_mux, mux); 513} 514 515static long bypass_mux_round_rate(struct clk_hw *parent, 516 unsigned long *parent_rate, 517 unsigned long rate, int id, void *data) 518{ 519 struct cv1800_clk_bypass_mux *mux = data; 520 521 if (id == -1) { 522 if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) 523 return *parent_rate; 524 else 525 return mux_round_rate(parent, parent_rate, rate, 526 -1, &mux->mux); 527 } 528 529 if (id == 0) 530 return *parent_rate; 531 532 return mux_round_rate(parent, parent_rate, rate, id - 1, &mux->mux); 533} 534 535static int bypass_mux_determine_rate(struct clk_hw *hw, 536 struct clk_rate_request *req) 537{ 538 struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); 539 540 return mux_helper_determine_rate(&mux->mux.common, req, 541 bypass_mux_round_rate, mux); 542} 543 544static unsigned long bypass_mux_recalc_rate(struct clk_hw *hw, 545 unsigned long parent_rate) 546{ 547 struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); 548 549 if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) 550 return parent_rate; 551 552 return mux_recalc_rate(hw, parent_rate); 553} 554 555static int bypass_mux_set_rate(struct clk_hw *hw, unsigned long rate, 556 unsigned long parent_rate) 557{ 558 struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); 559 560 if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) 561 return 0; 562 563 return mux_set_rate(hw, rate, parent_rate); 564} 565 566static u8 bypass_mux_get_parent(struct clk_hw *hw) 567{ 568 struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); 569 570 if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) 571 return 0; 572 573 return mux_get_parent(hw) + 1; 574} 575 576static int bypass_mux_set_parent(struct clk_hw *hw, u8 index) 577{ 578 struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); 579 580 if (index == 0) 581 return cv1800_clk_setbit(&mux->mux.common, &mux->bypass); 582 583 return cv1800_clk_clearbit(&mux->mux.common, &mux->bypass); 584} 585 586const struct clk_ops cv1800_clk_bypass_mux_ops = { 587 .disable = mux_disable, 588 .enable = mux_enable, 589 .is_enabled = mux_is_enabled, 590 591 .determine_rate = bypass_mux_determine_rate, 592 .recalc_rate = bypass_mux_recalc_rate, 593 .set_rate = bypass_mux_set_rate, 594 595 .set_parent = bypass_mux_set_parent, 596 .get_parent = bypass_mux_get_parent, 597}; 598 599/* MMUX */ 600static inline struct cv1800_clk_mmux *hw_to_cv1800_clk_mmux(struct clk_hw *hw) 601{ 602 struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); 603 604 return container_of(common, struct cv1800_clk_mmux, common); 605} 606 607static u8 mmux_get_parent_id(struct cv1800_clk_mmux *mmux) 608{ 609 struct clk_hw *hw = &mmux->common.hw; 610 struct clk_hw *parent = clk_hw_get_parent(hw); 611 unsigned int i; 612 613 for (i = 0; i < clk_hw_get_num_parents(hw); i++) { 614 if (parent == clk_hw_get_parent_by_index(hw, i)) 615 return i; 616 } 617 618 BUG(); 619} 620 621static int mmux_enable(struct clk_hw *hw) 622{ 623 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 624 625 return cv1800_clk_setbit(&mmux->common, &mmux->gate); 626} 627 628static void mmux_disable(struct clk_hw *hw) 629{ 630 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 631 632 cv1800_clk_clearbit(&mmux->common, &mmux->gate); 633} 634 635static int mmux_is_enabled(struct clk_hw *hw) 636{ 637 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 638 639 return cv1800_clk_checkbit(&mmux->common, &mmux->gate); 640} 641 642static long mmux_round_rate(struct clk_hw *parent, unsigned long *parent_rate, 643 unsigned long rate, int id, void *data) 644{ 645 struct cv1800_clk_mmux *mmux = data; 646 s8 div_id; 647 648 if (id == -1) { 649 if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) 650 return *parent_rate; 651 652 id = mmux_get_parent_id(mmux); 653 } 654 655 div_id = mmux->parent2sel[id]; 656 657 if (div_id < 0) 658 return *parent_rate; 659 660 return div_helper_round_rate(&mmux->div[div_id], 661 &mmux->common.hw, parent, 662 rate, parent_rate); 663} 664 665static int mmux_determine_rate(struct clk_hw *hw, 666 struct clk_rate_request *req) 667{ 668 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 669 670 return mux_helper_determine_rate(&mmux->common, req, 671 mmux_round_rate, mmux); 672} 673 674static unsigned long mmux_recalc_rate(struct clk_hw *hw, 675 unsigned long parent_rate) 676{ 677 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 678 unsigned long val; 679 struct cv1800_clk_regfield *div; 680 681 if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) 682 return parent_rate; 683 684 if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel)) 685 div = &mmux->div[0]; 686 else 687 div = &mmux->div[1]; 688 689 val = div_helper_get_clockdiv(&mmux->common, div); 690 if (val == 0) 691 return 0; 692 693 return divider_recalc_rate(hw, parent_rate, val, NULL, 694 div->flags, div->width); 695} 696 697static int mmux_set_rate(struct clk_hw *hw, unsigned long rate, 698 unsigned long parent_rate) 699{ 700 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 701 struct cv1800_clk_regfield *div; 702 unsigned long val; 703 704 if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) 705 return parent_rate; 706 707 if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel)) 708 div = &mmux->div[0]; 709 else 710 div = &mmux->div[1]; 711 712 val = divider_get_val(rate, parent_rate, NULL, 713 div->width, div->flags); 714 715 return div_helper_set_rate(&mmux->common, div, val); 716} 717 718static u8 mmux_get_parent(struct clk_hw *hw) 719{ 720 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 721 struct cv1800_clk_regfield *mux; 722 u32 reg; 723 s8 clk_sel; 724 725 if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) 726 return 0; 727 728 if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel)) 729 clk_sel = 0; 730 else 731 clk_sel = 1; 732 mux = &mmux->mux[clk_sel]; 733 734 reg = readl(mmux->common.base + mux->reg); 735 736 return mmux->sel2parent[clk_sel][cv1800_clk_regfield_get(reg, mux)]; 737} 738 739static int mmux_set_parent(struct clk_hw *hw, u8 index) 740{ 741 struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); 742 struct cv1800_clk_regfield *mux; 743 unsigned long flags; 744 u32 reg; 745 s8 clk_sel = mmux->parent2sel[index]; 746 747 if (index == 0 || clk_sel == -1) { 748 cv1800_clk_setbit(&mmux->common, &mmux->bypass); 749 goto release; 750 } 751 752 cv1800_clk_clearbit(&mmux->common, &mmux->bypass); 753 754 if (clk_sel) 755 cv1800_clk_clearbit(&mmux->common, &mmux->clk_sel); 756 else 757 cv1800_clk_setbit(&mmux->common, &mmux->clk_sel); 758 759 spin_lock_irqsave(mmux->common.lock, flags); 760 761 mux = &mmux->mux[clk_sel]; 762 reg = readl(mmux->common.base + mux->reg); 763 reg = cv1800_clk_regfield_set(reg, index, mux); 764 765 writel(reg, mmux->common.base + mux->reg); 766 767 spin_unlock_irqrestore(mmux->common.lock, flags); 768 769release: 770 return 0; 771} 772 773const struct clk_ops cv1800_clk_mmux_ops = { 774 .disable = mmux_disable, 775 .enable = mmux_enable, 776 .is_enabled = mmux_is_enabled, 777 778 .determine_rate = mmux_determine_rate, 779 .recalc_rate = mmux_recalc_rate, 780 .set_rate = mmux_set_rate, 781 782 .set_parent = mmux_set_parent, 783 .get_parent = mmux_get_parent, 784}; 785 786/* AUDIO CLK */ 787static inline struct cv1800_clk_audio * 788hw_to_cv1800_clk_audio(struct clk_hw *hw) 789{ 790 struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); 791 792 return container_of(common, struct cv1800_clk_audio, common); 793} 794 795static int aclk_enable(struct clk_hw *hw) 796{ 797 struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); 798 799 cv1800_clk_setbit(&aclk->common, &aclk->src_en); 800 return cv1800_clk_setbit(&aclk->common, &aclk->output_en); 801} 802 803static void aclk_disable(struct clk_hw *hw) 804{ 805 struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); 806 807 cv1800_clk_clearbit(&aclk->common, &aclk->output_en); 808 cv1800_clk_clearbit(&aclk->common, &aclk->src_en); 809} 810 811static int aclk_is_enabled(struct clk_hw *hw) 812{ 813 struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); 814 815 return cv1800_clk_checkbit(&aclk->common, &aclk->output_en); 816} 817 818static int aclk_determine_rate(struct clk_hw *hw, 819 struct clk_rate_request *req) 820{ 821 struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); 822 823 req->rate = aclk->target_rate; 824 825 return 0; 826} 827 828static unsigned long aclk_recalc_rate(struct clk_hw *hw, 829 unsigned long parent_rate) 830{ 831 struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); 832 u64 rate = parent_rate; 833 u64 factor = 2; 834 u32 regval; 835 836 if (!cv1800_clk_checkbit(&aclk->common, &aclk->div_en)) 837 return 0; 838 839 regval = readl(aclk->common.base + aclk->m.reg); 840 factor *= cv1800_clk_regfield_get(regval, &aclk->m); 841 842 regval = readl(aclk->common.base + aclk->n.reg); 843 rate *= cv1800_clk_regfield_get(regval, &aclk->n); 844 845 return DIV64_U64_ROUND_UP(rate, factor); 846} 847 848static void aclk_determine_mn(unsigned long parent_rate, unsigned long rate, 849 u32 *m, u32 *n) 850{ 851 u32 tm = parent_rate / 2; 852 u32 tn = rate; 853 u32 tcommon = gcd(tm, tn); 854 *m = tm / tcommon; 855 *n = tn / tcommon; 856} 857 858static int aclk_set_rate(struct clk_hw *hw, unsigned long rate, 859 unsigned long parent_rate) 860{ 861 struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); 862 unsigned long flags; 863 u32 m, n; 864 865 aclk_determine_mn(parent_rate, rate, 866 &m, &n); 867 868 spin_lock_irqsave(aclk->common.lock, flags); 869 870 writel(m, aclk->common.base + aclk->m.reg); 871 writel(n, aclk->common.base + aclk->n.reg); 872 873 cv1800_clk_setbit(&aclk->common, &aclk->div_en); 874 cv1800_clk_setbit(&aclk->common, &aclk->div_up); 875 876 spin_unlock_irqrestore(aclk->common.lock, flags); 877 878 return 0; 879} 880 881const struct clk_ops cv1800_clk_audio_ops = { 882 .disable = aclk_disable, 883 .enable = aclk_enable, 884 .is_enabled = aclk_is_enabled, 885 886 .determine_rate = aclk_determine_rate, 887 .recalc_rate = aclk_recalc_rate, 888 .set_rate = aclk_set_rate, 889};
~/
Read-only file preview.