1d7a4088a435a2c3eb31abcbb64ddceb019b11b7
[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_soc_dapm_widget msm_qdsp6_widgets[] = {
245         /* Frontend AIF */
246         SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
247         SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
248         SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
249         SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
250         SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
251         SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
252         SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
253         SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
254         SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
255         SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
256         SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0),
257         SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
258         SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0),
259         SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
260         SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, 0, 0, 0),
261         SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
262
263         /* Mixer definitions */
264         SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
265                            hdmi_mixer_controls,
266                            ARRAY_SIZE(hdmi_mixer_controls)),
267 };
268
269 static const struct snd_soc_dapm_route intercon[] = {
270         {"HDMI Mixer", "MultiMedia1", "MM_DL1"},
271         {"HDMI Mixer", "MultiMedia2", "MM_DL2"},
272         {"HDMI Mixer", "MultiMedia3", "MM_DL3"},
273         {"HDMI Mixer", "MultiMedia4", "MM_DL4"},
274         {"HDMI Mixer", "MultiMedia5", "MM_DL5"},
275         {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
276         {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
277         {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
278         {"HDMI_RX", NULL, "HDMI Mixer"},
279 };
280
281 static int routing_hw_params(struct snd_pcm_substream *substream,
282                                      struct snd_pcm_hw_params *params)
283 {
284         struct snd_soc_pcm_runtime *rtd = substream->private_data;
285         struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
286         struct msm_routing_data *data = dev_get_drvdata(c->dev);
287         unsigned int be_id = rtd->cpu_dai->id;
288         struct session_data *session;
289         int path_type;
290
291         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
292                 path_type = ADM_PATH_PLAYBACK;
293         else
294                 path_type = ADM_PATH_LIVE_REC;
295
296         if (be_id > AFE_MAX_PORTS)
297                 return -EINVAL;
298
299         session = &data->port_data[be_id];
300
301         mutex_lock(&data->lock);
302
303         session->path_type = path_type;
304         session->sample_rate = params_rate(params);
305         session->channels = params_channels(params);
306
307         switch (params_format(params)) {
308         case SNDRV_PCM_FORMAT_S16_LE:
309                         session->bits_per_sample = 16;
310                 break;
311         case SNDRV_PCM_FORMAT_S24_LE:
312                         session->bits_per_sample = 24;
313                 break;
314         default:
315                 break;
316         }
317
318         mutex_unlock(&data->lock);
319         return 0;
320 }
321
322 static struct snd_pcm_ops q6pcm_routing_ops = {
323         .hw_params = routing_hw_params,
324 };
325
326 static int msm_routing_probe(struct snd_soc_component *c)
327 {
328         int i;
329
330         for (i = 0; i < MAX_SESSIONS; i++)
331                 routing_data->sessions[i].port_id = -1;
332
333         return 0;
334 }
335
336 static const struct snd_soc_component_driver msm_soc_routing_component = {
337         .ops = &q6pcm_routing_ops,
338         .probe = msm_routing_probe,
339         .name = DRV_NAME,
340         .dapm_widgets = msm_qdsp6_widgets,
341         .num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets),
342         .dapm_routes = intercon,
343         .num_dapm_routes = ARRAY_SIZE(intercon),
344 };
345
346 static int q6routing_dai_bind(struct device *dev, struct device *master,
347                               void *data)
348 {
349         routing_data = kzalloc(sizeof(*routing_data), GFP_KERNEL);
350         if (!routing_data)
351                 return -ENOMEM;
352
353         routing_data->dev = dev;
354
355         mutex_init(&routing_data->lock);
356         dev_set_drvdata(dev, routing_data);
357
358         return snd_soc_register_component(dev, &msm_soc_routing_component,
359                                           NULL, 0);
360 }
361
362 static void q6routing_dai_unbind(struct device *dev, struct device *master,
363                                  void *d)
364 {
365         struct msm_routing_data *data = dev_get_drvdata(dev);
366
367         snd_soc_unregister_component(dev);
368
369         kfree(data);
370
371         routing_data = NULL;
372 }
373
374 static const struct component_ops q6routing_dai_comp_ops = {
375         .bind   = q6routing_dai_bind,
376         .unbind = q6routing_dai_unbind,
377 };
378
379 static int q6pcm_routing_probe(struct platform_device *pdev)
380 {
381         return component_add(&pdev->dev, &q6routing_dai_comp_ops);
382 }
383
384 static int q6pcm_routing_remove(struct platform_device *pdev)
385 {
386         component_del(&pdev->dev, &q6routing_dai_comp_ops);
387         return 0;
388 }
389
390 static struct platform_driver q6pcm_routing_platform_driver = {
391         .driver = {
392                 .name = "q6routing",
393         },
394         .probe = q6pcm_routing_probe,
395         .remove = q6pcm_routing_remove,
396 };
397 module_platform_driver(q6pcm_routing_platform_driver);
398
399 MODULE_DESCRIPTION("Q6 Routing platform");
400 MODULE_LICENSE("GPL v2");