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