Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Spreadtrum divider clock driver
0004 //
0005 // Copyright (C) 2017 Spreadtrum, Inc.
0006 // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
0007 
0008 #include <linux/clk-provider.h>
0009 
0010 #include "div.h"
0011 
0012 long sprd_div_helper_round_rate(struct sprd_clk_common *common,
0013                 const struct sprd_div_internal *div,
0014                 unsigned long rate,
0015                 unsigned long *parent_rate)
0016 {
0017     return divider_round_rate(&common->hw, rate, parent_rate,
0018                   NULL, div->width, 0);
0019 }
0020 EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate);
0021 
0022 static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate,
0023                 unsigned long *parent_rate)
0024 {
0025     struct sprd_div *cd = hw_to_sprd_div(hw);
0026 
0027     return sprd_div_helper_round_rate(&cd->common, &cd->div,
0028                       rate, parent_rate);
0029 }
0030 
0031 unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common,
0032                       const struct sprd_div_internal *div,
0033                       unsigned long parent_rate)
0034 {
0035     unsigned long val;
0036     unsigned int reg;
0037 
0038     regmap_read(common->regmap, common->reg, &reg);
0039     val = reg >> div->shift;
0040     val &= (1 << div->width) - 1;
0041 
0042     return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0,
0043                    div->width);
0044 }
0045 EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate);
0046 
0047 static unsigned long sprd_div_recalc_rate(struct clk_hw *hw,
0048                       unsigned long parent_rate)
0049 {
0050     struct sprd_div *cd = hw_to_sprd_div(hw);
0051 
0052     return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate);
0053 }
0054 
0055 int sprd_div_helper_set_rate(const struct sprd_clk_common *common,
0056                  const struct sprd_div_internal *div,
0057                  unsigned long rate,
0058                  unsigned long parent_rate)
0059 {
0060     unsigned long val;
0061     unsigned int reg;
0062 
0063     val = divider_get_val(rate, parent_rate, NULL,
0064                   div->width, 0);
0065 
0066     regmap_read(common->regmap, common->reg, &reg);
0067     reg &= ~GENMASK(div->width + div->shift - 1, div->shift);
0068 
0069     regmap_write(common->regmap, common->reg,
0070               reg | (val << div->shift));
0071 
0072     return 0;
0073 
0074 }
0075 EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate);
0076 
0077 static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate,
0078                  unsigned long parent_rate)
0079 {
0080     struct sprd_div *cd = hw_to_sprd_div(hw);
0081 
0082     return sprd_div_helper_set_rate(&cd->common, &cd->div,
0083                     rate, parent_rate);
0084 }
0085 
0086 const struct clk_ops sprd_div_ops = {
0087     .recalc_rate = sprd_div_recalc_rate,
0088     .round_rate = sprd_div_round_rate,
0089     .set_rate = sprd_div_set_rate,
0090 };
0091 EXPORT_SYMBOL_GPL(sprd_div_ops);