1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#include "rsnd.h"
38
39#define MIX_NAME_SIZE 16
40#define MIX_NAME "mix"
41
42struct rsnd_mix {
43 struct rsnd_mod mod;
44 struct rsnd_kctrl_cfg_s volumeA;
45 struct rsnd_kctrl_cfg_s volumeB;
46 struct rsnd_kctrl_cfg_s volumeC;
47 struct rsnd_kctrl_cfg_s volumeD;
48 struct rsnd_kctrl_cfg_s ren;
49 struct rsnd_kctrl_cfg_s rup;
50 struct rsnd_kctrl_cfg_s rdw;
51 u32 flags;
52};
53
54#define ONCE_KCTRL_INITIALIZED (1 << 0)
55#define HAS_VOLA (1 << 1)
56#define HAS_VOLB (1 << 2)
57#define HAS_VOLC (1 << 3)
58#define HAS_VOLD (1 << 4)
59
60#define VOL_MAX 0x3ff
61
62#define rsnd_mod_to_mix(_mod) \
63 container_of((_mod), struct rsnd_mix, mod)
64
65#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
66#define rsnd_mix_nr(priv) ((priv)->mix_nr)
67#define for_each_rsnd_mix(pos, priv, i) \
68 for ((i) = 0; \
69 ((i) < rsnd_mix_nr(priv)) && \
70 ((pos) = (struct rsnd_mix *)(priv)->mix + i); \
71 i++)
72
73static void rsnd_mix_activation(struct rsnd_mod *mod)
74{
75 rsnd_mod_write(mod, MIX_SWRSR, 0);
76 rsnd_mod_write(mod, MIX_SWRSR, 1);
77}
78
79static void rsnd_mix_halt(struct rsnd_mod *mod)
80{
81 rsnd_mod_write(mod, MIX_MIXIR, 1);
82 rsnd_mod_write(mod, MIX_SWRSR, 0);
83}
84
85#define rsnd_mix_get_vol(mix, X) \
86 rsnd_flags_has(mix, HAS_VOL##X) ? \
87 (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
88static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
89 struct rsnd_mod *mod)
90{
91 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
92 struct device *dev = rsnd_priv_to_dev(priv);
93 struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
94 u32 volA = rsnd_mix_get_vol(mix, A);
95 u32 volB = rsnd_mix_get_vol(mix, B);
96 u32 volC = rsnd_mix_get_vol(mix, C);
97 u32 volD = rsnd_mix_get_vol(mix, D);
98
99 dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n",
100 volA, volB, volC, volD);
101
102 rsnd_mod_write(mod, MIX_MDBAR, volA);
103 rsnd_mod_write(mod, MIX_MDBBR, volB);
104 rsnd_mod_write(mod, MIX_MDBCR, volC);
105 rsnd_mod_write(mod, MIX_MDBDR, volD);
106}
107
108static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
109 struct rsnd_mod *mod)
110{
111 struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
112
113 rsnd_mod_write(mod, MIX_MIXIR, 1);
114
115
116 rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
117
118
119 rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren));
120 rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 |
121 rsnd_kctrl_vals(mix->rdw));
122
123
124 rsnd_mix_volume_parameter(io, mod);
125
126 rsnd_mod_write(mod, MIX_MIXIR, 0);
127}
128
129static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
130 struct rsnd_mod *mod)
131{
132
133 rsnd_mod_write(mod, MIX_MDBER, 0);
134
135
136 rsnd_mix_volume_parameter(io, mod);
137
138
139 rsnd_mod_write(mod, MIX_MDBER, 1);
140}
141
142static int rsnd_mix_probe_(struct rsnd_mod *mod,
143 struct rsnd_dai_stream *io,
144 struct rsnd_priv *priv)
145{
146 return rsnd_cmd_attach(io, rsnd_mod_id(mod));
147}
148
149static int rsnd_mix_init(struct rsnd_mod *mod,
150 struct rsnd_dai_stream *io,
151 struct rsnd_priv *priv)
152{
153 rsnd_mod_power_on(mod);
154
155 rsnd_mix_activation(mod);
156
157 rsnd_mix_volume_init(io, mod);
158
159 rsnd_mix_volume_update(io, mod);
160
161 return 0;
162}
163
164static int rsnd_mix_quit(struct rsnd_mod *mod,
165 struct rsnd_dai_stream *io,
166 struct rsnd_priv *priv)
167{
168 rsnd_mix_halt(mod);
169
170 rsnd_mod_power_off(mod);
171
172 return 0;
173}
174
175static int rsnd_mix_pcm_new(struct rsnd_mod *mod,
176 struct rsnd_dai_stream *io,
177 struct snd_soc_pcm_runtime *rtd)
178{
179 struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
180 struct device *dev = rsnd_priv_to_dev(priv);
181 struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
182 struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
183 struct rsnd_kctrl_cfg_s *volume;
184 int ret;
185
186 switch (rsnd_mod_id(src_mod)) {
187 case 3:
188 case 6:
189 volume = &mix->volumeA;
190 rsnd_flags_set(mix, HAS_VOLA);
191 break;
192 case 4:
193 case 9:
194 volume = &mix->volumeB;
195 rsnd_flags_set(mix, HAS_VOLB);
196 break;
197 case 0:
198 case 1:
199 volume = &mix->volumeC;
200 rsnd_flags_set(mix, HAS_VOLC);
201 break;
202 case 2:
203 case 5:
204 volume = &mix->volumeD;
205 rsnd_flags_set(mix, HAS_VOLD);
206 break;
207 default:
208 dev_err(dev, "unknown SRC is connected\n");
209 return -EINVAL;
210 }
211
212
213 ret = rsnd_kctrl_new_s(mod, io, rtd,
214 "MIX Playback Volume",
215 rsnd_kctrl_accept_anytime,
216 rsnd_mix_volume_update,
217 volume, VOL_MAX);
218 if (ret < 0)
219 return ret;
220 rsnd_kctrl_vals(*volume) = VOL_MAX;
221
222 if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
223 return ret;
224
225
226 ret = rsnd_kctrl_new_s(mod, io, rtd,
227 "MIX Ramp Switch",
228 rsnd_kctrl_accept_anytime,
229 rsnd_mix_volume_update,
230 &mix->ren, 1);
231 if (ret < 0)
232 return ret;
233
234 ret = rsnd_kctrl_new_e(mod, io, rtd,
235 "MIX Ramp Up Rate",
236 rsnd_kctrl_accept_anytime,
237 rsnd_mix_volume_update,
238 &mix->rup,
239 volume_ramp_rate,
240 VOLUME_RAMP_MAX_MIX);
241 if (ret < 0)
242 return ret;
243
244 ret = rsnd_kctrl_new_e(mod, io, rtd,
245 "MIX Ramp Down Rate",
246 rsnd_kctrl_accept_anytime,
247 rsnd_mix_volume_update,
248 &mix->rdw,
249 volume_ramp_rate,
250 VOLUME_RAMP_MAX_MIX);
251
252 rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED);
253
254 return ret;
255}
256
257static struct rsnd_mod_ops rsnd_mix_ops = {
258 .name = MIX_NAME,
259 .probe = rsnd_mix_probe_,
260 .init = rsnd_mix_init,
261 .quit = rsnd_mix_quit,
262 .pcm_new = rsnd_mix_pcm_new,
263};
264
265struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
266{
267 if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
268 id = 0;
269
270 return rsnd_mod_get(rsnd_mix_get(priv, id));
271}
272
273int rsnd_mix_probe(struct rsnd_priv *priv)
274{
275 struct device_node *node;
276 struct device_node *np;
277 struct device *dev = rsnd_priv_to_dev(priv);
278 struct rsnd_mix *mix;
279 struct clk *clk;
280 char name[MIX_NAME_SIZE];
281 int i, nr, ret;
282
283
284 if (rsnd_is_gen1(priv))
285 return 0;
286
287 node = rsnd_mix_of_node(priv);
288 if (!node)
289 return 0;
290
291 nr = of_get_child_count(node);
292 if (!nr) {
293 ret = -EINVAL;
294 goto rsnd_mix_probe_done;
295 }
296
297 mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
298 if (!mix) {
299 ret = -ENOMEM;
300 goto rsnd_mix_probe_done;
301 }
302
303 priv->mix_nr = nr;
304 priv->mix = mix;
305
306 i = 0;
307 ret = 0;
308 for_each_child_of_node(node, np) {
309 mix = rsnd_mix_get(priv, i);
310
311 snprintf(name, MIX_NAME_SIZE, "%s.%d",
312 MIX_NAME, i);
313
314 clk = devm_clk_get(dev, name);
315 if (IS_ERR(clk)) {
316 ret = PTR_ERR(clk);
317 of_node_put(np);
318 goto rsnd_mix_probe_done;
319 }
320
321 ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
322 clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
323 if (ret) {
324 of_node_put(np);
325 goto rsnd_mix_probe_done;
326 }
327
328 i++;
329 }
330
331rsnd_mix_probe_done:
332 of_node_put(node);
333
334 return ret;
335}
336
337void rsnd_mix_remove(struct rsnd_priv *priv)
338{
339 struct rsnd_mix *mix;
340 int i;
341
342 for_each_rsnd_mix(mix, priv, i) {
343 rsnd_mod_quit(rsnd_mod_get(mix));
344 }
345}
346