]>
Commit | Line | Data |
---|---|---|
e10e2918 MS |
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 <[email protected]> | |
7 | // | |
8 | // Copyright (c) 2018 Linaro Ltd. | |
9 | // Author: Manivannan Sadhasivam <[email protected]> | |
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(&common->hw, rate, parent_rate, | |
22 | div_hw->table, div_hw->width, | |
23 | 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(&div->common, &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(common->regmap, div_hw->reg, ®); | |
43 | val = reg >> div_hw->shift; | |
44 | val &= (1 << div_hw->width) - 1; | |
45 | ||
46 | return divider_recalc_rate(&common->hw, parent_rate, | |
47 | val, div_hw->table, | |
48 | div_hw->div_flags, | |
49 | 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(&div->common, | |
58 | &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, div_hw->table, | |
70 | div_hw->width, 0); | |
71 | ||
72 | regmap_read(common->regmap, div_hw->reg, ®); | |
73 | reg &= ~GENMASK(div_hw->width + div_hw->shift - 1, div_hw->shift); | |
74 | ||
75 | regmap_write(common->regmap, div_hw->reg, | |
76 | 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(&div->common, &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 | }; |