1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * Copyright (c) 2016 Maxime Ripard. All rights reserved. |
4 | */ |
5 | |
6 | #ifndef _CCU_DIV_H_ |
7 | #define _CCU_DIV_H_ |
8 | |
9 | #include <linux/clk-provider.h> |
10 | |
11 | #include "ccu_common.h" |
12 | #include "ccu_mux.h" |
13 | |
14 | /** |
15 | * struct ccu_div_internal - Internal divider description |
16 | * @shift: Bit offset of the divider in its register |
17 | * @width: Width of the divider field in its register |
18 | * @max: Maximum value allowed for that divider. This is the |
19 | * arithmetic value, not the maximum value to be set in the |
20 | * register. |
21 | * @flags: clk_divider flags to apply on this divider |
22 | * @table: Divider table pointer (if applicable) |
23 | * |
24 | * That structure represents a single divider, and is meant to be |
25 | * embedded in other structures representing the various clock |
26 | * classes. |
27 | * |
28 | * It is basically a wrapper around the clk_divider functions |
29 | * arguments. |
30 | */ |
31 | struct ccu_div_internal { |
32 | u8 shift; |
33 | u8 width; |
34 | |
35 | u32 max; |
36 | u32 offset; |
37 | |
38 | u32 flags; |
39 | |
40 | struct clk_div_table *table; |
41 | }; |
42 | |
43 | #define _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, _flags) \ |
44 | { \ |
45 | .shift = _shift, \ |
46 | .width = _width, \ |
47 | .flags = _flags, \ |
48 | .table = _table, \ |
49 | } |
50 | |
51 | #define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \ |
52 | _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0) |
53 | |
54 | #define _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _off, _max, _flags) \ |
55 | { \ |
56 | .shift = _shift, \ |
57 | .width = _width, \ |
58 | .flags = _flags, \ |
59 | .max = _max, \ |
60 | .offset = _off, \ |
61 | } |
62 | |
63 | #define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \ |
64 | _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, 1, _max, _flags) |
65 | |
66 | #define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \ |
67 | _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, 0, _flags) |
68 | |
69 | #define _SUNXI_CCU_DIV_MAX(_shift, _width, _max) \ |
70 | _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, 0) |
71 | |
72 | #define _SUNXI_CCU_DIV_OFFSET(_shift, _width, _offset) \ |
73 | _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _offset, 0, 0) |
74 | |
75 | #define _SUNXI_CCU_DIV(_shift, _width) \ |
76 | _SUNXI_CCU_DIV_FLAGS(_shift, _width, 0) |
77 | |
78 | struct ccu_div { |
79 | u32 enable; |
80 | |
81 | struct ccu_div_internal div; |
82 | struct ccu_mux_internal mux; |
83 | struct ccu_common common; |
84 | unsigned int fixed_post_div; |
85 | }; |
86 | |
87 | #define SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \ |
88 | _shift, _width, \ |
89 | _table, _gate, _flags) \ |
90 | struct ccu_div _struct = { \ |
91 | .div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \ |
92 | _table), \ |
93 | .enable = _gate, \ |
94 | .common = { \ |
95 | .reg = _reg, \ |
96 | .hw.init = CLK_HW_INIT(_name, \ |
97 | _parent, \ |
98 | &ccu_div_ops, \ |
99 | _flags), \ |
100 | } \ |
101 | } |
102 | |
103 | |
104 | #define SUNXI_CCU_DIV_TABLE(_struct, _name, _parent, _reg, \ |
105 | _shift, _width, \ |
106 | _table, _flags) \ |
107 | SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \ |
108 | _shift, _width, _table, 0, \ |
109 | _flags) |
110 | |
111 | #define SUNXI_CCU_DIV_TABLE_HW(_struct, _name, _parent, _reg, \ |
112 | _shift, _width, \ |
113 | _table, _flags) \ |
114 | struct ccu_div _struct = { \ |
115 | .div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \ |
116 | _table), \ |
117 | .common = { \ |
118 | .reg = _reg, \ |
119 | .hw.init = CLK_HW_INIT_HW(_name, \ |
120 | _parent, \ |
121 | &ccu_div_ops, \ |
122 | _flags), \ |
123 | } \ |
124 | } |
125 | |
126 | |
127 | #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ |
128 | _parents, _table, \ |
129 | _reg, \ |
130 | _mshift, _mwidth, \ |
131 | _muxshift, _muxwidth, \ |
132 | _gate, _flags) \ |
133 | struct ccu_div _struct = { \ |
134 | .enable = _gate, \ |
135 | .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ |
136 | .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ |
137 | .common = { \ |
138 | .reg = _reg, \ |
139 | .hw.init = CLK_HW_INIT_PARENTS(_name, \ |
140 | _parents, \ |
141 | &ccu_div_ops, \ |
142 | _flags), \ |
143 | }, \ |
144 | } |
145 | |
146 | #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \ |
147 | _parents, _table, \ |
148 | _reg, \ |
149 | _mshift, _mwidth, \ |
150 | _muxshift, _muxwidth, \ |
151 | _gate, _flags) \ |
152 | struct ccu_div _struct = { \ |
153 | .enable = _gate, \ |
154 | .div = _SUNXI_CCU_DIV_FLAGS(_mshift, _mwidth, CLK_DIVIDER_ROUND_CLOSEST), \ |
155 | .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ |
156 | .common = { \ |
157 | .reg = _reg, \ |
158 | .hw.init = CLK_HW_INIT_PARENTS(_name, \ |
159 | _parents, \ |
160 | &ccu_div_ops, \ |
161 | _flags), \ |
162 | .features = CCU_FEATURE_CLOSEST_RATE, \ |
163 | }, \ |
164 | } |
165 | |
166 | #define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ |
167 | _mshift, _mwidth, _muxshift, _muxwidth, \ |
168 | _gate, _flags) \ |
169 | SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ |
170 | _parents, NULL, \ |
171 | _reg, _mshift, _mwidth, \ |
172 | _muxshift, _muxwidth, \ |
173 | _gate, _flags) |
174 | |
175 | #define SUNXI_CCU_M_WITH_MUX_GATE_CLOSEST(_struct, _name, _parents, \ |
176 | _reg, _mshift, _mwidth, \ |
177 | _muxshift, _muxwidth, \ |
178 | _gate, _flags) \ |
179 | SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \ |
180 | _parents, NULL, \ |
181 | _reg, _mshift, _mwidth, \ |
182 | _muxshift, _muxwidth, \ |
183 | _gate, _flags) |
184 | |
185 | #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \ |
186 | _mshift, _mwidth, _muxshift, _muxwidth, \ |
187 | _flags) \ |
188 | SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ |
189 | _parents, NULL, \ |
190 | _reg, _mshift, _mwidth, \ |
191 | _muxshift, _muxwidth, \ |
192 | 0, _flags) |
193 | |
194 | |
195 | #define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ |
196 | _mshift, _mwidth, _gate, \ |
197 | _flags) \ |
198 | struct ccu_div _struct = { \ |
199 | .enable = _gate, \ |
200 | .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ |
201 | .common = { \ |
202 | .reg = _reg, \ |
203 | .hw.init = CLK_HW_INIT(_name, \ |
204 | _parent, \ |
205 | &ccu_div_ops, \ |
206 | _flags), \ |
207 | }, \ |
208 | } |
209 | |
210 | #define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth, \ |
211 | _flags) \ |
212 | SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ |
213 | _mshift, _mwidth, 0, _flags) |
214 | |
215 | #define SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ |
216 | _mshift, _mwidth, \ |
217 | _muxshift, _muxwidth, \ |
218 | _gate, _flags) \ |
219 | struct ccu_div _struct = { \ |
220 | .enable = _gate, \ |
221 | .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ |
222 | .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ |
223 | .common = { \ |
224 | .reg = _reg, \ |
225 | .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ |
226 | _parents, \ |
227 | &ccu_div_ops, \ |
228 | _flags), \ |
229 | }, \ |
230 | } |
231 | |
232 | #define SUNXI_CCU_M_DATA_WITH_MUX(_struct, _name, _parents, _reg, \ |
233 | _mshift, _mwidth, \ |
234 | _muxshift, _muxwidth, \ |
235 | _flags) \ |
236 | SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ |
237 | _mshift, _mwidth, \ |
238 | _muxshift, _muxwidth, \ |
239 | 0, _flags) |
240 | |
241 | #define SUNXI_CCU_M_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ |
242 | _mshift, _mwidth, _muxshift, _muxwidth, \ |
243 | _gate, _flags) \ |
244 | struct ccu_div _struct = { \ |
245 | .enable = _gate, \ |
246 | .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ |
247 | .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ |
248 | .common = { \ |
249 | .reg = _reg, \ |
250 | .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \ |
251 | _parents, \ |
252 | &ccu_div_ops, \ |
253 | _flags), \ |
254 | }, \ |
255 | } |
256 | |
257 | #define SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ |
258 | _mshift, _mwidth, _gate, \ |
259 | _flags) \ |
260 | struct ccu_div _struct = { \ |
261 | .enable = _gate, \ |
262 | .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ |
263 | .common = { \ |
264 | .reg = _reg, \ |
265 | .hw.init = CLK_HW_INIT_HWS(_name, \ |
266 | _parent, \ |
267 | &ccu_div_ops, \ |
268 | _flags), \ |
269 | }, \ |
270 | } |
271 | |
272 | #define SUNXI_CCU_M_HWS(_struct, _name, _parent, _reg, _mshift, \ |
273 | _mwidth, _flags) \ |
274 | SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ |
275 | _mshift, _mwidth, 0, _flags) |
276 | |
277 | static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) |
278 | { |
279 | struct ccu_common *common = hw_to_ccu_common(hw); |
280 | |
281 | return container_of(common, struct ccu_div, common); |
282 | } |
283 | |
284 | extern const struct clk_ops ccu_div_ops; |
285 | |
286 | #endif /* _CCU_DIV_H_ */ |
287 | |