]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - sound/soc/sh/rcar/mix.c
Merge remote-tracking branches 'asoc/topic/ac97', 'asoc/topic/ac97-mfd', 'asoc/topic...
[mirror_ubuntu-focal-kernel.git] / sound / soc / sh / rcar / mix.c
CommitLineData
70fb1052
KM
1/*
2 * mix.c
3 *
4 * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
3e3c9ee1
KM
10
11/*
12 * CTUn MIXn
13 * +------+ +------+
14 * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| ->
15 * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| ->
16 * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| ->
17 * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| ->
18 * +------+ +------+
19 *
20 * ex)
21 * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>;
22 * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
23 *
24 * MIX Volume
25 * amixer set "MIX",0 100% // DAI0 Volume
26 * amixer set "MIX",1 100% // DAI1 Volume
27 *
28 * Volume Ramp
29 * amixer set "MIX Ramp Up Rate" "0.125 dB/1 step"
30 * amixer set "MIX Ramp Down Rate" "4 dB/1 step"
31 * amixer set "MIX Ramp" on
32 * aplay xxx.wav &
33 * amixer set "MIX",0 80% // DAI0 Volume Down
34 * amixer set "MIX",1 100% // DAI1 Volume Up
35 */
36
70fb1052
KM
37#include "rsnd.h"
38
39#define MIX_NAME_SIZE 16
40#define MIX_NAME "mix"
41
42struct rsnd_mix {
70fb1052 43 struct rsnd_mod mod;
3e3c9ee1
KM
44 struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */
45 struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */
46 struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */
47 struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */
48 struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
49 struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
50 struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */
51 u32 flags;
70fb1052
KM
52};
53
3e3c9ee1
KM
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
c7fe4be8 65#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id)
70fb1052
KM
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
4fe32521 73static void rsnd_mix_activation(struct rsnd_mod *mod)
70fb1052
KM
74{
75 rsnd_mod_write(mod, MIX_SWRSR, 0);
76 rsnd_mod_write(mod, MIX_SWRSR, 1);
77}
78
95e6b0dd
KM
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
3e3c9ee1
KM
85#define rsnd_mix_get_vol(mix, X) \
86 rsnd_flags_has(mix, HAS_VOL##X) ? \
3a9fa27b 87 (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0
13e0d17d
KM
88static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io,
89 struct rsnd_mod *mod)
70fb1052 90{
3e3c9ee1
KM
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);
13e0d17d
KM
106}
107
108static void rsnd_mix_volume_init(struct rsnd_dai_stream *io,
109 struct rsnd_mod *mod)
110{
3e3c9ee1
KM
111 struct rsnd_mix *mix = rsnd_mod_to_mix(mod);
112
13e0d17d
KM
113 rsnd_mod_write(mod, MIX_MIXIR, 1);
114
115 /* General Information */
eed76bb8 116 rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io));
13e0d17d
KM
117
118 /* volume step */
3a9fa27b
KM
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));
13e0d17d
KM
122
123 /* common volume parameter */
124 rsnd_mix_volume_parameter(io, mod);
125
126 rsnd_mod_write(mod, MIX_MIXIR, 0);
70fb1052
KM
127}
128
129static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
130 struct rsnd_mod *mod)
131{
70fb1052
KM
132 /* Disable MIX dB setting */
133 rsnd_mod_write(mod, MIX_MDBER, 0);
134
13e0d17d
KM
135 /* common volume parameter */
136 rsnd_mix_volume_parameter(io, mod);
70fb1052
KM
137
138 /* Enable MIX dB setting */
139 rsnd_mod_write(mod, MIX_MDBER, 1);
140}
141
1b2ca0ad
KM
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
70fb1052
KM
149static int rsnd_mix_init(struct rsnd_mod *mod,
150 struct rsnd_dai_stream *io,
151 struct rsnd_priv *priv)
152{
c9929345 153 rsnd_mod_power_on(mod);
70fb1052 154
4fe32521 155 rsnd_mix_activation(mod);
70fb1052 156
13e0d17d 157 rsnd_mix_volume_init(io, mod);
70fb1052
KM
158
159 rsnd_mix_volume_update(io, mod);
160
70fb1052
KM
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{
95e6b0dd
KM
168 rsnd_mix_halt(mod);
169
c9929345 170 rsnd_mod_power_off(mod);
70fb1052
KM
171
172 return 0;
173}
174
3e3c9ee1
KM
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: /* MDBAR */
189 volume = &mix->volumeA;
190 rsnd_flags_set(mix, HAS_VOLA);
191 break;
192 case 4:
193 case 9: /* MDBBR */
194 volume = &mix->volumeB;
195 rsnd_flags_set(mix, HAS_VOLB);
196 break;
197 case 0:
198 case 1: /* MDBCR */
199 volume = &mix->volumeC;
200 rsnd_flags_set(mix, HAS_VOLC);
201 break;
202 case 2:
203 case 5: /* MDBDR */
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 /* Volume */
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;
3a9fa27b 220 rsnd_kctrl_vals(*volume) = VOL_MAX;
3e3c9ee1
KM
221
222 if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED))
223 return ret;
224
225 /* Ramp */
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
70fb1052
KM
257static struct rsnd_mod_ops rsnd_mix_ops = {
258 .name = MIX_NAME,
1b2ca0ad 259 .probe = rsnd_mix_probe_,
70fb1052
KM
260 .init = rsnd_mix_init,
261 .quit = rsnd_mix_quit,
3e3c9ee1 262 .pcm_new = rsnd_mix_pcm_new,
70fb1052
KM
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
c7fe4be8 270 return rsnd_mod_get(rsnd_mix_get(priv, id));
70fb1052
KM
271}
272
2ea6b074 273int rsnd_mix_probe(struct rsnd_priv *priv)
70fb1052 274{
c7fe4be8
KM
275 struct device_node *node;
276 struct device_node *np;
70fb1052
KM
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 /* This driver doesn't support Gen1 at this point */
8a98b422
KM
284 if (rsnd_is_gen1(priv))
285 return 0;
70fb1052 286
c7fe4be8
KM
287 node = rsnd_mix_of_node(priv);
288 if (!node)
289 return 0; /* not used is not error */
70fb1052 290
c7fe4be8
KM
291 nr = of_get_child_count(node);
292 if (!nr) {
293 ret = -EINVAL;
294 goto rsnd_mix_probe_done;
295 }
70fb1052
KM
296
297 mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
c7fe4be8
KM
298 if (!mix) {
299 ret = -ENOMEM;
300 goto rsnd_mix_probe_done;
301 }
70fb1052
KM
302
303 priv->mix_nr = nr;
304 priv->mix = mix;
305
c7fe4be8 306 i = 0;
2b235a3d 307 ret = 0;
c7fe4be8
KM
308 for_each_child_of_node(node, np) {
309 mix = rsnd_mix_get(priv, i);
310
70fb1052
KM
311 snprintf(name, MIX_NAME_SIZE, "%s.%d",
312 MIX_NAME, i);
313
314 clk = devm_clk_get(dev, name);
c7fe4be8
KM
315 if (IS_ERR(clk)) {
316 ret = PTR_ERR(clk);
53ba2aa3 317 of_node_put(np);
c7fe4be8
KM
318 goto rsnd_mix_probe_done;
319 }
70fb1052 320
b76e218a 321 ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
5ba17b42 322 clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
53ba2aa3
JL
323 if (ret) {
324 of_node_put(np);
c7fe4be8 325 goto rsnd_mix_probe_done;
53ba2aa3 326 }
c7fe4be8
KM
327
328 i++;
70fb1052
KM
329 }
330
c7fe4be8
KM
331rsnd_mix_probe_done:
332 of_node_put(node);
333
334 return ret;
70fb1052
KM
335}
336
2ea6b074 337void rsnd_mix_remove(struct rsnd_priv *priv)
70fb1052
KM
338{
339 struct rsnd_mix *mix;
340 int i;
341
342 for_each_rsnd_mix(mix, priv, i) {
b76e218a 343 rsnd_mod_quit(rsnd_mod_get(mix));
70fb1052
KM
344 }
345}