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