Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // OWL divider clock driver
0004 //
0005 // Copyright (c) 2014 Actions Semi Inc.
0006 // Author: David Liu <liuwei@actions-semi.com>
0007 //
0008 // Copyright (c) 2018 Linaro Ltd.
0009 // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
0010 
0011 #include <linux/clk-provider.h>
0012 #include <linux/regmap.h>
0013 
0014 #include "owl-divider.h"
0015 
0016 long owl_divider_helper_round_rate(struct owl_clk_common *common,
0017                 const struct owl_divider_hw *div_hw,
0018                 unsigned long rate,
0019                 unsigned long *parent_rate)
0020 {
0021     return divider_round_rate(&common->hw, rate, parent_rate,
0022                   div_hw->table, div_hw->width,
0023                   div_hw->div_flags);
0024 }
0025 
0026 static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate,
0027                 unsigned long *parent_rate)
0028 {
0029     struct owl_divider *div = hw_to_owl_divider(hw);
0030 
0031     return owl_divider_helper_round_rate(&div->common, &div->div_hw,
0032                          rate, parent_rate);
0033 }
0034 
0035 unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common,
0036                      const struct owl_divider_hw *div_hw,
0037                      unsigned long parent_rate)
0038 {
0039     unsigned long val;
0040     unsigned int reg;
0041 
0042     regmap_read(common->regmap, div_hw->reg, &reg);
0043     val = reg >> div_hw->shift;
0044     val &= (1 << div_hw->width) - 1;
0045 
0046     return divider_recalc_rate(&common->hw, parent_rate,
0047                    val, div_hw->table,
0048                    div_hw->div_flags,
0049                    div_hw->width);
0050 }
0051 
0052 static unsigned long owl_divider_recalc_rate(struct clk_hw *hw,
0053                       unsigned long parent_rate)
0054 {
0055     struct owl_divider *div = hw_to_owl_divider(hw);
0056 
0057     return owl_divider_helper_recalc_rate(&div->common,
0058                           &div->div_hw, parent_rate);
0059 }
0060 
0061 int owl_divider_helper_set_rate(const struct owl_clk_common *common,
0062                 const struct owl_divider_hw *div_hw,
0063                 unsigned long rate,
0064                 unsigned long parent_rate)
0065 {
0066     unsigned long val;
0067     unsigned int reg;
0068 
0069     val = divider_get_val(rate, parent_rate, div_hw->table,
0070                   div_hw->width, 0);
0071 
0072     regmap_read(common->regmap, div_hw->reg, &reg);
0073     reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift);
0074 
0075     regmap_write(common->regmap, div_hw->reg,
0076               reg | (val << div_hw->shift));
0077 
0078     return 0;
0079 }
0080 
0081 static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate,
0082                 unsigned long parent_rate)
0083 {
0084     struct owl_divider *div = hw_to_owl_divider(hw);
0085 
0086     return owl_divider_helper_set_rate(&div->common, &div->div_hw,
0087                     rate, parent_rate);
0088 }
0089 
0090 const struct clk_ops owl_divider_ops = {
0091     .recalc_rate = owl_divider_recalc_rate,
0092     .round_rate = owl_divider_round_rate,
0093     .set_rate = owl_divider_set_rate,
0094 };