diff options
-rw-r--r-- | drivers/clk/sprd/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/sprd/div.c | 90 | ||||
-rw-r--r-- | drivers/clk/sprd/div.h | 75 |
3 files changed, 166 insertions, 0 deletions
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile index cee36b511109..80e603905c90 100644 --- a/drivers/clk/sprd/Makefile +++ b/drivers/clk/sprd/Makefile | |||
@@ -3,3 +3,4 @@ obj-$(CONFIG_SPRD_COMMON_CLK) += clk-sprd.o | |||
3 | clk-sprd-y += common.o | 3 | clk-sprd-y += common.o |
4 | clk-sprd-y += gate.o | 4 | clk-sprd-y += gate.o |
5 | clk-sprd-y += mux.o | 5 | clk-sprd-y += mux.o |
6 | clk-sprd-y += div.o | ||
diff --git a/drivers/clk/sprd/div.c b/drivers/clk/sprd/div.c new file mode 100644 index 000000000000..887a8633fdc9 --- /dev/null +++ b/drivers/clk/sprd/div.c | |||
@@ -0,0 +1,90 @@ | |||
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 | long sprd_div_helper_round_rate(struct sprd_clk_common *common, | ||
13 | const struct sprd_div_internal *div, | ||
14 | unsigned long rate, | ||
15 | unsigned long *parent_rate) | ||
16 | { | ||
17 | return divider_round_rate(&common->hw, rate, parent_rate, | ||
18 | NULL, div->width, 0); | ||
19 | } | ||
20 | EXPORT_SYMBOL_GPL(sprd_div_helper_round_rate); | ||
21 | |||
22 | static long sprd_div_round_rate(struct clk_hw *hw, unsigned long rate, | ||
23 | unsigned long *parent_rate) | ||
24 | { | ||
25 | struct sprd_div *cd = hw_to_sprd_div(hw); | ||
26 | |||
27 | return sprd_div_helper_round_rate(&cd->common, &cd->div, | ||
28 | rate, parent_rate); | ||
29 | } | ||
30 | |||
31 | unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, | ||
32 | const struct sprd_div_internal *div, | ||
33 | unsigned long parent_rate) | ||
34 | { | ||
35 | unsigned long val; | ||
36 | unsigned int reg; | ||
37 | |||
38 | regmap_read(common->regmap, common->reg, ®); | ||
39 | val = reg >> div->shift; | ||
40 | val &= (1 << div->width) - 1; | ||
41 | |||
42 | return divider_recalc_rate(&common->hw, parent_rate, val, NULL, 0); | ||
43 | } | ||
44 | EXPORT_SYMBOL_GPL(sprd_div_helper_recalc_rate); | ||
45 | |||
46 | static unsigned long sprd_div_recalc_rate(struct clk_hw *hw, | ||
47 | unsigned long parent_rate) | ||
48 | { | ||
49 | struct sprd_div *cd = hw_to_sprd_div(hw); | ||
50 | |||
51 | return sprd_div_helper_recalc_rate(&cd->common, &cd->div, parent_rate); | ||
52 | } | ||
53 | |||
54 | int sprd_div_helper_set_rate(const struct sprd_clk_common *common, | ||
55 | const struct sprd_div_internal *div, | ||
56 | unsigned long rate, | ||
57 | unsigned long parent_rate) | ||
58 | { | ||
59 | unsigned long val; | ||
60 | unsigned int reg; | ||
61 | |||
62 | val = divider_get_val(rate, parent_rate, NULL, | ||
63 | div->width, 0); | ||
64 | |||
65 | regmap_read(common->regmap, common->reg, ®); | ||
66 | reg &= ~GENMASK(div->width + div->shift - 1, div->shift); | ||
67 | |||
68 | regmap_write(common->regmap, common->reg, | ||
69 | reg | (val << div->shift)); | ||
70 | |||
71 | return 0; | ||
72 | |||
73 | } | ||
74 | EXPORT_SYMBOL_GPL(sprd_div_helper_set_rate); | ||
75 | |||
76 | static int sprd_div_set_rate(struct clk_hw *hw, unsigned long rate, | ||
77 | unsigned long parent_rate) | ||
78 | { | ||
79 | struct sprd_div *cd = hw_to_sprd_div(hw); | ||
80 | |||
81 | return sprd_div_helper_set_rate(&cd->common, &cd->div, | ||
82 | rate, parent_rate); | ||
83 | } | ||
84 | |||
85 | const struct clk_ops sprd_div_ops = { | ||
86 | .recalc_rate = sprd_div_recalc_rate, | ||
87 | .round_rate = sprd_div_round_rate, | ||
88 | .set_rate = sprd_div_set_rate, | ||
89 | }; | ||
90 | EXPORT_SYMBOL_GPL(sprd_div_ops); | ||
diff --git a/drivers/clk/sprd/div.h b/drivers/clk/sprd/div.h new file mode 100644 index 000000000000..b3033d24d431 --- /dev/null +++ b/drivers/clk/sprd/div.h | |||
@@ -0,0 +1,75 @@ | |||
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 | #ifndef _SPRD_DIV_H_ | ||
9 | #define _SPRD_DIV_H_ | ||
10 | |||
11 | #include "common.h" | ||
12 | |||
13 | /** | ||
14 | * struct sprd_div_internal - Internal divider description | ||
15 | * @shift: Bit offset of the divider in its register | ||
16 | * @width: Width of the divider field in its register | ||
17 | * | ||
18 | * That structure represents a single divider, and is meant to be | ||
19 | * embedded in other structures representing the various clock | ||
20 | * classes. | ||
21 | */ | ||
22 | struct sprd_div_internal { | ||
23 | u8 shift; | ||
24 | u8 width; | ||
25 | }; | ||
26 | |||
27 | #define _SPRD_DIV_CLK(_shift, _width) \ | ||
28 | { \ | ||
29 | .shift = _shift, \ | ||
30 | .width = _width, \ | ||
31 | } | ||
32 | |||
33 | struct sprd_div { | ||
34 | struct sprd_div_internal div; | ||
35 | struct sprd_clk_common common; | ||
36 | }; | ||
37 | |||
38 | #define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \ | ||
39 | _shift, _width, _flags) \ | ||
40 | struct sprd_div _struct = { \ | ||
41 | .div = _SPRD_DIV_CLK(_shift, _width), \ | ||
42 | .common = { \ | ||
43 | .regmap = NULL, \ | ||
44 | .reg = _reg, \ | ||
45 | .hw.init = CLK_HW_INIT(_name, \ | ||
46 | _parent, \ | ||
47 | &sprd_div_ops, \ | ||
48 | _flags), \ | ||
49 | } \ | ||
50 | } | ||
51 | |||
52 | static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw) | ||
53 | { | ||
54 | struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); | ||
55 | |||
56 | return container_of(common, struct sprd_div, common); | ||
57 | } | ||
58 | |||
59 | long sprd_div_helper_round_rate(struct sprd_clk_common *common, | ||
60 | const struct sprd_div_internal *div, | ||
61 | unsigned long rate, | ||
62 | unsigned long *parent_rate); | ||
63 | |||
64 | unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, | ||
65 | const struct sprd_div_internal *div, | ||
66 | unsigned long parent_rate); | ||
67 | |||
68 | int sprd_div_helper_set_rate(const struct sprd_clk_common *common, | ||
69 | const struct sprd_div_internal *div, | ||
70 | unsigned long rate, | ||
71 | unsigned long parent_rate); | ||
72 | |||
73 | extern const struct clk_ops sprd_div_ops; | ||
74 | |||
75 | #endif /* _SPRD_DIV_H_ */ | ||