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, ®); 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, ®); 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 }; 95