xref: /linux/drivers/clk/sunxi-ng/ccu_mp.h (revision d608703fcdd9e9538f6c7a0fcf98bf79b1375b60)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (c) 2016 Maxime Ripard. All rights reserved.
4  */
5 
6 #ifndef _CCU_MP_H_
7 #define _CCU_MP_H_
8 
9 #include <linux/bitops.h>
10 #include <linux/clk-provider.h>
11 
12 #include "ccu_common.h"
13 #include "ccu_div.h"
14 #include "ccu_mult.h"
15 #include "ccu_mux.h"
16 
17 /*
18  * struct ccu_mp - Definition of an M-P clock
19  *
20  * Clocks based on the formula parent >> P / M
21  */
22 struct ccu_mp {
23 	u32			enable;
24 
25 	struct ccu_div_internal		m;
26 	struct ccu_div_internal		p;
27 	struct ccu_mux_internal	mux;
28 
29 	unsigned int		fixed_post_div;
30 
31 	struct ccu_common	common;
32 };
33 
34 #define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
35 					   _mshift, _mwidth,		\
36 					   _pshift, _pwidth,		\
37 					   _muxshift, _muxwidth,	\
38 					   _gate, _postdiv, _flags)	\
39 	struct ccu_mp _struct = {					\
40 		.enable	= _gate,					\
41 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
42 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
43 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
44 		.fixed_post_div	= _postdiv,				\
45 		.common	= {						\
46 			.reg		= _reg,				\
47 			.features	= CCU_FEATURE_FIXED_POSTDIV,	\
48 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
49 							      _parents, \
50 							      &ccu_mp_ops, \
51 							      _flags),	\
52 		}							\
53 	}
54 
55 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, \
56 						_reg,			\
57 						_mshift, _mwidth,	\
58 						_pshift, _pwidth,	\
59 						_muxshift, _muxwidth,	\
60 						_gate, _postdiv, _flags)\
61 	struct ccu_mp _struct = {					\
62 		.enable	= _gate,					\
63 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
64 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
65 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
66 		.fixed_post_div	= _postdiv,				\
67 		.common	= {						\
68 			.reg		= _reg,				\
69 			.features	= CCU_FEATURE_FIXED_POSTDIV,	\
70 			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
71 							_parents,	\
72 							&ccu_mp_ops,	\
73 							_flags),	\
74 		}							\
75 	}
76 
77 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
78 				   _mshift, _mwidth,			\
79 				   _pshift, _pwidth,			\
80 				   _muxshift, _muxwidth,		\
81 				   _gate, _flags)			\
82 	struct ccu_mp _struct = {					\
83 		.enable	= _gate,					\
84 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
85 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
86 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
87 		.common	= {						\
88 			.reg		= _reg,				\
89 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
90 							      _parents, \
91 							      &ccu_mp_ops, \
92 							      _flags),	\
93 		}							\
94 	}
95 
96 #define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg,		\
97 			      _mshift, _mwidth,				\
98 			      _pshift, _pwidth,				\
99 			      _muxshift, _muxwidth,			\
100 			      _flags)					\
101 	SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
102 				   _mshift, _mwidth,			\
103 				   _pshift, _pwidth,			\
104 				   _muxshift, _muxwidth,		\
105 				   0, _flags)
106 
107 #define SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(_struct, _name, _parents, _reg, \
108 					      _mshift, _mwidth,		\
109 					      _pshift, _pwidth,		\
110 					      _muxshift, _muxwidth,	\
111 					      _gate, _postdiv,		\
112 					      _flags)			\
113 	struct ccu_mp _struct = {					\
114 		.enable	= _gate,					\
115 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
116 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
117 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
118 		.fixed_post_div = _postdiv,				\
119 		.common	= {						\
120 			.reg		= _reg,				\
121 			.features	= CCU_FEATURE_FIXED_POSTDIV |	\
122 						CCU_FEATURE_DUAL_DIV,	\
123 			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
124 								   _parents, \
125 								   &ccu_mp_ops, \
126 								   _flags), \
127 		}							\
128 	}
129 
130 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents, _reg, \
131 					     _mshift, _mwidth,		\
132 					     _pshift, _pwidth,		\
133 					     _muxshift, _muxwidth,	\
134 					     _gate, _flags, _features)	\
135 	struct ccu_mp _struct = {					\
136 		.enable	= _gate,					\
137 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
138 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
139 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
140 		.common	= {						\
141 			.reg		= _reg,				\
142 			.features	= _features,			\
143 			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
144 								   _parents, \
145 								   &ccu_mp_ops, \
146 								   _flags), \
147 		}							\
148 	}
149 
150 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
151 					_mshift, _mwidth,		\
152 					_pshift, _pwidth,		\
153 					_muxshift, _muxwidth,		\
154 					_gate, _flags)			\
155 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents,	\
156 					     _reg, _mshift, _mwidth,	\
157 					     _pshift, _pwidth,		\
158 					     _muxshift, _muxwidth,	\
159 					     _gate, _flags, 0)
160 
161 #define SUNXI_CCU_DUALDIV_MUX_GATE(_struct, _name, _parents, _reg,	\
162 				   _mshift, _mwidth,			\
163 				   _pshift, _pwidth,			\
164 				   _muxshift, _muxwidth,		\
165 				   _gate, _flags)			\
166 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents,	\
167 					     _reg, _mshift, _mwidth,	\
168 					     _pshift, _pwidth,		\
169 					     _muxshift, _muxwidth,	\
170 					     _gate, _flags,		\
171 					     CCU_FEATURE_DUAL_DIV)
172 
173 #define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg,	\
174 				   _mshift, _mwidth,			\
175 				   _pshift, _pwidth,			\
176 				   _muxshift, _muxwidth,		\
177 				   _flags)				\
178 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
179 					_mshift, _mwidth,		\
180 					_pshift, _pwidth,		\
181 					_muxshift, _muxwidth,		\
182 					0, _flags)
183 
184 #define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
185 				      _mshift, _mwidth,			\
186 				      _pshift, _pwidth,			\
187 				      _muxshift, _muxwidth,		\
188 				      _gate, _flags)			\
189 	struct ccu_mp _struct = {					\
190 		.enable	= _gate,					\
191 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
192 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
193 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
194 		.common	= {						\
195 			.reg		= _reg,				\
196 			.hw.init	= CLK_HW_INIT_PARENTS_HW(_name, \
197 								 _parents, \
198 								 &ccu_mp_ops, \
199 								 _flags), \
200 		}							\
201 	}
202 
hw_to_ccu_mp(struct clk_hw * hw)203 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
204 {
205 	struct ccu_common *common = hw_to_ccu_common(hw);
206 
207 	return container_of(common, struct ccu_mp, common);
208 }
209 
210 extern const struct clk_ops ccu_mp_ops;
211 
212 /*
213  * Special class of M-P clock that supports MMC timing modes
214  *
215  * Since the MMC clock registers all follow the same layout, we can
216  * simplify the macro for this particular case. In addition, as
217  * switching modes also affects the output clock rate, we need to
218  * have CLK_GET_RATE_NOCACHE for all these types of clocks.
219  */
220 
221 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
222 				       _flags)				\
223 	struct ccu_mp _struct = {					\
224 		.enable	= BIT(31),					\
225 		.m	= _SUNXI_CCU_DIV(0, 4),				\
226 		.p	= _SUNXI_CCU_DIV(16, 2),			\
227 		.mux	= _SUNXI_CCU_MUX(24, 2),			\
228 		.common	= {						\
229 			.reg		= _reg,				\
230 			.features	= CCU_FEATURE_MMC_TIMING_SWITCH, \
231 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
232 							      _parents, \
233 							      &ccu_mp_mmc_ops, \
234 							      CLK_GET_RATE_NOCACHE | \
235 							      _flags),	\
236 		}							\
237 	}
238 
239 extern const struct clk_ops ccu_mp_mmc_ops;
240 
241 #endif /* _CCU_MP_H_ */
242