1 /*
2 * Copyright (c) 2016 Maxime Ripard. All rights reserved.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14 #ifndef _CCU_MP_H_
15 #define _CCU_MP_H_
16
17 #include <linux/bitops.h>
18 #include <linux/clk-provider.h>
19
20 #include "ccu_common.h"
21 #include "ccu_div.h"
22 #include "ccu_mult.h"
23 #include "ccu_mux.h"
24
25 /*
26 * struct ccu_mp - Definition of an M-P clock
27 *
28 * Clocks based on the formula parent >> P / M
29 */
30 struct ccu_mp {
31 u32 enable;
32
33 struct ccu_div_internal m;
34 struct ccu_div_internal p;
35 struct ccu_mux_internal mux;
36
37 unsigned int fixed_post_div;
38
39 struct ccu_common common;
40 };
41
42 #define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
43 _mshift, _mwidth, \
44 _pshift, _pwidth, \
45 _muxshift, _muxwidth, \
46 _gate, _postdiv, _flags) \
47 struct ccu_mp _struct = { \
48 .enable = _gate, \
49 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
50 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
51 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
52 .fixed_post_div = _postdiv, \
53 .common = { \
54 .reg = _reg, \
55 .features = CCU_FEATURE_FIXED_POSTDIV, \
56 .hw.init = CLK_HW_INIT_PARENTS(_name, \
57 _parents, \
58 &ccu_mp_ops, \
59 _flags), \
60 } \
61 }
62
63 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
64 _mshift, _mwidth, \
65 _pshift, _pwidth, \
66 _muxshift, _muxwidth, \
67 _gate, _flags) \
68 struct ccu_mp _struct = { \
69 .enable = _gate, \
70 .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
71 .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
72 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
73 .common = { \
74 .reg = _reg, \
75 .hw.init = CLK_HW_INIT_PARENTS(_name, \
76 _parents, \
77 &ccu_mp_ops, \
78 _flags), \
79 } \
80 }
81
82 #define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg, \
83 _mshift, _mwidth, \
84 _pshift, _pwidth, \
85 _muxshift, _muxwidth, \
86 _flags) \
87 SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
88 _mshift, _mwidth, \
89 _pshift, _pwidth, \
90 _muxshift, _muxwidth, \
91 0, _flags)
92
hw_to_ccu_mp(struct clk_hw * hw)93 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
94 {
95 struct ccu_common *common = hw_to_ccu_common(hw);
96
97 return container_of(common, struct ccu_mp, common);
98 }
99
100 extern const struct clk_ops ccu_mp_ops;
101
102 /*
103 * Special class of M-P clock that supports MMC timing modes
104 *
105 * Since the MMC clock registers all follow the same layout, we can
106 * simplify the macro for this particular case. In addition, as
107 * switching modes also affects the output clock rate, we need to
108 * have CLK_GET_RATE_NOCACHE for all these types of clocks.
109 */
110
111 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
112 _flags) \
113 struct ccu_mp _struct = { \
114 .enable = BIT(31), \
115 .m = _SUNXI_CCU_DIV(0, 4), \
116 .p = _SUNXI_CCU_DIV(16, 2), \
117 .mux = _SUNXI_CCU_MUX(24, 2), \
118 .common = { \
119 .reg = _reg, \
120 .features = CCU_FEATURE_MMC_TIMING_SWITCH, \
121 .hw.init = CLK_HW_INIT_PARENTS(_name, \
122 _parents, \
123 &ccu_mp_mmc_ops, \
124 CLK_GET_RATE_NOCACHE | \
125 _flags), \
126 } \
127 }
128
129 extern const struct clk_ops ccu_mp_mmc_ops;
130
131 #endif /* _CCU_MP_H_ */
132