1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _CCU_MUX_H_ |
3 | #define _CCU_MUX_H_ |
4 | |
5 | #include <linux/clk-provider.h> |
6 | |
7 | #include "ccu_common.h" |
8 | |
9 | struct ccu_mux_fixed_prediv { |
10 | u8 index; |
11 | u16 div; |
12 | }; |
13 | |
14 | struct ccu_mux_var_prediv { |
15 | u8 index; |
16 | u8 shift; |
17 | u8 width; |
18 | }; |
19 | |
20 | struct ccu_mux_internal { |
21 | u8 shift; |
22 | u8 width; |
23 | const u8 *table; |
24 | |
25 | const struct ccu_mux_fixed_prediv *fixed_predivs; |
26 | u8 n_predivs; |
27 | |
28 | const struct ccu_mux_var_prediv *var_predivs; |
29 | u8 n_var_predivs; |
30 | }; |
31 | |
32 | #define _SUNXI_CCU_MUX_TABLE(_shift, _width, _table) \ |
33 | { \ |
34 | .shift = _shift, \ |
35 | .width = _width, \ |
36 | .table = _table, \ |
37 | } |
38 | |
39 | #define _SUNXI_CCU_MUX(_shift, _width) \ |
40 | _SUNXI_CCU_MUX_TABLE(_shift, _width, NULL) |
41 | |
42 | struct ccu_mux { |
43 | u32 enable; |
44 | |
45 | struct ccu_mux_internal mux; |
46 | struct ccu_common common; |
47 | }; |
48 | |
49 | #define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, _table, \ |
50 | _reg, _shift, _width, _gate, \ |
51 | _flags, _features) \ |
52 | struct ccu_mux _struct = { \ |
53 | .enable = _gate, \ |
54 | .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \ |
55 | .common = { \ |
56 | .reg = _reg, \ |
57 | .hw.init = CLK_HW_INIT_PARENTS(_name, \ |
58 | _parents, \ |
59 | &ccu_mux_ops, \ |
60 | _flags), \ |
61 | .features = _features, \ |
62 | } \ |
63 | } |
64 | |
65 | #define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents, \ |
66 | _table, _reg, _shift, \ |
67 | _width, _gate, _flags) \ |
68 | SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \ |
69 | _table, _reg, _shift, \ |
70 | _width, _gate, _flags, \ |
71 | CCU_FEATURE_CLOSEST_RATE) |
72 | |
73 | #define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table, \ |
74 | _reg, _shift, _width, _gate, \ |
75 | _flags) \ |
76 | SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \ |
77 | _table, _reg, _shift, \ |
78 | _width, _gate, _flags, 0) |
79 | |
80 | #define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \ |
81 | _shift, _width, _gate, _flags) \ |
82 | SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL, \ |
83 | _reg, _shift, _width, _gate, \ |
84 | _flags) |
85 | |
86 | #define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width, \ |
87 | _flags) \ |
88 | SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL, \ |
89 | _reg, _shift, _width, 0, _flags) |
90 | |
91 | #define SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg, \ |
92 | _shift, _width, _gate, _flags) \ |
93 | struct ccu_mux _struct = { \ |
94 | .enable = _gate, \ |
95 | .mux = _SUNXI_CCU_MUX(_shift, _width), \ |
96 | .common = { \ |
97 | .reg = _reg, \ |
98 | .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ |
99 | _parents, \ |
100 | &ccu_mux_ops, \ |
101 | _flags), \ |
102 | } \ |
103 | } |
104 | |
105 | #define SUNXI_CCU_MUX_DATA(_struct, _name, _parents, _reg, \ |
106 | _shift, _width, _flags) \ |
107 | SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg, \ |
108 | _shift, _width, 0, _flags) |
109 | |
110 | #define SUNXI_CCU_MUX_HW_WITH_GATE(_struct, _name, _parents, _reg, \ |
111 | _shift, _width, _gate, _flags) \ |
112 | struct ccu_mux _struct = { \ |
113 | .enable = _gate, \ |
114 | .mux = _SUNXI_CCU_MUX(_shift, _width), \ |
115 | .common = { \ |
116 | .reg = _reg, \ |
117 | .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \ |
118 | _parents, \ |
119 | &ccu_mux_ops, \ |
120 | _flags), \ |
121 | } \ |
122 | } |
123 | |
124 | static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw) |
125 | { |
126 | struct ccu_common *common = hw_to_ccu_common(hw); |
127 | |
128 | return container_of(common, struct ccu_mux, common); |
129 | } |
130 | |
131 | extern const struct clk_ops ccu_mux_ops; |
132 | |
133 | unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common, |
134 | struct ccu_mux_internal *cm, |
135 | int parent_index, |
136 | unsigned long parent_rate); |
137 | int ccu_mux_helper_determine_rate(struct ccu_common *common, |
138 | struct ccu_mux_internal *cm, |
139 | struct clk_rate_request *req, |
140 | unsigned long (*round)(struct ccu_mux_internal *, |
141 | struct clk_hw *, |
142 | unsigned long *, |
143 | unsigned long, |
144 | void *), |
145 | void *data); |
146 | u8 ccu_mux_helper_get_parent(struct ccu_common *common, |
147 | struct ccu_mux_internal *cm); |
148 | int ccu_mux_helper_set_parent(struct ccu_common *common, |
149 | struct ccu_mux_internal *cm, |
150 | u8 index); |
151 | |
152 | struct ccu_mux_nb { |
153 | struct notifier_block clk_nb; |
154 | struct ccu_common *common; |
155 | struct ccu_mux_internal *cm; |
156 | |
157 | u32 delay_us; /* How many us to wait after reparenting */ |
158 | u8 bypass_index; /* Which parent to temporarily use */ |
159 | u8 original_index; /* This is set by the notifier callback */ |
160 | }; |
161 | |
162 | #define to_ccu_mux_nb(_nb) container_of(_nb, struct ccu_mux_nb, clk_nb) |
163 | |
164 | int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb); |
165 | |
166 | #endif /* _CCU_MUX_H_ */ |
167 | |