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