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 "ccu.h"
10 #include "ccu_common.h"
11 #include "ccu_div.h"
12 #include "ccu_mult.h"
13 #include "ccu_mux.h"
14
15 /*
16 * struct ccu_mp - Definition of an M-P clock
17 *
18 * Clocks based on the formula parent >> P / M
19 */
20 struct ccu_mp
21 {
22 u32 enable;
23
24 struct ccu_div_internal m;
25 struct ccu_div_internal p;
26 struct ccu_mux_internal mux;
27
28 unsigned int fixed_post_div;
29
30 struct ccu_common common;
31 };
32
33 #define SUNXI_CCU_MP_WITH_MUX_GATE_NO_INDEX(_struct, _name, _parents, _reg, \
34 _mshift, _mwidth, \
35 _pshift, _pwidth, \
36 _muxshift, _muxwidth, \
37 _gate, _flags) \
38 struct ccu_mp _struct = { \
39 .enable = _gate, \
40 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
41 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
42 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
43 .common = { \
44 .reg = _reg, \
45 .features = CCU_FEATURE_MP_NO_INDEX_MODE, \
46 .hw.init = CLK_HW_INIT_PARENTS(_name, \
47 _parents, \
48 &ccu_mp_ops, \
49 _flags), \
50 } \
51 }
52
53 #define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
54 _mshift, _mwidth, \
55 _pshift, _pwidth, \
56 _muxshift, _muxwidth, \
57 _gate, _postdiv, _flags) \
58 struct ccu_mp _struct = { \
59 .enable = _gate, \
60 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
61 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
62 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
63 .fixed_post_div = _postdiv, \
64 .common = { \
65 .reg = _reg, \
66 .features = CCU_FEATURE_FIXED_POSTDIV, \
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_GATE(_struct, _name, _parents, _reg, \
75 _mshift, _mwidth, \
76 _pshift, _pwidth, \
77 _muxshift, _muxwidth, \
78 _gate, _flags) \
79 struct ccu_mp _struct = { \
80 .enable = _gate, \
81 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
82 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
83 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
84 .common = { \
85 .reg = _reg, \
86 .hw.init = CLK_HW_INIT_PARENTS(_name, \
87 _parents, \
88 &ccu_mp_ops, \
89 _flags), \
90 } \
91 }
92
93 #define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg, \
94 _mshift, _mwidth, \
95 _pshift, _pwidth, \
96 _muxshift, _muxwidth, \
97 _flags) \
98 SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
99 _mshift, _mwidth, \
100 _pshift, _pwidth, \
101 _muxshift, _muxwidth, \
102 0, _flags)
103
hw_to_ccu_mp(struct clk_hw * hw)104 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
105 {
106 struct ccu_common *common = hw_to_ccu_common(hw);
107
108 return container_of(common, struct ccu_mp, common);
109 }
110
111 extern const struct clk_ops ccu_mp_ops;
112
113 /*
114 * Special class of M-P clock that supports MMC timing modes
115 *
116 * Since the MMC clock registers all follow the same layout, we can
117 * simplify the macro for this particular case. In addition, as
118 * switching modes also affects the output clock rate, we need to
119 * have CLK_GET_RATE_NOCACHE for all these types of clocks.
120 */
121
122 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
123 _flags) \
124 struct ccu_mp _struct = { \
125 .enable = BIT(31), \
126 .m = _SUNXI_CCU_DIV(0, 4), \
127 .p = _SUNXI_CCU_DIV(16, 2), \
128 .mux = _SUNXI_CCU_MUX(24, 2), \
129 .common = { \
130 .reg = _reg, \
131 .features = CCU_FEATURE_MMC_TIMING_SWITCH, \
132 .hw.init = CLK_HW_INIT_PARENTS(_name, \
133 _parents, \
134 &ccu_mp_mmc_ops, \
135 CLK_GET_RATE_NOCACHE | \
136 _flags), \
137 } \
138 }
139
140 extern const struct clk_ops ccu_mp_mmc_ops;
141
142 #endif /* _CCU_MP_H_ */
143