Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");