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_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
86 					_mshift, _mwidth,		\
87 					_pshift, _pwidth,		\
88 					_muxshift, _muxwidth,		\
89 					_gate, _flags)			\
90 	struct ccu_mp _struct = {					\
91 		.enable	= _gate,					\
92 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
93 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
94 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
95 		.common	= {						\
96 			.reg		= _reg,				\
97 			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
98 								   _parents, \
99 								   &ccu_mp_ops, \
100 								   _flags), \
101 		}							\
102 	}
103 
104 #define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg,	\
105 				   _mshift, _mwidth,			\
106 				   _pshift, _pwidth,			\
107 				   _muxshift, _muxwidth,		\
108 				   _flags)				\
109 	SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
110 					_mshift, _mwidth,		\
111 					_pshift, _pwidth,		\
112 					_muxshift, _muxwidth,		\
113 					0, _flags)
114 
115 #define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
116 				      _mshift, _mwidth,			\
117 				      _pshift, _pwidth,			\
118 				      _muxshift, _muxwidth,		\
119 				      _gate, _flags)			\
120 	struct ccu_mp _struct = {					\
121 		.enable	= _gate,					\
122 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
123 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
124 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
125 		.common	= {						\
126 			.reg		= _reg,				\
127 			.hw.init	= CLK_HW_INIT_PARENTS_HW(_name, \
128 								 _parents, \
129 								 &ccu_mp_ops, \
130 								 _flags), \
131 		}							\
132 	}
133 
hw_to_ccu_mp(struct clk_hw * hw)134 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
135 {
136 	struct ccu_common *common = hw_to_ccu_common(hw);
137 
138 	return container_of(common, struct ccu_mp, common);
139 }
140 
141 extern const struct clk_ops ccu_mp_ops;
142 
143 /*
144  * Special class of M-P clock that supports MMC timing modes
145  *
146  * Since the MMC clock registers all follow the same layout, we can
147  * simplify the macro for this particular case. In addition, as
148  * switching modes also affects the output clock rate, we need to
149  * have CLK_GET_RATE_NOCACHE for all these types of clocks.
150  */
151 
152 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
153 				       _flags)				\
154 	struct ccu_mp _struct = {					\
155 		.enable	= BIT(31),					\
156 		.m	= _SUNXI_CCU_DIV(0, 4),				\
157 		.p	= _SUNXI_CCU_DIV(16, 2),			\
158 		.mux	= _SUNXI_CCU_MUX(24, 2),			\
159 		.common	= {						\
160 			.reg		= _reg,				\
161 			.features	= CCU_FEATURE_MMC_TIMING_SWITCH, \
162 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
163 							      _parents, \
164 							      &ccu_mp_mmc_ops, \
165 							      CLK_GET_RATE_NOCACHE | \
166 							      _flags),	\
167 		}							\
168 	}
169 
170 extern const struct clk_ops ccu_mp_mmc_ops;
171 
172 #endif /* _CCU_MP_H_ */
173