xref: /linux/drivers/clk/spacemit/ccu_mix.h (revision e7e86d7697c6ed1dbbde18d7185c35b6967945ed)
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 
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_DIV_H_ */
224