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
hw_to_ccu_mp(struct clk_hw * hw)85 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
86 {
87 struct ccu_common *common = hw_to_ccu_common(hw);
88
89 return container_of(common, struct ccu_mp, common);
90 }
91
92 extern const struct clk_ops ccu_mp_ops;
93
94 /*
95 * Special class of M-P clock that supports MMC timing modes
96 *
97 * Since the MMC clock registers all follow the same layout, we can
98 * simplify the macro for this particular case. In addition, as
99 * switching modes also affects the output clock rate, we need to
100 * have CLK_GET_RATE_NOCACHE for all these types of clocks.
101 */
102
103 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
104 _flags) \
105 struct ccu_mp _struct = { \
106 .enable = BIT(31), \
107 .m = _SUNXI_CCU_DIV(0, 4), \
108 .p = _SUNXI_CCU_DIV(16, 2), \
109 .mux = _SUNXI_CCU_MUX(24, 2), \
110 .common = { \
111 .reg = _reg, \
112 .features = CCU_FEATURE_MMC_TIMING_SWITCH, \
113 .hw.init = CLK_HW_INIT_PARENTS(_name, \
114 _parents, \
115 &ccu_mp_mmc_ops, \
116 CLK_GET_RATE_NOCACHE | \
117 _flags), \
118 } \
119 }
120
121 extern const struct clk_ops ccu_mp_mmc_ops;
122
123 #endif /* _CCU_MP_H_ */
124