diff options
author | Jerome Brunet <jbrunet@baylibre.com> | 2018-05-22 12:34:53 -0400 |
---|---|---|
committer | Jerome Brunet <jbrunet@baylibre.com> | 2018-07-09 07:47:22 -0400 |
commit | 47f21315a6e4454ed9d8a450288a0989113e1e44 (patch) | |
tree | b775418d62d71c4e8db42c6c1b2f82f32d611d8a | |
parent | a9387f70cd27a8ca82c2141ef33787868d5c8de9 (diff) |
clk: meson: add clk-phase clock driver
Add a driver based meson clk-regmap to control clock phase on
amlogic SoCs
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
-rw-r--r-- | drivers/clk/meson/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/meson/clk-phase.c | 63 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.h | 8 |
3 files changed, 72 insertions, 0 deletions
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index d0d13aeb369a..162e4a6f5c55 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o | 5 | obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o |
6 | obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-phase.o | ||
6 | obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o | 7 | obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o |
7 | obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o | 8 | obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o |
8 | obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o | 9 | obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o |
diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c new file mode 100644 index 000000000000..cba43748ce3d --- /dev/null +++ b/drivers/clk/meson/clk-phase.c | |||
@@ -0,0 +1,63 @@ | |||
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) | ||
2 | /* | ||
3 | * Copyright (c) 2018 BayLibre, SAS. | ||
4 | * Author: Jerome Brunet <jbrunet@baylibre.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/clk-provider.h> | ||
8 | #include "clkc.h" | ||
9 | |||
10 | #define phase_step(_width) (360 / (1 << (_width))) | ||
11 | |||
12 | static inline struct meson_clk_phase_data * | ||
13 | meson_clk_phase_data(struct clk_regmap *clk) | ||
14 | { | ||
15 | return (struct meson_clk_phase_data *)clk->data; | ||
16 | } | ||
17 | |||
18 | int meson_clk_degrees_from_val(unsigned int val, unsigned int width) | ||
19 | { | ||
20 | return phase_step(width) * val; | ||
21 | } | ||
22 | EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val); | ||
23 | |||
24 | unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width) | ||
25 | { | ||
26 | unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width)); | ||
27 | |||
28 | /* | ||
29 | * This last calculation is here for cases when degrees is rounded | ||
30 | * to 360, in which case val == (1 << width). | ||
31 | */ | ||
32 | return val % (1 << width); | ||
33 | } | ||
34 | EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val); | ||
35 | |||
36 | static int meson_clk_phase_get_phase(struct clk_hw *hw) | ||
37 | { | ||
38 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
39 | struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); | ||
40 | unsigned int val; | ||
41 | |||
42 | val = meson_parm_read(clk->map, &phase->ph); | ||
43 | |||
44 | return meson_clk_degrees_from_val(val, phase->ph.width); | ||
45 | } | ||
46 | |||
47 | static int meson_clk_phase_set_phase(struct clk_hw *hw, int degrees) | ||
48 | { | ||
49 | struct clk_regmap *clk = to_clk_regmap(hw); | ||
50 | struct meson_clk_phase_data *phase = meson_clk_phase_data(clk); | ||
51 | unsigned int val; | ||
52 | |||
53 | val = meson_clk_degrees_to_val(degrees, phase->ph.width); | ||
54 | meson_parm_write(clk->map, &phase->ph, val); | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | const struct clk_ops meson_clk_phase_ops = { | ||
60 | .get_phase = meson_clk_phase_get_phase, | ||
61 | .set_phase = meson_clk_phase_set_phase, | ||
62 | }; | ||
63 | EXPORT_SYMBOL_GPL(meson_clk_phase_ops); | ||
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 2fb084330ee9..fd520ccdd1be 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h | |||
@@ -96,6 +96,13 @@ struct meson_clk_audio_div_data { | |||
96 | u8 flags; | 96 | u8 flags; |
97 | }; | 97 | }; |
98 | 98 | ||
99 | struct meson_clk_phase_data { | ||
100 | struct parm ph; | ||
101 | }; | ||
102 | |||
103 | int meson_clk_degrees_from_val(unsigned int val, unsigned int width); | ||
104 | unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width); | ||
105 | |||
99 | #define MESON_GATE(_name, _reg, _bit) \ | 106 | #define MESON_GATE(_name, _reg, _bit) \ |
100 | struct clk_regmap _name = { \ | 107 | struct clk_regmap _name = { \ |
101 | .data = &(struct clk_regmap_gate_data){ \ | 108 | .data = &(struct clk_regmap_gate_data){ \ |
@@ -119,5 +126,6 @@ extern const struct clk_ops meson_clk_mpll_ro_ops; | |||
119 | extern const struct clk_ops meson_clk_mpll_ops; | 126 | extern const struct clk_ops meson_clk_mpll_ops; |
120 | extern const struct clk_ops meson_clk_audio_divider_ro_ops; | 127 | extern const struct clk_ops meson_clk_audio_divider_ro_ops; |
121 | extern const struct clk_ops meson_clk_audio_divider_ops; | 128 | extern const struct clk_ops meson_clk_audio_divider_ops; |
129 | extern const struct clk_ops meson_clk_phase_ops; | ||
122 | 130 | ||
123 | #endif /* __CLKC_H */ | 131 | #endif /* __CLKC_H */ |