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