1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Spreadtrum divider clock driver 4 // 5 // Copyright (C) 2017 Spreadtrum, Inc. 6 // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com> 7 8 #include <linux/clk-provider.h> 9 10 #include "div.h" 11 12 long sprd_div_helper_round_rate(struct sprd_clk_common *common, 13 const struct sprd_div_internal *div, 14 unsigned long rate, 15 unsigned long *parent_rate) 16 { 17 return divider_round_rate(&common->hw, rate, parent_rate, 18 NULL, div->width, 0); 19 } 20 EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate); 21 22 static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate, 23 unsigned long *parent_rate) 24 { 25 struct sprd_div *cd = hw_to_sprd_div(hw); 26 27 return sprd_div_helper_round_rate(&cd->common, &cd->div, 28 rate, parent_rate); 29 } 30 31 unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, 32 const struct sprd_div_internal *div, 33 unsigned long parent_rate) 34 { 35 unsigned long val; 36 unsigned int reg; 37 38 regmap_read(common->regmap, common->reg, ®); 39 val = reg >> div->shift; 40 val &= (1 << div->width) - 1; 41 42 return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0, 43 div->width); 44 } 45 EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate); 46 47 static unsigned long sprd_div_recalc_rate(struct clk_hw *hw, 48 unsigned long parent_rate) 49 { 50 struct sprd_div *cd = hw_to_sprd_div(hw); 51 52 return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate); 53 } 54 55 int sprd_div_helper_set_rate(const struct sprd_clk_common *common, 56 const struct sprd_div_internal *div, 57 unsigned long rate, 58 unsigned long parent_rate) 59 { 60 unsigned long val; 61 unsigned int reg; 62 63 val = divider_get_val(rate, parent_rate, NULL, 64 div->width, 0); 65 66 regmap_read(common->regmap, common->reg, ®); 67 reg &= ~GENMASK(div->width + div->shift - 1, div->shift); 68 69 regmap_write(common->regmap, common->reg, 70 reg | (val << div->shift)); 71 72 return 0; 73 74 } 75 EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate); 76 77 static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate, 78 unsigned long parent_rate) 79 { 80 struct sprd_div *cd = hw_to_sprd_div(hw); 81 82 return sprd_div_helper_set_rate(&cd->common, &cd->div, 83 rate, parent_rate); 84 } 85 86 const struct clk_ops sprd_div_ops = { 87 .recalc_rate = sprd_div_recalc_rate, 88 .round_rate = sprd_div_round_rate, 89 .set_rate = sprd_div_set_rate, 90 }; 91 EXPORT_SYMBOL_GPL(sprd_div_ops); 92