^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0 OR MIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2018 BayLibre, SAS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Jerome Brunet <jbrunet@baylibre.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Sample clock generator divider:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This HW divider gates with value 0 but is otherwise a zero based divider:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * val >= 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * divider = val + 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * The duty cycle may also be set for the LR clock variant. The duty cycle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * ratio is:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * hi = [0 - val]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * duty_cycle = (1 + hi) / (1 + val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "clk-regmap.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "sclk-div.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static inline struct meson_sclk_div_data *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) meson_sclk_div_data(struct clk_regmap *clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return (struct meson_sclk_div_data *)clk->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static int sclk_div_maxval(struct meson_sclk_div_data *sclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return (1 << sclk->div.width) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int sclk_div_maxdiv(struct meson_sclk_div_data *sclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return sclk_div_maxval(sclk) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static int sclk_div_getdiv(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned long prate, int maxdiv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return clamp(div, 2, maxdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static int sclk_div_bestdiv(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned long *prate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct meson_sclk_div_data *sclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct clk_hw *parent = clk_hw_get_parent(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int bestdiv = 0, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) unsigned long maxdiv, now, parent_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned long best = 0, best_parent = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (!rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) rate = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) maxdiv = sclk_div_maxdiv(sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return sclk_div_getdiv(hw, rate, *prate, maxdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * The maximum divider we can use without overflowing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * unsigned long in rate * i below
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) maxdiv = min(ULONG_MAX / rate, maxdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) for (i = 2; i <= maxdiv; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * It's the most ideal case if the requested rate can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * divided from parent clock without needing to change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * parent rate, so return the divider immediately.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (rate * i == *prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) parent_now = clk_hw_round_rate(parent, rate * i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) now = DIV_ROUND_UP_ULL((u64)parent_now, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (abs(rate - now) < abs(rate - best)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) bestdiv = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) best = now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) best_parent = parent_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (!bestdiv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) bestdiv = sclk_div_maxdiv(sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) *prate = best_parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return bestdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static long sclk_div_round_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unsigned long *prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) div = sclk_div_bestdiv(hw, rate, prate, sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return DIV_ROUND_UP_ULL((u64)*prate, div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static void sclk_apply_ratio(struct clk_regmap *clk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct meson_sclk_div_data *sclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned int hi = DIV_ROUND_CLOSEST(sclk->cached_div *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) sclk->cached_duty.num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) sclk->cached_duty.den);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (hi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) hi -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) meson_parm_write(clk->map, &sclk->hi, hi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static int sclk_div_set_duty_cycle(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct clk_duty *duty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (MESON_PARM_APPLICABLE(&sclk->hi)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) memcpy(&sclk->cached_duty, duty, sizeof(*duty));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) sclk_apply_ratio(clk, sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int sclk_div_get_duty_cycle(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct clk_duty *duty)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int hi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (!MESON_PARM_APPLICABLE(&sclk->hi)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) duty->num = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) duty->den = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) hi = meson_parm_read(clk->map, &sclk->hi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) duty->num = hi + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) duty->den = sclk->cached_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static void sclk_apply_divider(struct clk_regmap *clk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct meson_sclk_div_data *sclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (MESON_PARM_APPLICABLE(&sclk->hi))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) sclk_apply_ratio(clk, sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) meson_parm_write(clk->map, &sclk->div, sclk->cached_div - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static int sclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) unsigned long prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) unsigned long maxdiv = sclk_div_maxdiv(sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) sclk->cached_div = sclk_div_getdiv(hw, rate, prate, maxdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (clk_hw_is_enabled(hw))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) sclk_apply_divider(clk, sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static unsigned long sclk_div_recalc_rate(struct clk_hw *hw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) unsigned long prate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return DIV_ROUND_UP_ULL((u64)prate, sclk->cached_div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int sclk_div_enable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) sclk_apply_divider(clk, sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static void sclk_div_disable(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) meson_parm_write(clk->map, &sclk->div, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int sclk_div_is_enabled(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (meson_parm_read(clk->map, &sclk->div))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static int sclk_div_init(struct clk_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct clk_regmap *clk = to_clk_regmap(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) struct meson_sclk_div_data *sclk = meson_sclk_div_data(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) val = meson_parm_read(clk->map, &sclk->div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* if the divider is initially disabled, assume max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (!val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) sclk->cached_div = sclk_div_maxdiv(sclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) sclk->cached_div = val + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) sclk_div_get_duty_cycle(hw, &sclk->cached_duty);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) const struct clk_ops meson_sclk_div_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .recalc_rate = sclk_div_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .round_rate = sclk_div_round_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .set_rate = sclk_div_set_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .enable = sclk_div_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .disable = sclk_div_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .is_enabled = sclk_div_is_enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) .get_duty_cycle = sclk_div_get_duty_cycle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .set_duty_cycle = sclk_div_set_duty_cycle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .init = sclk_div_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) MODULE_DESCRIPTION("Amlogic Sample divider driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) MODULE_LICENSE("GPL v2");