ASoC: qdsp6: q6routing: Add support to all SLIMBus Mixers
[platform/kernel/linux-rpi.git] / sound / soc / qcom / qdsp6 / q6routing.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
3 // Copyright (c) 2018, Linaro Limited
4
5 #include <linux/init.h>
6 #include <linux/err.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/of_platform.h>
10 #include <linux/bitops.h>
11 #include <linux/component.h>
12 #include <linux/mutex.h>
13 #include <linux/of_device.h>
14 #include <linux/slab.h>
15 #include <sound/core.h>
16 #include <sound/soc.h>
17 #include <sound/soc-dapm.h>
18 #include <sound/pcm.h>
19 #include <sound/control.h>
20 #include <sound/asound.h>
21 #include <sound/pcm_params.h>
22 #include "q6afe.h"
23 #include "q6asm.h"
24 #include "q6adm.h"
25 #include "q6routing.h"
26
27 #define DRV_NAME "q6routing-component"
28
29 struct session_data {
30         int state;
31         int port_id;
32         int path_type;
33         int app_type;
34         int acdb_id;
35         int sample_rate;
36         int bits_per_sample;
37         int channels;
38         int perf_mode;
39         int numcopps;
40         int fedai_id;
41         unsigned long copp_map;
42         struct q6copp *copps[MAX_COPPS_PER_PORT];
43 };
44
45 struct msm_routing_data {
46         struct session_data sessions[MAX_SESSIONS];
47         struct session_data port_data[AFE_MAX_PORTS];
48         struct device *dev;
49         struct mutex lock;
50 };
51
52 static struct msm_routing_data *routing_data;
53
54 /**
55  * q6routing_stream_open() - Register a new stream for route setup
56  *
57  * @fedai_id: Frontend dai id.
58  * @perf_mode: Performance mode.
59  * @stream_id: ASM stream id to map.
60  * @stream_type: Direction of stream
61  *
62  * Return: Will be an negative on error or a zero on success.
63  */
64 int q6routing_stream_open(int fedai_id, int perf_mode,
65                            int stream_id, int stream_type)
66 {
67         int j, topology, num_copps = 0;
68         struct route_payload payload;
69         struct q6copp *copp;
70         int copp_idx;
71         struct session_data *session, *pdata;
72
73         if (!routing_data) {
74                 pr_err("Routing driver not yet ready\n");
75                 return -EINVAL;
76         }
77
78         session = &routing_data->sessions[stream_id - 1];
79         pdata = &routing_data->port_data[session->port_id];
80
81         mutex_lock(&routing_data->lock);
82         session->fedai_id = fedai_id;
83
84         session->path_type = pdata->path_type;
85         session->sample_rate = pdata->sample_rate;
86         session->channels = pdata->channels;
87         session->bits_per_sample = pdata->bits_per_sample;
88
89         payload.num_copps = 0; /* only RX needs to use payload */
90         topology = NULL_COPP_TOPOLOGY;
91         copp = q6adm_open(routing_data->dev, session->port_id,
92                               session->path_type, session->sample_rate,
93                               session->channels, topology, perf_mode,
94                               session->bits_per_sample, 0, 0);
95
96         if (!copp) {
97                 mutex_unlock(&routing_data->lock);
98                 return -EINVAL;
99         }
100
101         copp_idx = q6adm_get_copp_id(copp);
102         set_bit(copp_idx, &session->copp_map);
103         session->copps[copp_idx] = copp;
104
105         for_each_set_bit(j, &session->copp_map, MAX_COPPS_PER_PORT) {
106                 payload.port_id[num_copps] = session->port_id;
107                 payload.copp_idx[num_copps] = j;
108                 num_copps++;
109         }
110
111         if (num_copps) {
112                 payload.num_copps = num_copps;
113                 payload.session_id = stream_id;
114                 q6adm_matrix_map(routing_data->dev, session->path_type,
115                                  payload, perf_mode);
116         }
117         mutex_unlock(&routing_data->lock);
118
119         return 0;
120 }
121 EXPORT_SYMBOL_GPL(q6routing_stream_open);
122
123 static struct session_data *get_session_from_id(struct msm_routing_data *data,
124                                                 int fedai_id)
125 {
126         int i;
127
128         for (i = 0; i < MAX_SESSIONS; i++) {
129                 if (fedai_id == data->sessions[i].fedai_id)
130                         return &data->sessions[i];
131         }
132
133         return NULL;
134 }
135 /**
136  * q6routing_stream_close() - Deregister a stream
137  *
138  * @fedai_id: Frontend dai id.
139  * @stream_type: Direction of stream
140  *
141  * Return: Will be an negative on error or a zero on success.
142  */
143 void q6routing_stream_close(int fedai_id, int stream_type)
144 {
145         struct session_data *session;
146         int idx;
147
148         session = get_session_from_id(routing_data, fedai_id);
149         if (!session)
150                 return;
151
152         for_each_set_bit(idx, &session->copp_map, MAX_COPPS_PER_PORT) {
153                 if (session->copps[idx]) {
154                         q6adm_close(routing_data->dev, session->copps[idx]);
155                         session->copps[idx] = NULL;
156                 }
157         }
158
159         session->fedai_id = -1;
160         session->copp_map = 0;
161 }
162 EXPORT_SYMBOL_GPL(q6routing_stream_close);
163
164 static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
165                                        struct snd_ctl_elem_value *ucontrol)
166 {
167         struct snd_soc_dapm_context *dapm =
168             snd_soc_dapm_kcontrol_dapm(kcontrol);
169         struct soc_mixer_control *mc =
170             (struct soc_mixer_control *)kcontrol->private_value;
171         int session_id = mc->shift;
172         struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
173         struct msm_routing_data *priv = dev_get_drvdata(c->dev);
174         struct session_data *session = &priv->sessions[session_id];
175
176         if (session->port_id == mc->reg)
177                 ucontrol->value.integer.value[0] = 1;
178         else
179                 ucontrol->value.integer.value[0] = 0;
180
181         return 0;
182 }
183
184 static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
185                                        struct snd_ctl_elem_value *ucontrol)
186 {
187         struct snd_soc_dapm_context *dapm =
188                                     snd_soc_dapm_kcontrol_dapm(kcontrol);
189         struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
190         struct msm_routing_data *data = dev_get_drvdata(c->dev);
191         struct soc_mixer_control *mc =
192                     (struct soc_mixer_control *)kcontrol->private_value;
193         struct snd_soc_dapm_update *update = NULL;
194         int be_id = mc->reg;
195         int session_id = mc->shift;
196         struct session_data *session = &data->sessions[session_id];
197
198         if (ucontrol->value.integer.value[0]) {
199                 session->port_id = be_id;
200                 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update);
201         } else {
202                 session->port_id = -1;
203                 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update);
204         }
205
206         return 1;
207 }
208
209 static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
210         SOC_SINGLE_EXT("MultiMedia1", HDMI_RX,
211                        MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0,
212                        msm_routing_get_audio_mixer,
213                        msm_routing_put_audio_mixer),
214         SOC_SINGLE_EXT("MultiMedia2", HDMI_RX,
215                        MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0,
216                        msm_routing_get_audio_mixer,
217                        msm_routing_put_audio_mixer),
218         SOC_SINGLE_EXT("MultiMedia3", HDMI_RX,
219                        MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0,
220                        msm_routing_get_audio_mixer,
221                        msm_routing_put_audio_mixer),
222         SOC_SINGLE_EXT("MultiMedia4", HDMI_RX,
223                        MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0,
224                        msm_routing_get_audio_mixer,
225                        msm_routing_put_audio_mixer),
226         SOC_SINGLE_EXT("MultiMedia5", HDMI_RX,
227                        MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0,
228                        msm_routing_get_audio_mixer,
229                        msm_routing_put_audio_mixer),
230         SOC_SINGLE_EXT("MultiMedia6", HDMI_RX,
231                        MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0,
232                        msm_routing_get_audio_mixer,
233                        msm_routing_put_audio_mixer),
234         SOC_SINGLE_EXT("MultiMedia7", HDMI_RX,
235                        MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0,
236                        msm_routing_get_audio_mixer,
237                        msm_routing_put_audio_mixer),
238         SOC_SINGLE_EXT("MultiMedia8", HDMI_RX,
239                        MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0,
240                        msm_routing_get_audio_mixer,
241                        msm_routing_put_audio_mixer),
242 };
243
244 static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
245         SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_0_RX,
246         MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
247         msm_routing_put_audio_mixer),
248         SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_0_RX,
249         MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
250         msm_routing_put_audio_mixer),
251         SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_0_RX,
252         MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
253         msm_routing_put_audio_mixer),
254         SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_0_RX,
255         MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
256         msm_routing_put_audio_mixer),
257         SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_0_RX,
258         MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
259         msm_routing_put_audio_mixer),
260         SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_0_RX,
261         MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
262         msm_routing_put_audio_mixer),
263         SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_0_RX,
264         MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
265         msm_routing_put_audio_mixer),
266         SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_0_RX,
267         MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
268         msm_routing_put_audio_mixer),
269 };
270
271 static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = {
272         SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_1_RX,
273         MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
274         msm_routing_put_audio_mixer),
275         SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_1_RX,
276         MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
277         msm_routing_put_audio_mixer),
278         SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_1_RX,
279         MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
280         msm_routing_put_audio_mixer),
281         SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_1_RX,
282         MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
283         msm_routing_put_audio_mixer),
284         SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_1_RX,
285         MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
286         msm_routing_put_audio_mixer),
287         SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_1_RX,
288         MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
289         msm_routing_put_audio_mixer),
290         SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_1_RX,
291         MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
292         msm_routing_put_audio_mixer),
293         SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_1_RX,
294         MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
295         msm_routing_put_audio_mixer),
296 };
297
298 static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = {
299         SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_2_RX,
300         MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
301         msm_routing_put_audio_mixer),
302         SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_2_RX,
303         MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
304         msm_routing_put_audio_mixer),
305         SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_2_RX,
306         MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
307         msm_routing_put_audio_mixer),
308         SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_2_RX,
309         MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
310         msm_routing_put_audio_mixer),
311         SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_2_RX,
312         MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
313         msm_routing_put_audio_mixer),
314         SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_2_RX,
315         MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
316         msm_routing_put_audio_mixer),
317         SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_2_RX,
318         MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
319         msm_routing_put_audio_mixer),
320         SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_2_RX,
321         MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
322         msm_routing_put_audio_mixer),
323 };
324
325 static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
326         SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_3_RX,
327         MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
328         msm_routing_put_audio_mixer),
329         SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_3_RX,
330         MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
331         msm_routing_put_audio_mixer),
332         SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_3_RX,
333         MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
334         msm_routing_put_audio_mixer),
335         SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_3_RX,
336         MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
337         msm_routing_put_audio_mixer),
338         SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_3_RX,
339         MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
340         msm_routing_put_audio_mixer),
341         SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_3_RX,
342         MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
343         msm_routing_put_audio_mixer),
344         SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_3_RX,
345         MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
346         msm_routing_put_audio_mixer),
347         SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_3_RX,
348         MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
349         msm_routing_put_audio_mixer),
350 };
351
352 static const struct snd_kcontrol_new slimbus_4_rx_mixer_controls[] = {
353         SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_4_RX,
354         MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
355         msm_routing_put_audio_mixer),
356         SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_4_RX,
357         MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
358         msm_routing_put_audio_mixer),
359         SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_4_RX,
360         MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
361         msm_routing_put_audio_mixer),
362 };
363
364 static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = {
365         SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_5_RX,
366         MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
367         msm_routing_put_audio_mixer),
368         SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_5_RX,
369         MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
370         msm_routing_put_audio_mixer),
371         SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_5_RX,
372         MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
373         msm_routing_put_audio_mixer),
374         SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_5_RX,
375         MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
376         msm_routing_put_audio_mixer),
377         SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_5_RX,
378         MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
379         msm_routing_put_audio_mixer),
380         SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_5_RX,
381         MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
382         msm_routing_put_audio_mixer),
383         SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_5_RX,
384         MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
385         msm_routing_put_audio_mixer),
386         SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_5_RX,
387         MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
388         msm_routing_put_audio_mixer),
389 };
390
391 static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = {
392         SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_6_RX,
393         MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
394         msm_routing_put_audio_mixer),
395         SOC_SINGLE_EXT("MultiMedia2", SLIMBUS_6_RX,
396         MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
397         msm_routing_put_audio_mixer),
398         SOC_SINGLE_EXT("MultiMedia3", SLIMBUS_6_RX,
399         MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
400         msm_routing_put_audio_mixer),
401         SOC_SINGLE_EXT("MultiMedia4", SLIMBUS_6_RX,
402         MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
403         msm_routing_put_audio_mixer),
404         SOC_SINGLE_EXT("MultiMedia5", SLIMBUS_6_RX,
405         MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
406         msm_routing_put_audio_mixer),
407         SOC_SINGLE_EXT("MultiMedia6", SLIMBUS_6_RX,
408         MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
409         msm_routing_put_audio_mixer),
410         SOC_SINGLE_EXT("MultiMedia7", SLIMBUS_6_RX,
411         MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
412         msm_routing_put_audio_mixer),
413         SOC_SINGLE_EXT("MultiMedia8", SLIMBUS_6_RX,
414         MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
415         msm_routing_put_audio_mixer),
416 };
417
418 static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
419         /* Frontend AIF */
420         SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
421         SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
422         SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
423         SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
424         SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
425         SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
426         SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
427         SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
428         SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
429         SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
430         SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0),
431         SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
432         SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
433         SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
434         SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, 0, 0, 0),
435         SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
436
437         /* Mixer definitions */
438         SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
439                            hdmi_mixer_controls,
440                            ARRAY_SIZE(hdmi_mixer_controls)),
441
442         SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
443                            slimbus_rx_mixer_controls,
444                            ARRAY_SIZE(slimbus_rx_mixer_controls)),
445         SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
446                            slimbus_1_rx_mixer_controls,
447                            ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
448         SND_SOC_DAPM_MIXER("SLIMBUS_2_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
449                            slimbus_2_rx_mixer_controls,
450                            ARRAY_SIZE(slimbus_2_rx_mixer_controls)),
451         SND_SOC_DAPM_MIXER("SLIMBUS_3_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
452                            slimbus_3_rx_mixer_controls,
453                            ARRAY_SIZE(slimbus_3_rx_mixer_controls)),
454         SND_SOC_DAPM_MIXER("SLIMBUS_4_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
455                            slimbus_4_rx_mixer_controls,
456                            ARRAY_SIZE(slimbus_4_rx_mixer_controls)),
457         SND_SOC_DAPM_MIXER("SLIMBUS_5_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
458                            slimbus_5_rx_mixer_controls,
459                             ARRAY_SIZE(slimbus_5_rx_mixer_controls)),
460         SND_SOC_DAPM_MIXER("SLIMBUS_6_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
461                            slimbus_6_rx_mixer_controls,
462                            ARRAY_SIZE(slimbus_6_rx_mixer_controls)),
463 };
464
465 static const struct snd_soc_dapm_route intercon[] = {
466         {"HDMI Mixer", "MultiMedia1", "MM_DL1"},
467         {"HDMI Mixer", "MultiMedia2", "MM_DL2"},
468         {"HDMI Mixer", "MultiMedia3", "MM_DL3"},
469         {"HDMI Mixer", "MultiMedia4", "MM_DL4"},
470         {"HDMI Mixer", "MultiMedia5", "MM_DL5"},
471         {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
472         {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
473         {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
474         {"HDMI_RX", NULL, "HDMI Mixer"},
475
476         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
477         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
478         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
479         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
480         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
481         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
482         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
483         {"SLIMBUS_0_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
484         {"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
485
486         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
487         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
488         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
489         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
490         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
491         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
492         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
493         {"SLIMBUS_1_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
494         {"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Audio Mixer"},
495
496         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
497         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
498         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
499         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
500         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
501         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
502         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
503         {"SLIMBUS_2_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
504         {"SLIMBUS_2_RX", NULL, "SLIMBUS_2_RX Audio Mixer"},
505
506         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
507         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
508         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
509         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
510         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
511         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
512         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
513         {"SLIMBUS_3_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
514         {"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Audio Mixer"},
515
516         {"SLIMBUS_4_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
517         {"SLIMBUS_4_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
518         {"SLIMBUS_4_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
519         {"SLIMBUS_4_RX", NULL, "SLIMBUS_4_RX Audio Mixer"},
520
521         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
522         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
523         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
524         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
525         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
526         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
527         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
528         {"SLIMBUS_5_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
529         {"SLIMBUS_5_RX", NULL, "SLIMBUS_5_RX Audio Mixer"},
530
531         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
532         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
533         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
534         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
535         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
536         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
537         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
538         {"SLIMBUS_6_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
539         {"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"},
540 };
541
542 static int routing_hw_params(struct snd_pcm_substream *substream,
543                                      struct snd_pcm_hw_params *params)
544 {
545         struct snd_soc_pcm_runtime *rtd = substream->private_data;
546         struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
547         struct msm_routing_data *data = dev_get_drvdata(c->dev);
548         unsigned int be_id = rtd->cpu_dai->id;
549         struct session_data *session;
550         int path_type;
551
552         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
553                 path_type = ADM_PATH_PLAYBACK;
554         else
555                 path_type = ADM_PATH_LIVE_REC;
556
557         if (be_id > AFE_MAX_PORTS)
558                 return -EINVAL;
559
560         session = &data->port_data[be_id];
561
562         mutex_lock(&data->lock);
563
564         session->path_type = path_type;
565         session->sample_rate = params_rate(params);
566         session->channels = params_channels(params);
567
568         switch (params_format(params)) {
569         case SNDRV_PCM_FORMAT_S16_LE:
570                         session->bits_per_sample = 16;
571                 break;
572         case SNDRV_PCM_FORMAT_S24_LE:
573                         session->bits_per_sample = 24;
574                 break;
575         default:
576                 break;
577         }
578
579         mutex_unlock(&data->lock);
580         return 0;
581 }
582
583 static struct snd_pcm_ops q6pcm_routing_ops = {
584         .hw_params = routing_hw_params,
585 };
586
587 static int msm_routing_probe(struct snd_soc_component *c)
588 {
589         int i;
590
591         for (i = 0; i < MAX_SESSIONS; i++)
592                 routing_data->sessions[i].port_id = -1;
593
594         return 0;
595 }
596
597 static const struct snd_soc_component_driver msm_soc_routing_component = {
598         .ops = &q6pcm_routing_ops,
599         .probe = msm_routing_probe,
600         .name = DRV_NAME,
601         .dapm_widgets = msm_qdsp6_widgets,
602         .num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets),
603         .dapm_routes = intercon,
604         .num_dapm_routes = ARRAY_SIZE(intercon),
605 };
606
607 static int q6routing_dai_bind(struct device *dev, struct device *master,
608                               void *data)
609 {
610         routing_data = kzalloc(sizeof(*routing_data), GFP_KERNEL);
611         if (!routing_data)
612                 return -ENOMEM;
613
614         routing_data->dev = dev;
615
616         mutex_init(&routing_data->lock);
617         dev_set_drvdata(dev, routing_data);
618
619         return snd_soc_register_component(dev, &msm_soc_routing_component,
620                                           NULL, 0);
621 }
622
623 static void q6routing_dai_unbind(struct device *dev, struct device *master,
624                                  void *d)
625 {
626         struct msm_routing_data *data = dev_get_drvdata(dev);
627
628         snd_soc_unregister_component(dev);
629
630         kfree(data);
631
632         routing_data = NULL;
633 }
634
635 static const struct component_ops q6routing_dai_comp_ops = {
636         .bind   = q6routing_dai_bind,
637         .unbind = q6routing_dai_unbind,
638 };
639
640 static int q6pcm_routing_probe(struct platform_device *pdev)
641 {
642         return component_add(&pdev->dev, &q6routing_dai_comp_ops);
643 }
644
645 static int q6pcm_routing_remove(struct platform_device *pdev)
646 {
647         component_del(&pdev->dev, &q6routing_dai_comp_ops);
648         return 0;
649 }
650
651 static struct platform_driver q6pcm_routing_platform_driver = {
652         .driver = {
653                 .name = "q6routing",
654         },
655         .probe = q6pcm_routing_probe,
656         .remove = q6pcm_routing_remove,
657 };
658 module_platform_driver(q6pcm_routing_platform_driver);
659
660 MODULE_DESCRIPTION("Q6 Routing platform");
661 MODULE_LICENSE("GPL v2");