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_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
105 _mul) \
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, 0) \
112 } \
113 }
114
115 #define CCU_MUX_GATE_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, \
116 _mask_gate, _flags) \
117 static struct ccu_mix _name = { \
118 .gate = CCU_GATE_INIT(_mask_gate), \
119 .mux = CCU_MUX_INIT(_shift, _width), \
120 .common = { \
121 .reg_ctrl = _reg_ctrl, \
122 CCU_MIX_INITHW_PARENTS(_name, _parents, \
123 spacemit_ccu_mux_gate_ops, _flags), \
124 } \
125 }
126
127 #define CCU_DIV_GATE_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, \
128 _mask_gate, _flags) \
129 static struct ccu_mix _name = { \
130 .gate = CCU_GATE_INIT(_mask_gate), \
131 .div = CCU_DIV_INIT(_shift, _width), \
132 .common = { \
133 .reg_ctrl = _reg_ctrl, \
134 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_gate_ops, \
135 _flags), \
136 } \
137 }
138
139 #define CCU_MUX_DIV_GATE_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \
140 _muxshift, _muxwidth, _mask_gate, _flags) \
141 static struct ccu_mix _name = { \
142 .gate = CCU_GATE_INIT(_mask_gate), \
143 .div = CCU_DIV_INIT(_mshift, _mwidth), \
144 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
145 .common = { \
146 .reg_ctrl = _reg_ctrl, \
147 CCU_MIX_INITHW_PARENTS(_name, _parents, \
148 spacemit_ccu_mux_div_gate_ops, _flags), \
149 }, \
150 }
151
152 #define CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_fc, \
153 _mshift, _mwidth, _mask_fc, _muxshift, \
154 _muxwidth, _mask_gate, _flags) \
155 static struct ccu_mix _name = { \
156 .gate = CCU_GATE_INIT(_mask_gate), \
157 .div = CCU_DIV_INIT(_mshift, _mwidth), \
158 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
159 .common = { \
160 .reg_ctrl = _reg_ctrl, \
161 .reg_fc = _reg_fc, \
162 .mask_fc = _mask_fc, \
163 CCU_MIX_INITHW_PARENTS(_name, _parents, \
164 spacemit_ccu_mux_div_gate_ops, _flags), \
165 }, \
166 }
167
168 #define CCU_MUX_DIV_GATE_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth,\
169 _mask_fc, _muxshift, _muxwidth, _mask_gate, \
170 _flags) \
171 CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_ctrl, _mshift,\
172 _mwidth, _mask_fc, _muxshift, _muxwidth, \
173 _mask_gate, _flags)
174
175 #define CCU_MUX_DIV_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \
176 _mask_fc, _muxshift, _muxwidth, _flags) \
177 static struct ccu_mix _name = { \
178 .div = CCU_DIV_INIT(_mshift, _mwidth), \
179 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
180 .common = { \
181 .reg_ctrl = _reg_ctrl, \
182 .reg_fc = _reg_ctrl, \
183 .mask_fc = _mask_fc, \
184 CCU_MIX_INITHW_PARENTS(_name, _parents, \
185 spacemit_ccu_mux_div_ops, _flags), \
186 }, \
187 }
188
189 #define CCU_MUX_FC_DEFINE(_name, _parents, _reg_ctrl, _mask_fc, _muxshift, \
190 _muxwidth, _flags) \
191 static struct ccu_mix _name = { \
192 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
193 .common = { \
194 .reg_ctrl = _reg_ctrl, \
195 .reg_fc = _reg_ctrl, \
196 .mask_fc = _mask_fc, \
197 CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \
198 _flags) \
199 }, \
200 }
201
hw_to_ccu_mix(struct clk_hw * hw)202 static inline struct ccu_mix *hw_to_ccu_mix(struct clk_hw *hw)
203 {
204 struct ccu_common *common = hw_to_ccu_common(hw);
205
206 return container_of(common, struct ccu_mix, common);
207 }
208
209 extern const struct clk_ops spacemit_ccu_gate_ops;
210 extern const struct clk_ops spacemit_ccu_factor_ops;
211 extern const struct clk_ops spacemit_ccu_mux_ops;
212 extern const struct clk_ops spacemit_ccu_div_ops;
213 extern const struct clk_ops spacemit_ccu_factor_gate_ops;
214 extern const struct clk_ops spacemit_ccu_div_gate_ops;
215 extern const struct clk_ops spacemit_ccu_mux_gate_ops;
216 extern const struct clk_ops spacemit_ccu_mux_div_ops;
217 extern const struct clk_ops spacemit_ccu_mux_div_gate_ops;
218 #endif /* _CCU_DIV_H_ */
219