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_NO_INDEX(_struct, _name, _parents, _reg, \
35 _mshift, _mwidth, \
36 _pshift, _pwidth, \
37 _muxshift, _muxwidth, \
38 _gate, _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 .common = { \
45 .reg = _reg, \
46 .features = CCU_FEATURE_MP_NO_INDEX_MODE, \
47 .hw.init = CLK_HW_INIT_PARENTS(_name, \
48 _parents, \
49 &ccu_mp_ops, \
50 _flags), \
51 } \
52 }
53
54 #define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
55 _mshift, _mwidth, \
56 _pshift, _pwidth, \
57 _muxshift, _muxwidth, \
58 _gate, _postdiv, _flags) \
59 struct ccu_mp _struct = { \
60 .enable = _gate, \
61 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
62 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
63 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
64 .fixed_post_div = _postdiv, \
65 .common = { \
66 .reg = _reg, \
67 .features = CCU_FEATURE_FIXED_POSTDIV, \
68 .hw.init = CLK_HW_INIT_PARENTS(_name, \
69 _parents, \
70 &ccu_mp_ops, \
71 _flags), \
72 } \
73 }
74
75 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
76 _mshift, _mwidth, \
77 _pshift, _pwidth, \
78 _muxshift, _muxwidth, \
79 _gate, _flags) \
80 struct ccu_mp _struct = { \
81 .enable = _gate, \
82 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
83 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
84 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
85 .common = { \
86 .reg = _reg, \
87 .hw.init = CLK_HW_INIT_PARENTS(_name, \
88 _parents, \
89 &ccu_mp_ops, \
90 _flags), \
91 } \
92 }
93
94 #define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg, \
95 _mshift, _mwidth, \
96 _pshift, _pwidth, \
97 _muxshift, _muxwidth, \
98 _flags) \
99 SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
100 _mshift, _mwidth, \
101 _pshift, _pwidth, \
102 _muxshift, _muxwidth, \
103 0, _flags)
104
hw_to_ccu_mp(struct clk_hw * hw)105 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
106 {
107 struct ccu_common *common = hw_to_ccu_common(hw);
108
109 return container_of(common, struct ccu_mp, common);
110 }
111
112 extern const struct clk_ops ccu_mp_ops;
113
114 /*
115 * Special class of M-P clock that supports MMC timing modes
116 *
117 * Since the MMC clock registers all follow the same layout, we can
118 * simplify the macro for this particular case. In addition, as
119 * switching modes also affects the output clock rate, we need to
120 * have CLK_GET_RATE_NOCACHE for all these types of clocks.
121 */
122
123 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
124 _flags) \
125 struct ccu_mp _struct = { \
126 .enable = BIT(31), \
127 .m = _SUNXI_CCU_DIV(0, 4), \
128 .p = _SUNXI_CCU_DIV(16, 2), \
129 .mux = _SUNXI_CCU_MUX(24, 2), \
130 .common = { \
131 .reg = _reg, \
132 .features = CCU_FEATURE_MMC_TIMING_SWITCH, \
133 .hw.init = CLK_HW_INIT_PARENTS(_name, \
134 _parents, \
135 &ccu_mp_mmc_ops, \
136 CLK_GET_RATE_NOCACHE | \
137 _flags), \
138 } \
139 }
140
141 extern const struct clk_ops ccu_mp_mmc_ops;
142
143 #endif /* _CCU_MP_H_ */
144