xref: /openbmc/linux/drivers/clk/sunxi-ng/ccu_mp.h (revision 4d75f5c664195b970e1cd2fd25b65b5eff257a0a)
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_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
108 					_mshift, _mwidth,		\
109 					_pshift, _pwidth,		\
110 					_muxshift, _muxwidth,		\
111 					_gate, _flags)			\
112 	struct ccu_mp _struct = {					\
113 		.enable	= _gate,					\
114 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
115 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
116 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
117 		.common	= {						\
118 			.reg		= _reg,				\
119 			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
120 								   _parents, \
121 								   &ccu_mp_ops, \
122 								   _flags), \
123 		}							\
124 	}
125 
126 #define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg,	\
127 				   _mshift, _mwidth,			\
128 				   _pshift, _pwidth,			\
129 				   _muxshift, _muxwidth,		\
130 				   _flags)				\
131 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
132 					_mshift, _mwidth,		\
133 					_pshift, _pwidth,		\
134 					_muxshift, _muxwidth,		\
135 					0, _flags)
136 
137 #define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
138 				      _mshift, _mwidth,			\
139 				      _pshift, _pwidth,			\
140 				      _muxshift, _muxwidth,		\
141 				      _gate, _flags)			\
142 	struct ccu_mp _struct = {					\
143 		.enable	= _gate,					\
144 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
145 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
146 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
147 		.common	= {						\
148 			.reg		= _reg,				\
149 			.hw.init	= CLK_HW_INIT_PARENTS_HW(_name, \
150 								 _parents, \
151 								 &ccu_mp_ops, \
152 								 _flags), \
153 		}							\
154 	}
155 
hw_to_ccu_mp(struct clk_hw * hw)156 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
157 {
158 	struct ccu_common *common = hw_to_ccu_common(hw);
159 
160 	return container_of(common, struct ccu_mp, common);
161 }
162 
163 extern const struct clk_ops ccu_mp_ops;
164 
165 /*
166  * Special class of M-P clock that supports MMC timing modes
167  *
168  * Since the MMC clock registers all follow the same layout, we can
169  * simplify the macro for this particular case. In addition, as
170  * switching modes also affects the output clock rate, we need to
171  * have CLK_GET_RATE_NOCACHE for all these types of clocks.
172  */
173 
174 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
175 				       _flags)				\
176 	struct ccu_mp _struct = {					\
177 		.enable	= BIT(31),					\
178 		.m	= _SUNXI_CCU_DIV(0, 4),				\
179 		.p	= _SUNXI_CCU_DIV(16, 2),			\
180 		.mux	= _SUNXI_CCU_MUX(24, 2),			\
181 		.common	= {						\
182 			.reg		= _reg,				\
183 			.features	= CCU_FEATURE_MMC_TIMING_SWITCH, \
184 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
185 							      _parents, \
186 							      &ccu_mp_mmc_ops, \
187 							      CLK_GET_RATE_NOCACHE | \
188 							      _flags),	\
189 		}							\
190 	}
191 
192 extern const struct clk_ops ccu_mp_mmc_ops;
193 
194 #endif /* _CCU_MP_H_ */
195