1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Copyright (c) 2024 SpacemiT Technology Co. Ltd
4 * Copyright (c) 2024-2025 Haylen Chu <heylenay@4d2.org>
5 */
6
7 #ifndef _CCU_MIX_H_
8 #define _CCU_MIX_H_
9
10 #include <linux/clk-provider.h>
11
12 #include "ccu_common.h"
13
14 /**
15 * struct ccu_gate_config - Gate configuration
16 *
17 * @mask: Mask to enable the gate. Some clocks may have more than one bit
18 * set in this field.
19 */
20 struct ccu_gate_config {
21 u32 mask;
22 };
23
24 struct ccu_factor_config {
25 u32 div;
26 u32 mul;
27 };
28
29 struct ccu_mux_config {
30 u8 shift;
31 u8 width;
32 };
33
34 struct ccu_div_config {
35 u8 shift;
36 u8 width;
37 };
38
39 struct ccu_mix {
40 struct ccu_factor_config factor;
41 struct ccu_gate_config gate;
42 struct ccu_div_config div;
43 struct ccu_mux_config mux;
44 struct ccu_common common;
45 };
46
47 #define CCU_GATE_INIT(_mask) { .mask = _mask }
48 #define CCU_FACTOR_INIT(_div, _mul) { .div = _div, .mul = _mul }
49 #define CCU_MUX_INIT(_shift, _width) { .shift = _shift, .width = _width }
50 #define CCU_DIV_INIT(_shift, _width) { .shift = _shift, .width = _width }
51
52 #define CCU_PARENT_HW(_parent) { .hw = &_parent.common.hw }
53 #define CCU_PARENT_NAME(_name) { .fw_name = #_name }
54
55 #define CCU_MIX_INITHW(_name, _parent, _ops, _flags) \
56 .hw.init = &(struct clk_init_data) { \
57 .flags = _flags, \
58 .name = #_name, \
59 .parent_data = (const struct clk_parent_data[]) \
60 { _parent }, \
61 .num_parents = 1, \
62 .ops = &_ops, \
63 }
64
65 #define CCU_MIX_INITHW_PARENTS(_name, _parents, _ops, _flags) \
66 .hw.init = CLK_HW_INIT_PARENTS_DATA(#_name, _parents, &_ops, _flags)
67
68 #define CCU_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _flags) \
69 static struct ccu_mix _name = { \
70 .gate = CCU_GATE_INIT(_mask_gate), \
71 .common = { \
72 .reg_ctrl = _reg_ctrl, \
73 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_gate_ops, _flags), \
74 } \
75 }
76
77 #define CCU_FACTOR_DEFINE(_name, _parent, _div, _mul) \
78 static struct ccu_mix _name = { \
79 .factor = CCU_FACTOR_INIT(_div, _mul), \
80 .common = { \
81 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_ops, 0), \
82 } \
83 }
84
85 #define CCU_MUX_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, _flags) \
86 static struct ccu_mix _name = { \
87 .mux = CCU_MUX_INIT(_shift, _width), \
88 .common = { \
89 .reg_ctrl = _reg_ctrl, \
90 CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \
91 _flags), \
92 } \
93 }
94
95 #define CCU_DIV_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, _flags) \
96 static struct ccu_mix _name = { \
97 .div = CCU_DIV_INIT(_shift, _width), \
98 .common = { \
99 .reg_ctrl = _reg_ctrl, \
100 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_ops, _flags) \
101 } \
102 }
103
104 #define CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
105 _mul, _flags) \
106 static struct ccu_mix _name = { \
107 .gate = CCU_GATE_INIT(_mask_gate), \
108 .factor = CCU_FACTOR_INIT(_div, _mul), \
109 .common = { \
110 .reg_ctrl = _reg_ctrl, \
111 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, _flags) \
112 } \
113 }
114
115 #define CCU_FACTOR_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
116 _mul) \
117 CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
118 _mul, 0)
119
120 #define CCU_MUX_GATE_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, \
121 _mask_gate, _flags) \
122 static struct ccu_mix _name = { \
123 .gate = CCU_GATE_INIT(_mask_gate), \
124 .mux = CCU_MUX_INIT(_shift, _width), \
125 .common = { \
126 .reg_ctrl = _reg_ctrl, \
127 CCU_MIX_INITHW_PARENTS(_name, _parents, \
128 spacemit_ccu_mux_gate_ops, _flags), \
129 } \
130 }
131
132 #define CCU_DIV_GATE_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, \
133 _mask_gate, _flags) \
134 static struct ccu_mix _name = { \
135 .gate = CCU_GATE_INIT(_mask_gate), \
136 .div = CCU_DIV_INIT(_shift, _width), \
137 .common = { \
138 .reg_ctrl = _reg_ctrl, \
139 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_gate_ops, \
140 _flags), \
141 } \
142 }
143
144 #define CCU_MUX_DIV_GATE_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \
145 _muxshift, _muxwidth, _mask_gate, _flags) \
146 static struct ccu_mix _name = { \
147 .gate = CCU_GATE_INIT(_mask_gate), \
148 .div = CCU_DIV_INIT(_mshift, _mwidth), \
149 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
150 .common = { \
151 .reg_ctrl = _reg_ctrl, \
152 CCU_MIX_INITHW_PARENTS(_name, _parents, \
153 spacemit_ccu_mux_div_gate_ops, _flags), \
154 }, \
155 }
156
157 #define CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_fc, \
158 _mshift, _mwidth, _mask_fc, _muxshift, \
159 _muxwidth, _mask_gate, _flags) \
160 static struct ccu_mix _name = { \
161 .gate = CCU_GATE_INIT(_mask_gate), \
162 .div = CCU_DIV_INIT(_mshift, _mwidth), \
163 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
164 .common = { \
165 .reg_ctrl = _reg_ctrl, \
166 .reg_fc = _reg_fc, \
167 .mask_fc = _mask_fc, \
168 CCU_MIX_INITHW_PARENTS(_name, _parents, \
169 spacemit_ccu_mux_div_gate_ops, _flags), \
170 }, \
171 }
172
173 #define CCU_MUX_DIV_GATE_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth,\
174 _mask_fc, _muxshift, _muxwidth, _mask_gate, \
175 _flags) \
176 CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_ctrl, _mshift,\
177 _mwidth, _mask_fc, _muxshift, _muxwidth, \
178 _mask_gate, _flags)
179
180 #define CCU_MUX_DIV_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \
181 _mask_fc, _muxshift, _muxwidth, _flags) \
182 static struct ccu_mix _name = { \
183 .div = CCU_DIV_INIT(_mshift, _mwidth), \
184 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
185 .common = { \
186 .reg_ctrl = _reg_ctrl, \
187 .reg_fc = _reg_ctrl, \
188 .mask_fc = _mask_fc, \
189 CCU_MIX_INITHW_PARENTS(_name, _parents, \
190 spacemit_ccu_mux_div_ops, _flags), \
191 }, \
192 }
193
194 #define CCU_MUX_FC_DEFINE(_name, _parents, _reg_ctrl, _mask_fc, _muxshift, \
195 _muxwidth, _flags) \
196 static struct ccu_mix _name = { \
197 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
198 .common = { \
199 .reg_ctrl = _reg_ctrl, \
200 .reg_fc = _reg_ctrl, \
201 .mask_fc = _mask_fc, \
202 CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \
203 _flags) \
204 }, \
205 }
206
hw_to_ccu_mix(struct clk_hw * hw)207 static inline struct ccu_mix *hw_to_ccu_mix(struct clk_hw *hw)
208 {
209 struct ccu_common *common = hw_to_ccu_common(hw);
210
211 return container_of(common, struct ccu_mix, common);
212 }
213
214 extern const struct clk_ops spacemit_ccu_gate_ops;
215 extern const struct clk_ops spacemit_ccu_factor_ops;
216 extern const struct clk_ops spacemit_ccu_mux_ops;
217 extern const struct clk_ops spacemit_ccu_div_ops;
218 extern const struct clk_ops spacemit_ccu_factor_gate_ops;
219 extern const struct clk_ops spacemit_ccu_div_gate_ops;
220 extern const struct clk_ops spacemit_ccu_mux_gate_ops;
221 extern const struct clk_ops spacemit_ccu_mux_div_ops;
222 extern const struct clk_ops spacemit_ccu_mux_div_gate_ops;
223 #endif /* _CCU_MIX_H_ */
224