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