1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // OWL divider clock driver |
4 | // |
5 | // Copyright (c) 2014 Actions Semi Inc. |
6 | // Author: David Liu <liuwei@actions-semi.com> |
7 | // |
8 | // Copyright (c) 2018 Linaro Ltd. |
9 | // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> |
10 | |
11 | #include <linux/clk-provider.h> |
12 | #include <linux/regmap.h> |
13 | |
14 | #include "owl-divider.h" |
15 | |
16 | long owl_divider_helper_round_rate(struct owl_clk_common *common, |
17 | const struct owl_divider_hw *div_hw, |
18 | unsigned long rate, |
19 | unsigned long *parent_rate) |
20 | { |
21 | return divider_round_rate(hw: &common->hw, rate, prate: parent_rate, |
22 | table: div_hw->table, width: div_hw->width, |
23 | flags: div_hw->div_flags); |
24 | } |
25 | |
26 | static long owl_divider_round_rate(struct clk_hw *hw, unsigned long rate, |
27 | unsigned long *parent_rate) |
28 | { |
29 | struct owl_divider *div = hw_to_owl_divider(hw); |
30 | |
31 | return owl_divider_helper_round_rate(common: &div->common, div_hw: &div->div_hw, |
32 | rate, parent_rate); |
33 | } |
34 | |
35 | unsigned long owl_divider_helper_recalc_rate(struct owl_clk_common *common, |
36 | const struct owl_divider_hw *div_hw, |
37 | unsigned long parent_rate) |
38 | { |
39 | unsigned long val; |
40 | unsigned int reg; |
41 | |
42 | regmap_read(map: common->regmap, reg: div_hw->reg, val: ®); |
43 | val = reg >> div_hw->shift; |
44 | val &= (1 << div_hw->width) - 1; |
45 | |
46 | return divider_recalc_rate(hw: &common->hw, parent_rate, |
47 | val, table: div_hw->table, |
48 | flags: div_hw->div_flags, |
49 | width: div_hw->width); |
50 | } |
51 | |
52 | static unsigned long owl_divider_recalc_rate(struct clk_hw *hw, |
53 | unsigned long parent_rate) |
54 | { |
55 | struct owl_divider *div = hw_to_owl_divider(hw); |
56 | |
57 | return owl_divider_helper_recalc_rate(common: &div->common, |
58 | div_hw: &div->div_hw, parent_rate); |
59 | } |
60 | |
61 | int owl_divider_helper_set_rate(const struct owl_clk_common *common, |
62 | const struct owl_divider_hw *div_hw, |
63 | unsigned long rate, |
64 | unsigned long parent_rate) |
65 | { |
66 | unsigned long val; |
67 | unsigned int reg; |
68 | |
69 | val = divider_get_val(rate, parent_rate, table: div_hw->table, |
70 | width: div_hw->width, flags: 0); |
71 | |
72 | regmap_read(map: common->regmap, reg: div_hw->reg, val: ®); |
73 | reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift); |
74 | |
75 | regmap_write(map: common->regmap, reg: div_hw->reg, |
76 | val: reg | (val << div_hw->shift)); |
77 | |
78 | return 0; |
79 | } |
80 | |
81 | static int owl_divider_set_rate(struct clk_hw *hw, unsigned long rate, |
82 | unsigned long parent_rate) |
83 | { |
84 | struct owl_divider *div = hw_to_owl_divider(hw); |
85 | |
86 | return owl_divider_helper_set_rate(common: &div->common, div_hw: &div->div_hw, |
87 | rate, parent_rate); |
88 | } |
89 | |
90 | const struct clk_ops owl_divider_ops = { |
91 | .recalc_rate = owl_divider_recalc_rate, |
92 | .round_rate = owl_divider_round_rate, |
93 | .set_rate = owl_divider_set_rate, |
94 | }; |
95 | |