Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: actions: Add divider clock support

Add support for Actions Semi divider clock together with
helper functions to be used in composite clock.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Manivannan Sadhasivam and committed by
Stephen Boyd
e10e2918 a8338772

+170
+1
drivers/clk/actions/Makefile
··· 3 3 clk-owl-y += owl-common.o 4 4 clk-owl-y += owl-gate.o 5 5 clk-owl-y += owl-mux.o 6 + clk-owl-y += owl-divider.o
+94
drivers/clk/actions/owl-divider.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + // 3 + // OWL divider clock driver 4 + // 5 + // Copyright (c) 2014 Actions Semi Inc. 6 + // Author: David Liu <liuwei@actions-semi.com> 7 + // 8 + // Copyright (c) 2018 Linaro Ltd. 9 + // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 10 + 11 + #include <linux/clk-provider.h> 12 + #include <linux/regmap.h> 13 + 14 + #include "owl-divider.h" 15 + 16 + long owl_divider_helper_round_rate(struct owl_clk_common *common, 17 + const struct owl_divider_hw *div_hw, 18 + unsigned long rate, 19 + unsigned long *parent_rate) 20 + { 21 + return divider_round_rate(&common->hw, rate, parent_rate, 22 + div_hw->table, div_hw->width, 23 + div_hw->div_flags); 24 + } 25 + 26 + static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate, 27 + unsigned long *parent_rate) 28 + { 29 + struct owl_divider *div = hw_to_owl_divider(hw); 30 + 31 + return owl_divider_helper_round_rate(&div->common, &div->div_hw, 32 + rate, parent_rate); 33 + } 34 + 35 + unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, 36 + const struct owl_divider_hw *div_hw, 37 + unsigned long parent_rate) 38 + { 39 + unsigned long val; 40 + unsigned int reg; 41 + 42 + regmap_read(common->regmap, div_hw->reg, &reg); 43 + val = reg >> div_hw->shift; 44 + val &= (1 << div_hw->width) - 1; 45 + 46 + return divider_recalc_rate(&common->hw, parent_rate, 47 + val, div_hw->table, 48 + div_hw->div_flags, 49 + div_hw->width); 50 + } 51 + 52 + static unsigned long owl_divider_recalc_rate(struct clk_hw *hw, 53 + unsigned long parent_rate) 54 + { 55 + struct owl_divider *div = hw_to_owl_divider(hw); 56 + 57 + return owl_divider_helper_recalc_rate(&div->common, 58 + &div->div_hw, parent_rate); 59 + } 60 + 61 + int owl_divider_helper_set_rate(const struct owl_clk_common *common, 62 + const struct owl_divider_hw *div_hw, 63 + unsigned long rate, 64 + unsigned long parent_rate) 65 + { 66 + unsigned long val; 67 + unsigned int reg; 68 + 69 + val = divider_get_val(rate, parent_rate, div_hw->table, 70 + div_hw->width, 0); 71 + 72 + regmap_read(common->regmap, div_hw->reg, &reg); 73 + reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift); 74 + 75 + regmap_write(common->regmap, div_hw->reg, 76 + reg | (val << div_hw->shift)); 77 + 78 + return 0; 79 + } 80 + 81 + static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate, 82 + unsigned long parent_rate) 83 + { 84 + struct owl_divider *div = hw_to_owl_divider(hw); 85 + 86 + return owl_divider_helper_set_rate(&div->common, &div->div_hw, 87 + rate, parent_rate); 88 + } 89 + 90 + const struct clk_ops owl_divider_ops = { 91 + .recalc_rate = owl_divider_recalc_rate, 92 + .round_rate = owl_divider_round_rate, 93 + .set_rate = owl_divider_set_rate, 94 + };
+75
drivers/clk/actions/owl-divider.h
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + // 3 + // OWL divider clock driver 4 + // 5 + // Copyright (c) 2014 Actions Semi Inc. 6 + // Author: David Liu <liuwei@actions-semi.com> 7 + // 8 + // Copyright (c) 2018 Linaro Ltd. 9 + // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 10 + 11 + #ifndef _OWL_DIVIDER_H_ 12 + #define _OWL_DIVIDER_H_ 13 + 14 + #include "owl-common.h" 15 + 16 + struct owl_divider_hw { 17 + u32 reg; 18 + u8 shift; 19 + u8 width; 20 + u8 div_flags; 21 + struct clk_div_table *table; 22 + }; 23 + 24 + struct owl_divider { 25 + struct owl_divider_hw div_hw; 26 + struct owl_clk_common common; 27 + }; 28 + 29 + #define OWL_DIVIDER_HW(_reg, _shift, _width, _div_flags, _table) \ 30 + { \ 31 + .reg = _reg, \ 32 + .shift = _shift, \ 33 + .width = _width, \ 34 + .div_flags = _div_flags, \ 35 + .table = _table, \ 36 + } 37 + 38 + #define OWL_DIVIDER(_struct, _name, _parent, _reg, \ 39 + _shift, _width, _table, _div_flags, _flags) \ 40 + struct owl_divider _struct = { \ 41 + .div_hw = OWL_DIVIDER_HW(_reg, _shift, _width, \ 42 + _div_flags, _table), \ 43 + .common = { \ 44 + .regmap = NULL, \ 45 + .hw.init = CLK_HW_INIT(_name, \ 46 + _parent, \ 47 + &owl_divider_ops, \ 48 + _flags), \ 49 + }, \ 50 + } 51 + 52 + static inline struct owl_divider *hw_to_owl_divider(const struct clk_hw *hw) 53 + { 54 + struct owl_clk_common *common = hw_to_owl_clk_common(hw); 55 + 56 + return container_of(common, struct owl_divider, common); 57 + } 58 + 59 + long owl_divider_helper_round_rate(struct owl_clk_common *common, 60 + const struct owl_divider_hw *div_hw, 61 + unsigned long rate, 62 + unsigned long *parent_rate); 63 + 64 + unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, 65 + const struct owl_divider_hw *div_hw, 66 + unsigned long parent_rate); 67 + 68 + int owl_divider_helper_set_rate(const struct owl_clk_common *common, 69 + const struct owl_divider_hw *div_hw, 70 + unsigned long rate, 71 + unsigned long parent_rate); 72 + 73 + extern const struct clk_ops owl_divider_ops; 74 + 75 + #endif /* _OWL_DIVIDER_H_ */