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 | |
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 | |