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 int owl_divider_determine_rate(struct clk_hw *hw, 27 struct clk_rate_request *req) 28 { 29 struct owl_divider *div = hw_to_owl_divider(hw); 30 31 req->rate = owl_divider_helper_round_rate(&div->common, &div->div_hw, 32 req->rate, 33 &req->best_parent_rate); 34 35 return 0; 36 } 37 38 unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, 39 const struct owl_divider_hw *div_hw, 40 unsigned long parent_rate) 41 { 42 unsigned long val; 43 unsigned int reg; 44 45 regmap_read(common->regmap, div_hw->reg, ®); 46 val = reg >> div_hw->shift; 47 val &= (1 << div_hw->width) - 1; 48 49 return divider_recalc_rate(&common->hw, parent_rate, 50 val, div_hw->table, 51 div_hw->div_flags, 52 div_hw->width); 53 } 54 55 static unsigned long owl_divider_recalc_rate(struct clk_hw *hw, 56 unsigned long parent_rate) 57 { 58 struct owl_divider *div = hw_to_owl_divider(hw); 59 60 return owl_divider_helper_recalc_rate(&div->common, 61 &div->div_hw, parent_rate); 62 } 63 64 int owl_divider_helper_set_rate(const struct owl_clk_common *common, 65 const struct owl_divider_hw *div_hw, 66 unsigned long rate, 67 unsigned long parent_rate) 68 { 69 unsigned long val; 70 unsigned int reg; 71 72 val = divider_get_val(rate, parent_rate, div_hw->table, 73 div_hw->width, 0); 74 75 regmap_read(common->regmap, div_hw->reg, ®); 76 reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift); 77 78 regmap_write(common->regmap, div_hw->reg, 79 reg | (val << div_hw->shift)); 80 81 return 0; 82 } 83 84 static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate, 85 unsigned long parent_rate) 86 { 87 struct owl_divider *div = hw_to_owl_divider(hw); 88 89 return owl_divider_helper_set_rate(&div->common, &div->div_hw, 90 rate, parent_rate); 91 } 92 93 const struct clk_ops owl_divider_ops = { 94 .recalc_rate = owl_divider_recalc_rate, 95 .determine_rate = owl_divider_determine_rate, 96 .set_rate = owl_divider_set_rate, 97 }; 98