diff mbox series

[v5,08/12] clk: actions: Add factor clock support

Message ID 20180317100952.28538-9-manivannan.sadhasivam@linaro.org
State Accepted
Commit 4bb78fc9744a7597b8f847ca7343add5a31fa1b3
Headers show
Series None | expand

Commit Message

Manivannan Sadhasivam March 17, 2018, 10:09 a.m. UTC
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

Comments

kernel test robot March 18, 2018, 8:31 p.m. UTC | #1
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, &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
Stephen Boyd March 20, 2018, 1:08 a.m. UTC | #2
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
Stephen Boyd March 20, 2018, 1:11 a.m. UTC | #3
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
kernel test robot March 20, 2018, 1:41 a.m. UTC | #4
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 mbox series

Patch

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, &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);
+
+	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_ */