1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Spreadtrum divider clock driver |
4 | // |
5 | // Copyright (C) 2017 Spreadtrum, Inc. |
6 | // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
7 | |
8 | #include <linux/clk-provider.h> |
9 | |
10 | #include "div.h" |
11 | |
12 | static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate, |
13 | unsigned long *parent_rate) |
14 | { |
15 | struct sprd_div *cd = hw_to_sprd_div(hw); |
16 | |
17 | return divider_round_rate(hw: &cd->common.hw, rate, prate: parent_rate, NULL, |
18 | width: cd->div.width, flags: 0); |
19 | } |
20 | |
21 | unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, |
22 | const struct sprd_div_internal *div, |
23 | unsigned long parent_rate) |
24 | { |
25 | unsigned long val; |
26 | unsigned int reg; |
27 | |
28 | regmap_read(map: common->regmap, reg: common->reg + div->offset, val: ®); |
29 | val = reg >> div->shift; |
30 | val &= (1 << div->width) - 1; |
31 | |
32 | return divider_recalc_rate(hw: &common->hw, parent_rate, val, NULL, flags: 0, |
33 | width: div->width); |
34 | } |
35 | EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate); |
36 | |
37 | static unsigned long sprd_div_recalc_rate(struct clk_hw *hw, |
38 | unsigned long parent_rate) |
39 | { |
40 | struct sprd_div *cd = hw_to_sprd_div(hw); |
41 | |
42 | return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate); |
43 | } |
44 | |
45 | int sprd_div_helper_set_rate(const struct sprd_clk_common *common, |
46 | const struct sprd_div_internal *div, |
47 | unsigned long rate, |
48 | unsigned long parent_rate) |
49 | { |
50 | unsigned long val; |
51 | unsigned int reg; |
52 | |
53 | val = divider_get_val(rate, parent_rate, NULL, |
54 | width: div->width, flags: 0); |
55 | |
56 | regmap_read(map: common->regmap, reg: common->reg + div->offset, val: ®); |
57 | reg &= ~GENMASK(div->width + div->shift - 1, div->shift); |
58 | |
59 | regmap_write(map: common->regmap, reg: common->reg + div->offset, |
60 | val: reg | (val << div->shift)); |
61 | |
62 | return 0; |
63 | |
64 | } |
65 | EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate); |
66 | |
67 | static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate, |
68 | unsigned long parent_rate) |
69 | { |
70 | struct sprd_div *cd = hw_to_sprd_div(hw); |
71 | |
72 | return sprd_div_helper_set_rate(&cd->common, &cd->div, |
73 | rate, parent_rate); |
74 | } |
75 | |
76 | const struct clk_ops sprd_div_ops = { |
77 | .recalc_rate = sprd_div_recalc_rate, |
78 | .round_rate = sprd_div_round_rate, |
79 | .set_rate = sprd_div_set_rate, |
80 | }; |
81 | EXPORT_SYMBOL_GPL(sprd_div_ops); |
82 | |