div.c (2368B)
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 12long 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} 20EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate); 21 22static 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 31unsigned 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} 45EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate); 46 47static 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 55int 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} 75EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate); 76 77static 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 86const 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}; 91EXPORT_SYMBOL_GPL(sprd_div_ops);