xref: /linux/drivers/clk/sunxi-ng/ccu_mp.h (revision 6315d93541f8a5f77c5ef5c4f25233e66d189603)
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_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
56 				   _mshift, _mwidth,			\
57 				   _pshift, _pwidth,			\
58 				   _muxshift, _muxwidth,		\
59 				   _gate, _flags)			\
60 	struct ccu_mp _struct = {					\
61 		.enable	= _gate,					\
62 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
63 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
64 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
65 		.common	= {						\
66 			.reg		= _reg,				\
67 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
68 							      _parents, \
69 							      &ccu_mp_ops, \
70 							      _flags),	\
71 		}							\
72 	}
73 
74 #define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg,		\
75 			      _mshift, _mwidth,				\
76 			      _pshift, _pwidth,				\
77 			      _muxshift, _muxwidth,			\
78 			      _flags)					\
79 	SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
80 				   _mshift, _mwidth,			\
81 				   _pshift, _pwidth,			\
82 				   _muxshift, _muxwidth,		\
83 				   0, _flags)
84 
85 #define SUNXI_CCU_MP_MUX_GATE_POSTDIV_DUALDIV(_struct, _name, _parents, _reg, \
86 					      _mshift, _mwidth,		\
87 					      _pshift, _pwidth,		\
88 					      _muxshift, _muxwidth,	\
89 					      _gate, _postdiv,		\
90 					      _flags)			\
91 	struct ccu_mp _struct = {					\
92 		.enable	= _gate,					\
93 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
94 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
95 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
96 		.fixed_post_div = _postdiv,				\
97 		.common	= {						\
98 			.reg		= _reg,				\
99 			.features	= CCU_FEATURE_FIXED_POSTDIV |	\
100 						CCU_FEATURE_DUAL_DIV,	\
101 			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
102 								   _parents, \
103 								   &ccu_mp_ops, \
104 								   _flags), \
105 		}							\
106 	}
107 
108 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents, _reg, \
109 					     _mshift, _mwidth,		\
110 					     _pshift, _pwidth,		\
111 					     _muxshift, _muxwidth,	\
112 					     _gate, _features,		\
113 					     _flags)			\
114 	struct ccu_mp _struct = {					\
115 		.enable	= _gate,					\
116 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
117 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
118 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
119 		.common	= {						\
120 			.reg		= _reg,				\
121 			.features	= _features,			\
122 			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
123 								   _parents, \
124 								   &ccu_mp_ops, \
125 								   _flags), \
126 		}							\
127 	}
128 
129 #define SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
130 					_mshift, _mwidth,		\
131 					_pshift, _pwidth,		\
132 					_muxshift, _muxwidth,		\
133 					_gate, _flags)			\
134 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents,	\
135 					     _reg, _mshift, _mwidth,	\
136 					     _pshift, _pwidth,		\
137 					     _muxshift, _muxwidth,	\
138 					     _gate, _flags, 0)
139 
140 #define SUNXI_CCU_DUALDIV_MUX_GATE(_struct, _name, _parents, _reg,	\
141 				   _mshift, _mwidth,			\
142 				   _pshift, _pwidth,			\
143 				   _muxshift, _muxwidth,		\
144 				   _gate, _flags)			\
145 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(_struct, _name, _parents,	\
146 					     _reg, _mshift, _mwidth,	\
147 					     _pshift, _pwidth,		\
148 					     _muxshift, _muxwidth,	\
149 					     _gate, _flags,		\
150 					     CCU_FEATURE_DUAL_DIV)
151 
152 #define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg,	\
153 				   _mshift, _mwidth,			\
154 				   _pshift, _pwidth,			\
155 				   _muxshift, _muxwidth,		\
156 				   _flags)				\
157 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
158 					_mshift, _mwidth,		\
159 					_pshift, _pwidth,		\
160 					_muxshift, _muxwidth,		\
161 					0, _flags)
162 
163 #define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
164 				      _mshift, _mwidth,			\
165 				      _pshift, _pwidth,			\
166 				      _muxshift, _muxwidth,		\
167 				      _gate, _flags)			\
168 	struct ccu_mp _struct = {					\
169 		.enable	= _gate,					\
170 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
171 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
172 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
173 		.common	= {						\
174 			.reg		= _reg,				\
175 			.hw.init	= CLK_HW_INIT_PARENTS_HW(_name, \
176 								 _parents, \
177 								 &ccu_mp_ops, \
178 								 _flags), \
179 		}							\
180 	}
181 
182 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
183 {
184 	struct ccu_common *common = hw_to_ccu_common(hw);
185 
186 	return container_of(common, struct ccu_mp, common);
187 }
188 
189 extern const struct clk_ops ccu_mp_ops;
190 
191 /*
192  * Special class of M-P clock that supports MMC timing modes
193  *
194  * Since the MMC clock registers all follow the same layout, we can
195  * simplify the macro for this particular case. In addition, as
196  * switching modes also affects the output clock rate, we need to
197  * have CLK_GET_RATE_NOCACHE for all these types of clocks.
198  */
199 
200 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
201 				       _flags)				\
202 	struct ccu_mp _struct = {					\
203 		.enable	= BIT(31),					\
204 		.m	= _SUNXI_CCU_DIV(0, 4),				\
205 		.p	= _SUNXI_CCU_DIV(16, 2),			\
206 		.mux	= _SUNXI_CCU_MUX(24, 2),			\
207 		.common	= {						\
208 			.reg		= _reg,				\
209 			.features	= CCU_FEATURE_MMC_TIMING_SWITCH, \
210 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
211 							      _parents, \
212 							      &ccu_mp_mmc_ops, \
213 							      CLK_GET_RATE_NOCACHE | \
214 							      _flags),	\
215 		}							\
216 	}
217 
218 extern const struct clk_ops ccu_mp_mmc_ops;
219 
220 #endif /* _CCU_MP_H_ */
221