1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Copyright (c) 2016 Maxime Ripard. All rights reserved.
4 */
5
6 #ifndef _CCU_MP_H_
7 #define _CCU_MP_H_
8
9 #include <linux/bitops.h>
10 #include <linux/clk-provider.h>
11
12 #include "ccu_common.h"
13 #include "ccu_div.h"
14 #include "ccu_mult.h"
15 #include "ccu_mux.h"
16
17 /*
18 * struct ccu_mp - Definition of an M-P clock
19 *
20 * Clocks based on the formula parent >> P / M
21 */
22 struct ccu_mp {
23 u32 enable;
24
25 struct ccu_div_internal m;
26 struct ccu_div_internal p;
27 struct ccu_mux_internal mux;
28
29 unsigned int fixed_post_div;
30
31 struct ccu_common common;
32 };
33
34 #define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
35 _mshift, _mwidth, \
36 _pshift, _pwidth, \
37 _muxshift, _muxwidth, \
38 _gate, _postdiv, _flags) \
39 struct ccu_mp _struct = { \
40 .enable = _gate, \
41 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
42 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
43 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
44 .fixed_post_div = _postdiv, \
45 .common = { \
46 .reg = _reg, \
47 .features = CCU_FEATURE_FIXED_POSTDIV, \
48 .hw.init = CLK_HW_INIT_PARENTS(_name, \
49 _parents, \
50 &ccu_mp_ops, \
51 _flags), \
52 } \
53 }
54
55 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, \
56 _reg, \
57 _mshift, _mwidth, \
58 _pshift, _pwidth, \
59 _muxshift, _muxwidth, \
60 _gate, _postdiv, _flags)\
61 struct ccu_mp _struct = { \
62 .enable = _gate, \
63 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
64 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
65 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
66 .fixed_post_div = _postdiv, \
67 .common = { \
68 .reg = _reg, \
69 .features = CCU_FEATURE_FIXED_POSTDIV, \
70 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \
71 _parents, \
72 &ccu_mp_ops, \
73 _flags), \
74 } \
75 }
76
77 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
78 _mshift, _mwidth, \
79 _pshift, _pwidth, \
80 _muxshift, _muxwidth, \
81 _gate, _flags) \
82 struct ccu_mp _struct = { \
83 .enable = _gate, \
84 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
85 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
86 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
87 .common = { \
88 .reg = _reg, \
89 .hw.init = CLK_HW_INIT_PARENTS(_name, \
90 _parents, \
91 &ccu_mp_ops, \
92 _flags), \
93 } \
94 }
95
96 #define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg, \
97 _mshift, _mwidth, \
98 _pshift, _pwidth, \
99 _muxshift, _muxwidth, \
100 _flags) \
101 SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
102 _mshift, _mwidth, \
103 _pshift, _pwidth, \
104 _muxshift, _muxwidth, \
105 0, _flags)
106
107 #define SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(_struct, _name, _parents, _reg, \
108 _mshift, _mwidth, \
109 _pshift, _pwidth, \
110 _muxshift, _muxwidth, \
111 _gate, _postdiv, \
112 _flags) \
113 struct ccu_mp _struct = { \
114 .enable = _gate, \
115 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
116 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
117 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
118 .fixed_post_div = _postdiv, \
119 .common = { \
120 .reg = _reg, \
121 .features = CCU_FEATURE_FIXED_POSTDIV | \
122 CCU_FEATURE_DUAL_DIV, \
123 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \
124 _parents, \
125 &ccu_mp_ops, \
126 _flags), \
127 } \
128 }
129
130 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents, _reg, \
131 _mshift, _mwidth, \
132 _pshift, _pwidth, \
133 _muxshift, _muxwidth, \
134 _gate, _flags, _features) \
135 struct ccu_mp _struct = { \
136 .enable = _gate, \
137 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
138 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
139 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
140 .common = { \
141 .reg = _reg, \
142 .features = _features, \
143 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \
144 _parents, \
145 &ccu_mp_ops, \
146 _flags), \
147 } \
148 }
149
150 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
151 _mshift, _mwidth, \
152 _pshift, _pwidth, \
153 _muxshift, _muxwidth, \
154 _gate, _flags) \
155 SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents, \
156 _reg, _mshift, _mwidth, \
157 _pshift, _pwidth, \
158 _muxshift, _muxwidth, \
159 _gate, _flags, 0)
160
161 #define SUNXI_CCU_DUALDIV_MUX_GATE(_struct, _name, _parents, _reg, \
162 _mshift, _mwidth, \
163 _pshift, _pwidth, \
164 _muxshift, _muxwidth, \
165 _gate, _flags) \
166 SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents, \
167 _reg, _mshift, _mwidth, \
168 _pshift, _pwidth, \
169 _muxshift, _muxwidth, \
170 _gate, _flags, \
171 CCU_FEATURE_DUAL_DIV)
172
173 #define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg, \
174 _mshift, _mwidth, \
175 _pshift, _pwidth, \
176 _muxshift, _muxwidth, \
177 _flags) \
178 SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
179 _mshift, _mwidth, \
180 _pshift, _pwidth, \
181 _muxshift, _muxwidth, \
182 0, _flags)
183
184 #define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
185 _mshift, _mwidth, \
186 _pshift, _pwidth, \
187 _muxshift, _muxwidth, \
188 _gate, _flags) \
189 struct ccu_mp _struct = { \
190 .enable = _gate, \
191 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
192 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
193 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
194 .common = { \
195 .reg = _reg, \
196 .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \
197 _parents, \
198 &ccu_mp_ops, \
199 _flags), \
200 } \
201 }
202
hw_to_ccu_mp(struct clk_hw * hw)203 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
204 {
205 struct ccu_common *common = hw_to_ccu_common(hw);
206
207 return container_of(common, struct ccu_mp, common);
208 }
209
210 extern const struct clk_ops ccu_mp_ops;
211
212 /*
213 * Special class of M-P clock that supports MMC timing modes
214 *
215 * Since the MMC clock registers all follow the same layout, we can
216 * simplify the macro for this particular case. In addition, as
217 * switching modes also affects the output clock rate, we need to
218 * have CLK_GET_RATE_NOCACHE for all these types of clocks.
219 */
220
221 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
222 _flags) \
223 struct ccu_mp _struct = { \
224 .enable = BIT(31), \
225 .m = _SUNXI_CCU_DIV(0, 4), \
226 .p = _SUNXI_CCU_DIV(16, 2), \
227 .mux = _SUNXI_CCU_MUX(24, 2), \
228 .common = { \
229 .reg = _reg, \
230 .features = CCU_FEATURE_MMC_TIMING_SWITCH, \
231 .hw.init = CLK_HW_INIT_PARENTS(_name, \
232 _parents, \
233 &ccu_mp_mmc_ops, \
234 CLK_GET_RATE_NOCACHE | \
235 _flags), \
236 } \
237 }
238
239 extern const struct clk_ops ccu_mp_mmc_ops;
240
241 #endif /* _CCU_MP_H_ */
242