xref: /openbmc/linux/drivers/clk/qcom/clk-regmap-divider.c (revision 4116076e8cbfaacb5925c24a4d22e6b47a96eb42)
1*4116076eSJosh Cartwright /*
2*4116076eSJosh Cartwright  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3*4116076eSJosh Cartwright  *
4*4116076eSJosh Cartwright  * This software is licensed under the terms of the GNU General Public
5*4116076eSJosh Cartwright  * License version 2, as published by the Free Software Foundation, and
6*4116076eSJosh Cartwright  * may be copied, distributed, and modified under those terms.
7*4116076eSJosh Cartwright  *
8*4116076eSJosh Cartwright  * This program is distributed in the hope that it will be useful,
9*4116076eSJosh Cartwright  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10*4116076eSJosh Cartwright  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*4116076eSJosh Cartwright  * GNU General Public License for more details.
12*4116076eSJosh Cartwright  */
13*4116076eSJosh Cartwright 
14*4116076eSJosh Cartwright #include <linux/kernel.h>
15*4116076eSJosh Cartwright #include <linux/bitops.h>
16*4116076eSJosh Cartwright #include <linux/regmap.h>
17*4116076eSJosh Cartwright #include <linux/export.h>
18*4116076eSJosh Cartwright 
19*4116076eSJosh Cartwright #include "clk-regmap-divider.h"
20*4116076eSJosh Cartwright 
21*4116076eSJosh Cartwright static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw)
22*4116076eSJosh Cartwright {
23*4116076eSJosh Cartwright 	return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr);
24*4116076eSJosh Cartwright }
25*4116076eSJosh Cartwright 
26*4116076eSJosh Cartwright static long div_round_rate(struct clk_hw *hw, unsigned long rate,
27*4116076eSJosh Cartwright 			   unsigned long *prate)
28*4116076eSJosh Cartwright {
29*4116076eSJosh Cartwright 	struct clk_regmap_div *divider = to_clk_regmap_div(hw);
30*4116076eSJosh Cartwright 
31*4116076eSJosh Cartwright 	return divider_round_rate(hw, rate, prate, NULL, divider->width,
32*4116076eSJosh Cartwright 				  CLK_DIVIDER_ROUND_CLOSEST);
33*4116076eSJosh Cartwright }
34*4116076eSJosh Cartwright 
35*4116076eSJosh Cartwright static int div_set_rate(struct clk_hw *hw, unsigned long rate,
36*4116076eSJosh Cartwright 			unsigned long parent_rate)
37*4116076eSJosh Cartwright {
38*4116076eSJosh Cartwright 	struct clk_regmap_div *divider = to_clk_regmap_div(hw);
39*4116076eSJosh Cartwright 	struct clk_regmap *clkr = &divider->clkr;
40*4116076eSJosh Cartwright 	u32 div;
41*4116076eSJosh Cartwright 
42*4116076eSJosh Cartwright 	div = divider_get_val(rate, parent_rate, NULL, divider->width,
43*4116076eSJosh Cartwright 			      CLK_DIVIDER_ROUND_CLOSEST);
44*4116076eSJosh Cartwright 
45*4116076eSJosh Cartwright 	return regmap_update_bits(clkr->regmap, divider->reg,
46*4116076eSJosh Cartwright 				  (BIT(divider->width) - 1) << divider->shift,
47*4116076eSJosh Cartwright 				  div << divider->shift);
48*4116076eSJosh Cartwright }
49*4116076eSJosh Cartwright 
50*4116076eSJosh Cartwright static unsigned long div_recalc_rate(struct clk_hw *hw,
51*4116076eSJosh Cartwright 				     unsigned long parent_rate)
52*4116076eSJosh Cartwright {
53*4116076eSJosh Cartwright 	struct clk_regmap_div *divider = to_clk_regmap_div(hw);
54*4116076eSJosh Cartwright 	struct clk_regmap *clkr = &divider->clkr;
55*4116076eSJosh Cartwright 	u32 div;
56*4116076eSJosh Cartwright 
57*4116076eSJosh Cartwright 	regmap_read(clkr->regmap, divider->reg, &div);
58*4116076eSJosh Cartwright 	div >>= divider->shift;
59*4116076eSJosh Cartwright 	div &= BIT(divider->width) - 1;
60*4116076eSJosh Cartwright 
61*4116076eSJosh Cartwright 	return divider_recalc_rate(hw, parent_rate, div, NULL,
62*4116076eSJosh Cartwright 				   CLK_DIVIDER_ROUND_CLOSEST);
63*4116076eSJosh Cartwright }
64*4116076eSJosh Cartwright 
65*4116076eSJosh Cartwright const struct clk_ops clk_regmap_div_ops = {
66*4116076eSJosh Cartwright 	.round_rate = div_round_rate,
67*4116076eSJosh Cartwright 	.set_rate = div_set_rate,
68*4116076eSJosh Cartwright 	.recalc_rate = div_recalc_rate,
69*4116076eSJosh Cartwright };
70*4116076eSJosh Cartwright EXPORT_SYMBOL_GPL(clk_regmap_div_ops);
71