Message ID | 20180317100952.28538-9-manivannan.sadhasivam@linaro.org |
---|---|
State | Accepted |
Commit | 4bb78fc9744a7597b8f847ca7343add5a31fa1b3 |
Headers | show |
Series | None | expand |
Hi Manivannan, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on v4.16-rc4] [cannot apply to next-20180316] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Manivannan-Sadhasivam/Add-clock-driver-for-Actions-S900-SoC/20180319-015124 config: sh-allmodconfig (attached as .config) compiler: sh4-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=sh All warnings (new ones prefixed by >>): In file included from ./arch/sh/include/generated/asm/div64.h:1:0, from include/linux/kernel.h:173, from include/asm-generic/bug.h:18, from arch/sh/include/asm/bug.h:112, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk/actions/owl-factor.c:11: drivers/clk/actions/owl-factor.c: In function 'owl_factor_helper_recalc_rate': include/asm-generic/div64.h:222:28: warning: comparison of distinct pointer types lacks a cast (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ ^ >> drivers/clk/actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from include/linux/init.h:5:0, from include/linux/io.h:22, from include/linux/clk-provider.h:14, from drivers/clk/actions/owl-factor.c:11: include/asm-generic/div64.h:235:25: warning: right shift count >= width of type [-Wshift-count-overflow] } else if (likely(((n) >> 32) == 0)) { \ ^ include/linux/compiler.h:76:40: note: in definition of macro 'likely' # define likely(x) __builtin_expect(!!(x), 1) ^ >> drivers/clk/actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from ./arch/sh/include/generated/asm/div64.h:1:0, from include/linux/kernel.h:173, from include/asm-generic/bug.h:18, from arch/sh/include/asm/bug.h:112, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk/actions/owl-factor.c:11: include/asm-generic/div64.h:239:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types] __rem = __div64_32(&(n), __base); \ ^ >> drivers/clk/actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ include/asm-generic/div64.h:213:17: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'long unsigned int *' extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); ^~~~~~~~~~ cc1: some warnings being treated as errors vim +/do_div +170 drivers/clk/actions/owl-factor.c 10 > 11 #include <linux/clk-provider.h> 12 #include <linux/regmap.h> 13 #include <linux/slab.h> 14 15 #include "owl-factor.h" 16 17 static unsigned int _get_table_maxval(const struct clk_factor_table *table) 18 { 19 unsigned int maxval = 0; 20 const struct clk_factor_table *clkt; 21 22 for (clkt = table; clkt->div; clkt++) 23 if (clkt->val > maxval) 24 maxval = clkt->val; 25 return maxval; 26 } 27 28 static int _get_table_div_mul(const struct clk_factor_table *table, 29 unsigned int val, unsigned int *mul, unsigned int *div) 30 { 31 const struct clk_factor_table *clkt; 32 33 for (clkt = table; clkt->div; clkt++) { 34 if (clkt->val == val) { 35 *mul = clkt->mul; 36 *div = clkt->div; 37 return 1; 38 } 39 } 40 41 return 0; 42 } 43 44 static unsigned int _get_table_val(const struct clk_factor_table *table, 45 unsigned long rate, unsigned long parent_rate) 46 { 47 const struct clk_factor_table *clkt; 48 int val = -1; 49 u64 calc_rate; 50 51 for (clkt = table; clkt->div; clkt++) { 52 calc_rate = parent_rate * clkt->mul; 53 do_div(calc_rate, clkt->div); 54 55 if ((unsigned long)calc_rate <= rate) { 56 val = clkt->val; 57 break; 58 } 59 } 60 61 if (val == -1) 62 val = _get_table_maxval(table); 63 64 return val; 65 } 66 67 static int clk_val_best(struct clk_hw *hw, unsigned long rate, 68 unsigned long *best_parent_rate) 69 { 70 struct owl_factor *factor = hw_to_owl_factor(hw); 71 struct owl_factor_hw *factor_hw = &factor->factor_hw; 72 const struct clk_factor_table *clkt = factor_hw->table; 73 unsigned long parent_rate, try_parent_rate, best = 0, cur_rate; 74 unsigned long parent_rate_saved = *best_parent_rate; 75 int bestval = 0; 76 77 if (!rate) 78 rate = 1; 79 80 if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { 81 parent_rate = *best_parent_rate; 82 bestval = _get_table_val(clkt, rate, parent_rate); 83 return bestval; 84 } 85 86 for (clkt = factor_hw->table; clkt->div; clkt++) { 87 try_parent_rate = rate * clkt->div / clkt->mul; 88 89 if (try_parent_rate == parent_rate_saved) { 90 pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n", 91 __func__, clkt->val, clkt->mul, clkt->div, 92 try_parent_rate); 93 /* 94 * It's the most ideal case if the requested rate can be 95 * divided from parent clock without any need to change 96 * parent rate, so return the divider immediately. 97 */ 98 *best_parent_rate = parent_rate_saved; 99 return clkt->val; 100 } 101 102 parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 103 try_parent_rate); 104 cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul; 105 if (cur_rate <= rate && cur_rate > best) { 106 bestval = clkt->val; 107 best = cur_rate; 108 *best_parent_rate = parent_rate; 109 } 110 } 111 112 if (!bestval) { 113 bestval = _get_table_maxval(clkt); 114 *best_parent_rate = clk_hw_round_rate( 115 clk_hw_get_parent(hw), 1); 116 } 117 118 return bestval; 119 } 120 121 long owl_factor_helper_round_rate(struct owl_clk_common *common, 122 const struct owl_factor_hw *factor_hw, 123 unsigned long rate, 124 unsigned long *parent_rate) 125 { 126 const struct clk_factor_table *clkt = factor_hw->table; 127 unsigned int val, mul = 0, div = 1; 128 129 val = clk_val_best(&common->hw, rate, parent_rate); 130 _get_table_div_mul(clkt, val, &mul, &div); 131 132 return *parent_rate * mul / div; 133 } 134 135 static long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate, 136 unsigned long *parent_rate) 137 { 138 struct owl_factor *factor = hw_to_owl_factor(hw); 139 struct owl_factor_hw *factor_hw = &factor->factor_hw; 140 141 return owl_factor_helper_round_rate(&factor->common, factor_hw, 142 rate, parent_rate); 143 } 144 145 unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common, 146 const struct owl_factor_hw *factor_hw, 147 unsigned long parent_rate) 148 { 149 const struct clk_factor_table *clkt = factor_hw->table; 150 unsigned long rate; 151 u32 reg, val, mul, div; 152 153 div = 0; 154 mul = 0; 155 156 regmap_read(common->regmap, factor_hw->reg, ®); 157 158 val = reg >> factor_hw->shift; 159 val &= div_mask(factor_hw); 160 161 _get_table_div_mul(clkt, val, &mul, &div); 162 if (!div) { 163 WARN(!(factor_hw->fct_flags & CLK_DIVIDER_ALLOW_ZERO), 164 "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", 165 __clk_get_name(common->hw.clk)); 166 return parent_rate; 167 } 168 169 rate = parent_rate * mul; > 170 do_div(rate, div); 171 172 return rate; 173 } 174 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Quoting Manivannan Sadhasivam (2018-03-17 03:09:48) > Add support for Actions Semi factor clock together with > helper functions to be used in composite clock. > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> Adddress kbuild robot comments and I'll apply. -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoting Manivannan Sadhasivam (2018-03-17 03:09:48) > + > +static int clk_val_best(struct clk_hw *hw, unsigned long rate, > + unsigned long *best_parent_rate) > +{ [...] > + } > + > + parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), > + try_parent_rate); > + cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul; > + if (cur_rate <= rate && cur_rate > best) { > + bestval = clkt->val; > + best = cur_rate; > + *best_parent_rate = parent_rate; > + } > + } > + > + if (!bestval) { > + bestval = _get_table_maxval(clkt); > + *best_parent_rate = clk_hw_round_rate( > + clk_hw_get_parent(hw), 1); > + } > + > + return bestval; Also, if this is largely copy/paste from the factor clk code then perhaps those functions can be exported to here and reused instead of copy/paste. > +} -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Manivannan, Thank you for the patch! Yet something to improve: [auto build test ERROR on v4.16-rc4] [cannot apply to next-20180319] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Manivannan-Sadhasivam/Add-clock-driver-for-Actions-S900-SoC/20180319-015124 config: arm-allmodconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=arm All errors (new ones prefixed by >>): In file included from arch/arm/include/asm/div64.h:127:0, from include/linux/kernel.h:173, from include/asm-generic/bug.h:18, from arch/arm/include/asm/bug.h:60, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk/actions/owl-factor.c:11: drivers/clk/actions/owl-factor.c: In function 'owl_factor_helper_recalc_rate': include/asm-generic/div64.h:222:28: warning: comparison of distinct pointer types lacks a cast (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ ^ drivers/clk/actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from include/linux/init.h:5:0, from include/linux/io.h:22, from include/linux/clk-provider.h:14, from drivers/clk/actions/owl-factor.c:11: include/asm-generic/div64.h:235:25: warning: right shift count >= width of type [-Wshift-count-overflow] } else if (likely(((n) >> 32) == 0)) { \ ^ include/linux/compiler.h:76:40: note: in definition of macro 'likely' # define likely(x) __builtin_expect(!!(x), 1) ^ drivers/clk/actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from arch/arm/include/asm/div64.h:127:0, from include/linux/kernel.h:173, from include/asm-generic/bug.h:18, from arch/arm/include/asm/bug.h:60, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk/actions/owl-factor.c:11: >> include/asm-generic/div64.h:239:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types] __rem = __div64_32(&(n), __base); \ ^ drivers/clk/actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from include/linux/kernel.h:173:0, from include/asm-generic/bug.h:18, from arch/arm/include/asm/bug.h:60, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk/actions/owl-factor.c:11: arch/arm/include/asm/div64.h:33:24: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'long unsigned int *' static inline uint32_t __div64_32(uint64_t *n, uint32_t base) ^~~~~~~~~~ cc1: some warnings being treated as errors -- In file included from arch/arm/include/asm/div64.h:127:0, from include/linux/kernel.h:173, from include/asm-generic/bug.h:18, from arch/arm/include/asm/bug.h:60, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk//actions/owl-factor.c:11: drivers/clk//actions/owl-factor.c: In function 'owl_factor_helper_recalc_rate': include/asm-generic/div64.h:222:28: warning: comparison of distinct pointer types lacks a cast (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ ^ drivers/clk//actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from include/linux/init.h:5:0, from include/linux/io.h:22, from include/linux/clk-provider.h:14, from drivers/clk//actions/owl-factor.c:11: include/asm-generic/div64.h:235:25: warning: right shift count >= width of type [-Wshift-count-overflow] } else if (likely(((n) >> 32) == 0)) { \ ^ include/linux/compiler.h:76:40: note: in definition of macro 'likely' # define likely(x) __builtin_expect(!!(x), 1) ^ drivers/clk//actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from arch/arm/include/asm/div64.h:127:0, from include/linux/kernel.h:173, from include/asm-generic/bug.h:18, from arch/arm/include/asm/bug.h:60, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk//actions/owl-factor.c:11: >> include/asm-generic/div64.h:239:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types] __rem = __div64_32(&(n), __base); \ ^ drivers/clk//actions/owl-factor.c:170:2: note: in expansion of macro 'do_div' do_div(rate, div); ^~~~~~ In file included from include/linux/kernel.h:173:0, from include/asm-generic/bug.h:18, from arch/arm/include/asm/bug.h:60, from include/linux/bug.h:5, from include/linux/io.h:23, from include/linux/clk-provider.h:14, from drivers/clk//actions/owl-factor.c:11: arch/arm/include/asm/div64.h:33:24: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'long unsigned int *' static inline uint32_t __div64_32(uint64_t *n, uint32_t base) ^~~~~~~~~~ cc1: some warnings being treated as errors vim +/__div64_32 +239 include/asm-generic/div64.h ^1da177e Linus Torvalds 2005-04-16 215 ^1da177e Linus Torvalds 2005-04-16 216 /* The unnecessary pointer compare is there ^1da177e Linus Torvalds 2005-04-16 217 * to check for type safety (n must be 64bit) ^1da177e Linus Torvalds 2005-04-16 218 */ ^1da177e Linus Torvalds 2005-04-16 219 # define do_div(n,base) ({ \ ^1da177e Linus Torvalds 2005-04-16 220 uint32_t __base = (base); \ ^1da177e Linus Torvalds 2005-04-16 221 uint32_t __rem; \ ^1da177e Linus Torvalds 2005-04-16 222 (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ 911918aa Nicolas Pitre 2015-11-02 223 if (__builtin_constant_p(__base) && \ 911918aa Nicolas Pitre 2015-11-02 224 is_power_of_2(__base)) { \ 911918aa Nicolas Pitre 2015-11-02 225 __rem = (n) & (__base - 1); \ 911918aa Nicolas Pitre 2015-11-02 226 (n) >>= ilog2(__base); \ 461a5e51 Nicolas Pitre 2015-10-30 227 } else if (__div64_const32_is_OK && \ 461a5e51 Nicolas Pitre 2015-10-30 228 __builtin_constant_p(__base) && \ 461a5e51 Nicolas Pitre 2015-10-30 229 __base != 0) { \ 461a5e51 Nicolas Pitre 2015-10-30 230 uint32_t __res_lo, __n_lo = (n); \ 461a5e51 Nicolas Pitre 2015-10-30 231 (n) = __div64_const32(n, __base); \ 461a5e51 Nicolas Pitre 2015-10-30 232 /* the remainder can be computed with 32-bit regs */ \ 461a5e51 Nicolas Pitre 2015-10-30 233 __res_lo = (n); \ 461a5e51 Nicolas Pitre 2015-10-30 234 __rem = __n_lo - __res_lo * __base; \ 911918aa Nicolas Pitre 2015-11-02 235 } else if (likely(((n) >> 32) == 0)) { \ ^1da177e Linus Torvalds 2005-04-16 236 __rem = (uint32_t)(n) % __base; \ ^1da177e Linus Torvalds 2005-04-16 237 (n) = (uint32_t)(n) / __base; \ ^1da177e Linus Torvalds 2005-04-16 238 } else \ ^1da177e Linus Torvalds 2005-04-16 @239 __rem = __div64_32(&(n), __base); \ ^1da177e Linus Torvalds 2005-04-16 240 __rem; \ ^1da177e Linus Torvalds 2005-04-16 241 }) ^1da177e Linus Torvalds 2005-04-16 242 :::::: The code at line 239 was first introduced by commit :::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2 :::::: TO: Linus Torvalds <torvalds@ppc970.osdl.org> :::::: CC: Linus Torvalds <torvalds@ppc970.osdl.org> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile index 5ce75df57e1a..994357fa560b 100644 --- a/drivers/clk/actions/Makefile +++ b/drivers/clk/actions/Makefile @@ -4,3 +4,4 @@ clk-owl-y += owl-common.o clk-owl-y += owl-gate.o clk-owl-y += owl-mux.o clk-owl-y += owl-divider.o +clk-owl-y += owl-factor.o diff --git a/drivers/clk/actions/owl-factor.c b/drivers/clk/actions/owl-factor.c new file mode 100644 index 000000000000..c48a2c8b479e --- /dev/null +++ b/drivers/clk/actions/owl-factor.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// OWL factor clock driver +// +// Copyright (c) 2014 Actions Semi Inc. +// Author: David Liu <liuwei@actions-semi.com> +// +// Copyright (c) 2018 Linaro Ltd. +// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + +#include <linux/clk-provider.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include "owl-factor.h" + +static unsigned int _get_table_maxval(const struct clk_factor_table *table) +{ + unsigned int maxval = 0; + const struct clk_factor_table *clkt; + + for (clkt = table; clkt->div; clkt++) + if (clkt->val > maxval) + maxval = clkt->val; + return maxval; +} + +static int _get_table_div_mul(const struct clk_factor_table *table, + unsigned int val, unsigned int *mul, unsigned int *div) +{ + const struct clk_factor_table *clkt; + + for (clkt = table; clkt->div; clkt++) { + if (clkt->val == val) { + *mul = clkt->mul; + *div = clkt->div; + return 1; + } + } + + return 0; +} + +static unsigned int _get_table_val(const struct clk_factor_table *table, + unsigned long rate, unsigned long parent_rate) +{ + const struct clk_factor_table *clkt; + int val = -1; + u64 calc_rate; + + for (clkt = table; clkt->div; clkt++) { + calc_rate = parent_rate * clkt->mul; + do_div(calc_rate, clkt->div); + + if ((unsigned long)calc_rate <= rate) { + val = clkt->val; + break; + } + } + + if (val == -1) + val = _get_table_maxval(table); + + return val; +} + +static int clk_val_best(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate) +{ + struct owl_factor *factor = hw_to_owl_factor(hw); + struct owl_factor_hw *factor_hw = &factor->factor_hw; + const struct clk_factor_table *clkt = factor_hw->table; + unsigned long parent_rate, try_parent_rate, best = 0, cur_rate; + unsigned long parent_rate_saved = *best_parent_rate; + int bestval = 0; + + if (!rate) + rate = 1; + + if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { + parent_rate = *best_parent_rate; + bestval = _get_table_val(clkt, rate, parent_rate); + return bestval; + } + + for (clkt = factor_hw->table; clkt->div; clkt++) { + try_parent_rate = rate * clkt->div / clkt->mul; + + if (try_parent_rate == parent_rate_saved) { + pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n", + __func__, clkt->val, clkt->mul, clkt->div, + try_parent_rate); + /* + * It's the most ideal case if the requested rate can be + * divided from parent clock without any need to change + * parent rate, so return the divider immediately. + */ + *best_parent_rate = parent_rate_saved; + return clkt->val; + } + + parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), + try_parent_rate); + cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul; + if (cur_rate <= rate && cur_rate > best) { + bestval = clkt->val; + best = cur_rate; + *best_parent_rate = parent_rate; + } + } + + if (!bestval) { + bestval = _get_table_maxval(clkt); + *best_parent_rate = clk_hw_round_rate( + clk_hw_get_parent(hw), 1); + } + + return bestval; +} + +long owl_factor_helper_round_rate(struct owl_clk_common *common, + const struct owl_factor_hw *factor_hw, + unsigned long rate, + unsigned long *parent_rate) +{ + const struct clk_factor_table *clkt = factor_hw->table; + unsigned int val, mul = 0, div = 1; + + val = clk_val_best(&common->hw, rate, parent_rate); + _get_table_div_mul(clkt, val, &mul, &div); + + return *parent_rate * mul / div; +} + +static long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct owl_factor *factor = hw_to_owl_factor(hw); + struct owl_factor_hw *factor_hw = &factor->factor_hw; + + return owl_factor_helper_round_rate(&factor->common, factor_hw, + rate, parent_rate); +} + +unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common, + const struct owl_factor_hw *factor_hw, + unsigned long parent_rate) +{ + const struct clk_factor_table *clkt = factor_hw->table; + unsigned long rate; + u32 reg, val, mul, div; + + div = 0; + mul = 0; + + regmap_read(common->regmap, factor_hw->reg, ®); + + val = reg >> factor_hw->shift; + val &= div_mask(factor_hw); + + _get_table_div_mul(clkt, val, &mul, &div); + if (!div) { + WARN(!(factor_hw->fct_flags & CLK_DIVIDER_ALLOW_ZERO), + "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", + __clk_get_name(common->hw.clk)); + return parent_rate; + } + + rate = parent_rate * mul; + do_div(rate, div); + + return rate; +} + +static unsigned long owl_factor_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct owl_factor *factor = hw_to_owl_factor(hw); + struct owl_factor_hw *factor_hw = &factor->factor_hw; + struct owl_clk_common *common = &factor->common; + + return owl_factor_helper_recalc_rate(common, factor_hw, parent_rate); +} + +int owl_factor_helper_set_rate(const struct owl_clk_common *common, + const struct owl_factor_hw *factor_hw, + unsigned long rate, + unsigned long parent_rate) +{ + u32 val, reg; + + val = _get_table_val(factor_hw->table, rate, parent_rate); + + if (val > div_mask(factor_hw)) + val = div_mask(factor_hw); + + regmap_read(common->regmap, factor_hw->reg, ®); + + reg &= ~(div_mask(factor_hw) << factor_hw->shift); + reg |= val << factor_hw->shift; + + regmap_write(common->regmap, factor_hw->reg, reg); + + return 0; +} + +static int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct owl_factor *factor = hw_to_owl_factor(hw); + struct owl_factor_hw *factor_hw = &factor->factor_hw; + struct owl_clk_common *common = &factor->common; + + return owl_factor_helper_set_rate(common, factor_hw, + rate, parent_rate); +} + +const struct clk_ops owl_factor_ops = { + .round_rate = owl_factor_round_rate, + .recalc_rate = owl_factor_recalc_rate, + .set_rate = owl_factor_set_rate, +}; diff --git a/drivers/clk/actions/owl-factor.h b/drivers/clk/actions/owl-factor.h new file mode 100644 index 000000000000..f1a7ffe896e1 --- /dev/null +++ b/drivers/clk/actions/owl-factor.h @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// OWL factor clock driver +// +// Copyright (c) 2014 Actions Semi Inc. +// Author: David Liu <liuwei@actions-semi.com> +// +// Copyright (c) 2018 Linaro Ltd. +// Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + +#ifndef _OWL_FACTOR_H_ +#define _OWL_FACTOR_H_ + +#include "owl-common.h" + +struct clk_factor_table { + unsigned int val; + unsigned int mul; + unsigned int div; +}; + +struct owl_factor_hw { + u32 reg; + u8 shift; + u8 width; + u8 fct_flags; + struct clk_factor_table *table; +}; + +struct owl_factor { + struct owl_factor_hw factor_hw; + struct owl_clk_common common; +}; + +#define OWL_FACTOR_HW(_reg, _shift, _width, _fct_flags, _table) \ + { \ + .reg = _reg, \ + .shift = _shift, \ + .width = _width, \ + .fct_flags = _fct_flags, \ + .table = _table, \ + } + +#define OWL_FACTOR(_struct, _name, _parent, _reg, \ + _shift, _width, _table, _fct_flags, _flags) \ + struct owl_factor _struct = { \ + .factor_hw = OWL_FACTOR_HW(_reg, _shift, \ + _width, _fct_flags, _table), \ + .common = { \ + .regmap = NULL, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &owl_factor_ops, \ + _flags), \ + }, \ + } + +#define div_mask(d) ((1 << ((d)->width)) - 1) + +static inline struct owl_factor *hw_to_owl_factor(const struct clk_hw *hw) +{ + struct owl_clk_common *common = hw_to_owl_clk_common(hw); + + return container_of(common, struct owl_factor, common); +} + +long owl_factor_helper_round_rate(struct owl_clk_common *common, + const struct owl_factor_hw *factor_hw, + unsigned long rate, + unsigned long *parent_rate); + +unsigned long owl_factor_helper_recalc_rate(struct owl_clk_common *common, + const struct owl_factor_hw *factor_hw, + unsigned long parent_rate); + +int owl_factor_helper_set_rate(const struct owl_clk_common *common, + const struct owl_factor_hw *factor_hw, + unsigned long rate, + unsigned long parent_rate); + +extern const struct clk_ops owl_factor_ops; + +#endif /* _OWL_FACTOR_H_ */
Add support for Actions Semi factor clock together with helper functions to be used in composite clock. Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> --- drivers/clk/actions/Makefile | 1 + drivers/clk/actions/owl-factor.c | 222 +++++++++++++++++++++++++++++++++++++++ drivers/clk/actions/owl-factor.h | 83 +++++++++++++++ 3 files changed, 306 insertions(+) create mode 100644 drivers/clk/actions/owl-factor.c create mode 100644 drivers/clk/actions/owl-factor.h -- 2.14.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html