1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020, Linaro Limited
3
4 #include <linux/cleanup.h>
5 #include <sound/soc.h>
6 #include <sound/soc-dapm.h>
7 #include <sound/pcm.h>
8 #include <sound/control.h>
9 #include <sound/asound.h>
10 #include <linux/firmware.h>
11 #include <sound/soc-topology.h>
12 #include <sound/soc-dpcm.h>
13 #include <uapi/sound/snd_ar_tokens.h>
14 #include <linux/kernel.h>
15 #include <linux/wait.h>
16 #include "q6apm.h"
17 #include "audioreach.h"
18
19 struct snd_ar_control {
20 u32 graph_id; /* Graph ID */
21 u32 sgid; /* Sub Graph ID */
22 u32 module_instance_id; /* Connected Module Instance ID */
23 struct snd_soc_dapm_widget *w;
24 struct list_head node;
25 struct snd_soc_component *scomp;
26 };
27
audioreach_tplg_alloc_graph_info(struct q6apm * apm,uint32_t graph_id,bool * found)28 static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm,
29 uint32_t graph_id,
30 bool *found)
31 {
32 struct audioreach_graph_info *info;
33 int ret;
34
35 mutex_lock(&apm->lock);
36 info = idr_find(&apm->graph_info_idr, graph_id);
37 mutex_unlock(&apm->lock);
38
39 if (info) {
40 *found = true;
41 return info;
42 }
43
44 *found = false;
45 info = kzalloc(sizeof(*info), GFP_KERNEL);
46 if (!info)
47 return ERR_PTR(-ENOMEM);
48
49 INIT_LIST_HEAD(&info->sg_list);
50
51 mutex_lock(&apm->lock);
52 ret = idr_alloc_u32(&apm->graph_info_idr, info, &graph_id, graph_id, GFP_KERNEL);
53 mutex_unlock(&apm->lock);
54
55 if (ret < 0) {
56 dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id);
57 kfree(info);
58 return ERR_PTR(ret);
59 }
60
61 info->id = graph_id;
62
63 return info;
64 }
65
audioreach_tplg_add_sub_graph(struct audioreach_sub_graph * sg,struct audioreach_graph_info * info)66 static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg,
67 struct audioreach_graph_info *info)
68 {
69 list_add_tail(&sg->node, &info->sg_list);
70 sg->info = info;
71 info->num_sub_graphs++;
72 }
73
audioreach_tplg_alloc_sub_graph(struct q6apm * apm,uint32_t sub_graph_id,bool * found)74 static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm,
75 uint32_t sub_graph_id,
76 bool *found)
77 {
78 struct audioreach_sub_graph *sg;
79 int ret;
80
81 if (!sub_graph_id)
82 return ERR_PTR(-EINVAL);
83
84 /* Find if there is already a matching sub-graph */
85 mutex_lock(&apm->lock);
86 sg = idr_find(&apm->sub_graphs_idr, sub_graph_id);
87 mutex_unlock(&apm->lock);
88
89 if (sg) {
90 *found = true;
91 return sg;
92 }
93
94 *found = false;
95 sg = kzalloc(sizeof(*sg), GFP_KERNEL);
96 if (!sg)
97 return ERR_PTR(-ENOMEM);
98
99 INIT_LIST_HEAD(&sg->container_list);
100
101 mutex_lock(&apm->lock);
102 ret = idr_alloc_u32(&apm->sub_graphs_idr, sg, &sub_graph_id, sub_graph_id, GFP_KERNEL);
103 mutex_unlock(&apm->lock);
104
105 if (ret < 0) {
106 dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id);
107 kfree(sg);
108 return ERR_PTR(ret);
109 }
110
111 sg->sub_graph_id = sub_graph_id;
112
113 return sg;
114 }
115
audioreach_tplg_alloc_container(struct q6apm * apm,struct audioreach_sub_graph * sg,uint32_t container_id,bool * found)116 static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm,
117 struct audioreach_sub_graph *sg,
118 uint32_t container_id,
119 bool *found)
120 {
121 struct audioreach_container *cont;
122 int ret;
123
124 if (!container_id)
125 return ERR_PTR(-EINVAL);
126
127 mutex_lock(&apm->lock);
128 cont = idr_find(&apm->containers_idr, container_id);
129 mutex_unlock(&apm->lock);
130
131 if (cont) {
132 *found = true;
133 return cont;
134 }
135 *found = false;
136
137 cont = kzalloc(sizeof(*cont), GFP_KERNEL);
138 if (!cont)
139 return ERR_PTR(-ENOMEM);
140
141 INIT_LIST_HEAD(&cont->modules_list);
142
143 mutex_lock(&apm->lock);
144 ret = idr_alloc_u32(&apm->containers_idr, cont, &container_id, container_id, GFP_KERNEL);
145 mutex_unlock(&apm->lock);
146
147 if (ret < 0) {
148 dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id);
149 kfree(cont);
150 return ERR_PTR(ret);
151 }
152
153 cont->container_id = container_id;
154 cont->sub_graph = sg;
155 /* add to container list */
156 list_add_tail(&cont->node, &sg->container_list);
157 sg->num_containers++;
158
159 return cont;
160 }
161
audioreach_tplg_alloc_module(struct q6apm * apm,struct audioreach_container * cont,struct snd_soc_dapm_widget * w,uint32_t module_id,bool * found)162 static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
163 struct audioreach_container *cont,
164 struct snd_soc_dapm_widget *w,
165 uint32_t module_id, bool *found)
166 {
167 struct audioreach_module *mod;
168 int ret;
169
170 mutex_lock(&apm->lock);
171 mod = idr_find(&apm->modules_idr, module_id);
172 mutex_unlock(&apm->lock);
173
174 if (mod) {
175 *found = true;
176 return mod;
177 }
178 *found = false;
179 mod = kzalloc(sizeof(*mod), GFP_KERNEL);
180 if (!mod)
181 return ERR_PTR(-ENOMEM);
182
183 mutex_lock(&apm->lock);
184 if (!module_id) { /* alloc module id dynamically */
185 ret = idr_alloc_cyclic(&apm->modules_idr, mod,
186 AR_MODULE_DYNAMIC_INSTANCE_ID_START,
187 AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL);
188 } else {
189 ret = idr_alloc_u32(&apm->modules_idr, mod, &module_id, module_id, GFP_KERNEL);
190 }
191 mutex_unlock(&apm->lock);
192
193 if (ret < 0) {
194 dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id);
195 kfree(mod);
196 return ERR_PTR(ret);
197 }
198
199 mod->instance_id = module_id;
200 /* add to module list */
201 list_add_tail(&mod->node, &cont->modules_list);
202 mod->container = cont;
203 mod->widget = w;
204 cont->num_modules++;
205
206 return mod;
207 }
208
audioreach_get_sg_array(struct snd_soc_tplg_private * private)209 static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array(
210 struct snd_soc_tplg_private *private)
211 {
212 struct snd_soc_tplg_vendor_array *sg_array = NULL;
213 bool found = false;
214 int sz;
215
216 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
217 struct snd_soc_tplg_vendor_value_elem *sg_elem;
218 int tkn_count = 0;
219
220 sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
221 sg_elem = sg_array->value;
222 sz = sz + le32_to_cpu(sg_array->size);
223 while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
224 switch (le32_to_cpu(sg_elem->token)) {
225 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
226 found = true;
227 break;
228 default:
229 break;
230 }
231 tkn_count++;
232 sg_elem++;
233 }
234 }
235
236 if (found)
237 return sg_array;
238
239 return NULL;
240 }
241
audioreach_get_cont_array(struct snd_soc_tplg_private * private)242 static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array(
243 struct snd_soc_tplg_private *private)
244 {
245 struct snd_soc_tplg_vendor_array *cont_array = NULL;
246 bool found = false;
247 int sz;
248
249 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
250 struct snd_soc_tplg_vendor_value_elem *cont_elem;
251 int tkn_count = 0;
252
253 cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
254 cont_elem = cont_array->value;
255 sz = sz + le32_to_cpu(cont_array->size);
256 while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
257 switch (le32_to_cpu(cont_elem->token)) {
258 case AR_TKN_U32_CONTAINER_INSTANCE_ID:
259 found = true;
260 break;
261 default:
262 break;
263 }
264 tkn_count++;
265 cont_elem++;
266 }
267 }
268
269 if (found)
270 return cont_array;
271
272 return NULL;
273 }
274
audioreach_get_module_array(struct snd_soc_tplg_private * private)275 static struct snd_soc_tplg_vendor_array *audioreach_get_module_array(
276 struct snd_soc_tplg_private *private)
277 {
278 struct snd_soc_tplg_vendor_array *mod_array = NULL;
279 bool found = false;
280 int sz = 0;
281
282 for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
283 struct snd_soc_tplg_vendor_value_elem *mod_elem;
284 int tkn_count = 0;
285
286 mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
287 mod_elem = mod_array->value;
288 sz = sz + le32_to_cpu(mod_array->size);
289 while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
290 switch (le32_to_cpu(mod_elem->token)) {
291 case AR_TKN_U32_MODULE_INSTANCE_ID:
292 found = true;
293 break;
294 default:
295 break;
296 }
297 tkn_count++;
298 mod_elem++;
299 }
300 }
301
302 if (found)
303 return mod_array;
304
305 return NULL;
306 }
307
audioreach_parse_sg_tokens(struct q6apm * apm,struct snd_soc_tplg_private * private)308 static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm,
309 struct snd_soc_tplg_private *private)
310 {
311 struct snd_soc_tplg_vendor_value_elem *sg_elem;
312 struct snd_soc_tplg_vendor_array *sg_array;
313 struct audioreach_graph_info *info = NULL;
314 int graph_id, sub_graph_id, tkn_count = 0;
315 struct audioreach_sub_graph *sg;
316 bool found;
317
318 sg_array = audioreach_get_sg_array(private);
319 sg_elem = sg_array->value;
320
321 while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
322 switch (le32_to_cpu(sg_elem->token)) {
323 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
324 sub_graph_id = le32_to_cpu(sg_elem->value);
325 sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found);
326 if (IS_ERR(sg)) {
327 return sg;
328 } else if (found) {
329 /* Already parsed data for this sub-graph */
330 return sg;
331 }
332 break;
333 case AR_TKN_DAI_INDEX:
334 /* Sub graph is associated with predefined graph */
335 graph_id = le32_to_cpu(sg_elem->value);
336 info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found);
337 if (IS_ERR(info))
338 return ERR_CAST(info);
339 break;
340 case AR_TKN_U32_SUB_GRAPH_PERF_MODE:
341 sg->perf_mode = le32_to_cpu(sg_elem->value);
342 break;
343 case AR_TKN_U32_SUB_GRAPH_DIRECTION:
344 sg->direction = le32_to_cpu(sg_elem->value);
345 break;
346 case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID:
347 sg->scenario_id = le32_to_cpu(sg_elem->value);
348 break;
349 default:
350 dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token);
351 break;
352
353 }
354 tkn_count++;
355 sg_elem++;
356 }
357
358 /* Sub graph is associated with predefined graph */
359 if (info)
360 audioreach_tplg_add_sub_graph(sg, info);
361
362 return sg;
363 }
364
audioreach_parse_cont_tokens(struct q6apm * apm,struct audioreach_sub_graph * sg,struct snd_soc_tplg_private * private)365 static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm,
366 struct audioreach_sub_graph *sg,
367 struct snd_soc_tplg_private *private)
368 {
369 struct snd_soc_tplg_vendor_value_elem *cont_elem;
370 struct snd_soc_tplg_vendor_array *cont_array;
371 struct audioreach_container *cont;
372 int container_id, tkn_count = 0;
373 bool found = false;
374
375 cont_array = audioreach_get_cont_array(private);
376 cont_elem = cont_array->value;
377
378 while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
379 switch (le32_to_cpu(cont_elem->token)) {
380 case AR_TKN_U32_CONTAINER_INSTANCE_ID:
381 container_id = le32_to_cpu(cont_elem->value);
382 cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found);
383 if (IS_ERR(cont) || found)/* Error or Already parsed container data */
384 return cont;
385 break;
386 case AR_TKN_U32_CONTAINER_CAPABILITY_ID:
387 cont->capability_id = le32_to_cpu(cont_elem->value);
388 break;
389 case AR_TKN_U32_CONTAINER_STACK_SIZE:
390 cont->stack_size = le32_to_cpu(cont_elem->value);
391 break;
392 case AR_TKN_U32_CONTAINER_GRAPH_POS:
393 cont->graph_pos = le32_to_cpu(cont_elem->value);
394 break;
395 case AR_TKN_U32_CONTAINER_PROC_DOMAIN:
396 cont->proc_domain = le32_to_cpu(cont_elem->value);
397 break;
398 default:
399 dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token);
400 break;
401
402 }
403 tkn_count++;
404 cont_elem++;
405 }
406
407 return cont;
408 }
409
audioreach_parse_common_tokens(struct q6apm * apm,struct audioreach_container * cont,struct snd_soc_tplg_private * private,struct snd_soc_dapm_widget * w)410 static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm,
411 struct audioreach_container *cont,
412 struct snd_soc_tplg_private *private,
413 struct snd_soc_dapm_widget *w)
414 {
415 uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
416 uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, };
417 uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, };
418 uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, };
419 uint32_t src_mod_inst_id = 0;
420
421 int module_id = 0, instance_id = 0, tkn_count = 0;
422 struct snd_soc_tplg_vendor_value_elem *mod_elem;
423 struct snd_soc_tplg_vendor_array *mod_array;
424 struct audioreach_module *mod = NULL;
425 uint32_t token;
426 bool found;
427 int max_tokens;
428
429 mod_array = audioreach_get_module_array(private);
430 mod_elem = mod_array->value;
431 max_tokens = le32_to_cpu(mod_array->num_elems);
432 while (tkn_count <= (max_tokens - 1)) {
433 token = le32_to_cpu(mod_elem->token);
434 switch (token) {
435 /* common module info */
436 case AR_TKN_U32_MODULE_ID:
437 module_id = le32_to_cpu(mod_elem->value);
438 break;
439 case AR_TKN_U32_MODULE_INSTANCE_ID:
440 instance_id = le32_to_cpu(mod_elem->value);
441 mod = audioreach_tplg_alloc_module(apm, cont, w,
442 instance_id, &found);
443 if (IS_ERR(mod)) {
444 return mod;
445 } else if (found) {
446 dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n",
447 instance_id);
448 return ERR_PTR(-EINVAL);
449 }
450
451 break;
452 case AR_TKN_U32_MODULE_MAX_IP_PORTS:
453 max_ip_port = le32_to_cpu(mod_elem->value);
454 break;
455 case AR_TKN_U32_MODULE_MAX_OP_PORTS:
456 max_op_port = le32_to_cpu(mod_elem->value);
457 break;
458 case AR_TKN_U32_MODULE_IN_PORTS:
459 in_port = le32_to_cpu(mod_elem->value);
460 break;
461 case AR_TKN_U32_MODULE_OUT_PORTS:
462 out_port = le32_to_cpu(mod_elem->value);
463 break;
464 case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
465 src_mod_inst_id = le32_to_cpu(mod_elem->value);
466 break;
467 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
468 src_mod_op_port_id[0] = le32_to_cpu(mod_elem->value);
469 break;
470 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID1:
471 src_mod_op_port_id[1] = le32_to_cpu(mod_elem->value);
472 break;
473 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID2:
474 src_mod_op_port_id[2] = le32_to_cpu(mod_elem->value);
475 break;
476 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID3:
477 src_mod_op_port_id[3] = le32_to_cpu(mod_elem->value);
478 break;
479 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID4:
480 src_mod_op_port_id[4] = le32_to_cpu(mod_elem->value);
481 break;
482 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID5:
483 src_mod_op_port_id[5] = le32_to_cpu(mod_elem->value);
484 break;
485 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID6:
486 src_mod_op_port_id[6] = le32_to_cpu(mod_elem->value);
487 break;
488 case AR_TKN_U32_MODULE_SRC_OP_PORT_ID7:
489 src_mod_op_port_id[7] = le32_to_cpu(mod_elem->value);
490 break;
491 case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
492 dst_mod_inst_id[0] = le32_to_cpu(mod_elem->value);
493 break;
494 case AR_TKN_U32_MODULE_DST_INSTANCE_ID1:
495 dst_mod_inst_id[1] = le32_to_cpu(mod_elem->value);
496 break;
497 case AR_TKN_U32_MODULE_DST_INSTANCE_ID2:
498 dst_mod_inst_id[2] = le32_to_cpu(mod_elem->value);
499 break;
500 case AR_TKN_U32_MODULE_DST_INSTANCE_ID3:
501 dst_mod_inst_id[3] = le32_to_cpu(mod_elem->value);
502 break;
503 case AR_TKN_U32_MODULE_DST_INSTANCE_ID4:
504 dst_mod_inst_id[4] = le32_to_cpu(mod_elem->value);
505 break;
506 case AR_TKN_U32_MODULE_DST_INSTANCE_ID5:
507 dst_mod_inst_id[5] = le32_to_cpu(mod_elem->value);
508 break;
509 case AR_TKN_U32_MODULE_DST_INSTANCE_ID6:
510 dst_mod_inst_id[6] = le32_to_cpu(mod_elem->value);
511 break;
512 case AR_TKN_U32_MODULE_DST_INSTANCE_ID7:
513 dst_mod_inst_id[7] = le32_to_cpu(mod_elem->value);
514 break;
515 case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
516 dst_mod_ip_port_id[0] = le32_to_cpu(mod_elem->value);
517 break;
518 case AR_TKN_U32_MODULE_DST_IN_PORT_ID1:
519 dst_mod_ip_port_id[1] = le32_to_cpu(mod_elem->value);
520 break;
521 case AR_TKN_U32_MODULE_DST_IN_PORT_ID2:
522 dst_mod_ip_port_id[2] = le32_to_cpu(mod_elem->value);
523 break;
524 case AR_TKN_U32_MODULE_DST_IN_PORT_ID3:
525 dst_mod_ip_port_id[3] = le32_to_cpu(mod_elem->value);
526 break;
527 case AR_TKN_U32_MODULE_DST_IN_PORT_ID4:
528 dst_mod_ip_port_id[4] = le32_to_cpu(mod_elem->value);
529 break;
530 case AR_TKN_U32_MODULE_DST_IN_PORT_ID5:
531 dst_mod_ip_port_id[5] = le32_to_cpu(mod_elem->value);
532 break;
533 case AR_TKN_U32_MODULE_DST_IN_PORT_ID6:
534 dst_mod_ip_port_id[6] = le32_to_cpu(mod_elem->value);
535 break;
536 case AR_TKN_U32_MODULE_DST_IN_PORT_ID7:
537 dst_mod_ip_port_id[7] = le32_to_cpu(mod_elem->value);
538 break;
539 default:
540 break;
541
542 }
543 tkn_count++;
544 mod_elem++;
545 }
546
547 if (mod) {
548 int pn, id = 0;
549
550 mod->module_id = module_id;
551 mod->max_ip_port = max_ip_port;
552 mod->max_op_port = max_op_port;
553 mod->in_port = in_port;
554 mod->out_port = out_port;
555 mod->src_mod_inst_id = src_mod_inst_id;
556 for (pn = 0; pn < mod->max_op_port; pn++) {
557 if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] &&
558 dst_mod_ip_port_id[pn]) {
559 mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn];
560 mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn];
561 mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn];
562 id++;
563 mod->num_connections = id;
564 }
565 }
566 }
567
568 return mod;
569 }
570
audioreach_widget_load_module_common(struct snd_soc_component * component,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * tplg_w)571 static int audioreach_widget_load_module_common(struct snd_soc_component *component,
572 int index, struct snd_soc_dapm_widget *w,
573 struct snd_soc_tplg_dapm_widget *tplg_w)
574 {
575 struct q6apm *apm = dev_get_drvdata(component->dev);
576 struct audioreach_container *cont;
577 struct audioreach_sub_graph *sg;
578 struct audioreach_module *mod;
579 struct snd_soc_dobj *dobj;
580
581 sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv);
582 if (IS_ERR(sg))
583 return PTR_ERR(sg);
584
585 cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv);
586 if (IS_ERR(cont))
587 return PTR_ERR(cont);
588
589 mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w);
590 if (IS_ERR(mod))
591 return PTR_ERR(mod);
592
593 dobj = &w->dobj;
594 dobj->private = mod;
595
596 return 0;
597 }
598
audioreach_widget_load_enc_dec_cnv(struct snd_soc_component * component,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * tplg_w)599 static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component,
600 int index, struct snd_soc_dapm_widget *w,
601 struct snd_soc_tplg_dapm_widget *tplg_w)
602 {
603 struct snd_soc_tplg_vendor_value_elem *mod_elem;
604 struct snd_soc_tplg_vendor_array *mod_array;
605 struct audioreach_module *mod;
606 struct snd_soc_dobj *dobj;
607 int tkn_count = 0;
608 int ret;
609
610 ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
611 if (ret)
612 return ret;
613
614 dobj = &w->dobj;
615 mod = dobj->private;
616 mod_array = audioreach_get_module_array(&tplg_w->priv);
617 mod_elem = mod_array->value;
618
619 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
620 switch (le32_to_cpu(mod_elem->token)) {
621 case AR_TKN_U32_MODULE_FMT_INTERLEAVE:
622 mod->interleave_type = le32_to_cpu(mod_elem->value);
623 break;
624 case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE:
625 mod->rate = le32_to_cpu(mod_elem->value);
626 break;
627 case AR_TKN_U32_MODULE_FMT_BIT_DEPTH:
628 mod->bit_depth = le32_to_cpu(mod_elem->value);
629 break;
630 default:
631 break;
632 }
633 tkn_count++;
634 mod_elem++;
635 }
636
637 return 0;
638 }
639
audioreach_widget_log_module_load(struct audioreach_module * mod,struct snd_soc_tplg_vendor_array * mod_array)640 static int audioreach_widget_log_module_load(struct audioreach_module *mod,
641 struct snd_soc_tplg_vendor_array *mod_array)
642 {
643 struct snd_soc_tplg_vendor_value_elem *mod_elem;
644 int tkn_count = 0;
645
646 mod_elem = mod_array->value;
647
648 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
649 switch (le32_to_cpu(mod_elem->token)) {
650
651 case AR_TKN_U32_MODULE_LOG_CODE:
652 mod->log_code = le32_to_cpu(mod_elem->value);
653 break;
654 case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID:
655 mod->log_tap_point_id = le32_to_cpu(mod_elem->value);
656 break;
657 case AR_TKN_U32_MODULE_LOG_MODE:
658 mod->log_mode = le32_to_cpu(mod_elem->value);
659 break;
660 default:
661 break;
662 }
663 tkn_count++;
664 mod_elem++;
665 }
666
667 return 0;
668 }
669
audioreach_widget_dma_module_load(struct audioreach_module * mod,struct snd_soc_tplg_vendor_array * mod_array)670 static int audioreach_widget_dma_module_load(struct audioreach_module *mod,
671 struct snd_soc_tplg_vendor_array *mod_array)
672 {
673 struct snd_soc_tplg_vendor_value_elem *mod_elem;
674 int tkn_count = 0;
675
676 mod_elem = mod_array->value;
677
678 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
679 switch (le32_to_cpu(mod_elem->token)) {
680 case AR_TKN_U32_MODULE_HW_IF_IDX:
681 mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
682 break;
683 case AR_TKN_U32_MODULE_FMT_DATA:
684 mod->data_format = le32_to_cpu(mod_elem->value);
685 break;
686 case AR_TKN_U32_MODULE_HW_IF_TYPE:
687 mod->hw_interface_type = le32_to_cpu(mod_elem->value);
688 break;
689 default:
690 break;
691 }
692 tkn_count++;
693 mod_elem++;
694 }
695
696 return 0;
697 }
698
audioreach_widget_i2s_module_load(struct audioreach_module * mod,struct snd_soc_tplg_vendor_array * mod_array)699 static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
700 struct snd_soc_tplg_vendor_array *mod_array)
701 {
702 struct snd_soc_tplg_vendor_value_elem *mod_elem;
703 int tkn_count = 0;
704
705 mod_elem = mod_array->value;
706
707 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
708 switch (le32_to_cpu(mod_elem->token)) {
709 case AR_TKN_U32_MODULE_HW_IF_IDX:
710 mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
711 break;
712 case AR_TKN_U32_MODULE_FMT_DATA:
713 mod->data_format = le32_to_cpu(mod_elem->value);
714 break;
715 case AR_TKN_U32_MODULE_HW_IF_TYPE:
716 mod->hw_interface_type = le32_to_cpu(mod_elem->value);
717 break;
718 case AR_TKN_U32_MODULE_SD_LINE_IDX:
719 mod->sd_line_idx = le32_to_cpu(mod_elem->value);
720 break;
721 case AR_TKN_U32_MODULE_WS_SRC:
722 mod->ws_src = le32_to_cpu(mod_elem->value);
723 break;
724 default:
725 break;
726 }
727 tkn_count++;
728 mod_elem++;
729 }
730
731 return 0;
732 }
733
audioreach_widget_dp_module_load(struct audioreach_module * mod,struct snd_soc_tplg_vendor_array * mod_array)734 static int audioreach_widget_dp_module_load(struct audioreach_module *mod,
735 struct snd_soc_tplg_vendor_array *mod_array)
736 {
737 struct snd_soc_tplg_vendor_value_elem *mod_elem;
738 int tkn_count = 0;
739
740 mod_elem = mod_array->value;
741
742 while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
743 switch (le32_to_cpu(mod_elem->token)) {
744 case AR_TKN_U32_MODULE_FMT_DATA:
745 mod->data_format = le32_to_cpu(mod_elem->value);
746 break;
747 default:
748 break;
749 }
750 tkn_count++;
751 mod_elem++;
752 }
753
754 return 0;
755 }
756
audioreach_widget_load_buffer(struct snd_soc_component * component,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * tplg_w)757 static int audioreach_widget_load_buffer(struct snd_soc_component *component,
758 int index, struct snd_soc_dapm_widget *w,
759 struct snd_soc_tplg_dapm_widget *tplg_w)
760 {
761 struct snd_soc_tplg_vendor_array *mod_array;
762 struct audioreach_module *mod;
763 struct snd_soc_dobj *dobj;
764 int ret;
765
766 ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
767 if (ret)
768 return ret;
769
770 dobj = &w->dobj;
771 mod = dobj->private;
772
773 mod_array = audioreach_get_module_array(&tplg_w->priv);
774
775 switch (mod->module_id) {
776 case MODULE_ID_CODEC_DMA_SINK:
777 case MODULE_ID_CODEC_DMA_SOURCE:
778 audioreach_widget_dma_module_load(mod, mod_array);
779 break;
780 case MODULE_ID_DATA_LOGGING:
781 audioreach_widget_log_module_load(mod, mod_array);
782 break;
783 case MODULE_ID_I2S_SINK:
784 case MODULE_ID_I2S_SOURCE:
785 audioreach_widget_i2s_module_load(mod, mod_array);
786 break;
787 case MODULE_ID_DISPLAY_PORT_SINK:
788 audioreach_widget_dp_module_load(mod, mod_array);
789 break;
790 default:
791 return -EINVAL;
792 }
793
794 return 0;
795 }
796
audioreach_widget_load_mixer(struct snd_soc_component * component,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * tplg_w)797 static int audioreach_widget_load_mixer(struct snd_soc_component *component,
798 int index, struct snd_soc_dapm_widget *w,
799 struct snd_soc_tplg_dapm_widget *tplg_w)
800 {
801 struct snd_soc_tplg_vendor_value_elem *w_elem;
802 struct snd_soc_tplg_vendor_array *w_array;
803 struct snd_ar_control *scontrol;
804 struct q6apm *data = dev_get_drvdata(component->dev);
805 struct snd_soc_dobj *dobj;
806 int tkn_count = 0;
807
808 w_array = &tplg_w->priv.array[0];
809
810 scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
811 if (!scontrol)
812 return -ENOMEM;
813
814 scontrol->scomp = component;
815 dobj = &w->dobj;
816 dobj->private = scontrol;
817
818 w_elem = w_array->value;
819 while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) {
820 switch (le32_to_cpu(w_elem->token)) {
821 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
822 scontrol->sgid = le32_to_cpu(w_elem->value);
823 break;
824 case AR_TKN_DAI_INDEX:
825 scontrol->graph_id = le32_to_cpu(w_elem->value);
826 break;
827 default: /* ignore other tokens */
828 break;
829 }
830 tkn_count++;
831 w_elem++;
832 }
833
834 scontrol->w = w;
835 list_add_tail(&scontrol->node, &data->widget_list);
836
837 return 0;
838 }
839
audioreach_pga_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)840 static int audioreach_pga_event(struct snd_soc_dapm_widget *w,
841 struct snd_kcontrol *kcontrol, int event)
842
843 {
844 struct snd_soc_dapm_context *dapm = w->dapm;
845 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
846 struct audioreach_module *mod = w->dobj.private;
847 struct q6apm *apm = dev_get_drvdata(c->dev);
848
849 switch (event) {
850 case SND_SOC_DAPM_POST_PMU:
851 /* apply gain after power up of widget */
852 audioreach_gain_set_vol_ctrl(apm, mod, mod->gain);
853 break;
854 default:
855 break;
856 }
857
858 return 0;
859 }
860
861 static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = {
862 { AR_PGA_DAPM_EVENT, audioreach_pga_event },
863 };
864
audioreach_widget_load_pga(struct snd_soc_component * component,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * tplg_w)865 static int audioreach_widget_load_pga(struct snd_soc_component *component,
866 int index, struct snd_soc_dapm_widget *w,
867 struct snd_soc_tplg_dapm_widget *tplg_w)
868 {
869 struct audioreach_module *mod;
870 struct snd_soc_dobj *dobj;
871 int ret;
872
873 ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
874 if (ret)
875 return ret;
876
877 dobj = &w->dobj;
878 mod = dobj->private;
879 mod->gain = VOL_CTRL_DEFAULT_GAIN;
880
881 ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops,
882 ARRAY_SIZE(audioreach_widget_ops),
883 le16_to_cpu(tplg_w->event_type));
884 if (ret) {
885 dev_err(component->dev, "matching event handlers NOT found for %d\n",
886 le16_to_cpu(tplg_w->event_type));
887 return -EINVAL;
888 }
889
890 return 0;
891 }
892
audioreach_widget_ready(struct snd_soc_component * component,int index,struct snd_soc_dapm_widget * w,struct snd_soc_tplg_dapm_widget * tplg_w)893 static int audioreach_widget_ready(struct snd_soc_component *component,
894 int index, struct snd_soc_dapm_widget *w,
895 struct snd_soc_tplg_dapm_widget *tplg_w)
896 {
897 switch (w->id) {
898 case snd_soc_dapm_aif_in:
899 case snd_soc_dapm_aif_out:
900 audioreach_widget_load_buffer(component, index, w, tplg_w);
901 break;
902 case snd_soc_dapm_decoder:
903 case snd_soc_dapm_encoder:
904 case snd_soc_dapm_src:
905 audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w);
906 break;
907 case snd_soc_dapm_buffer:
908 audioreach_widget_load_buffer(component, index, w, tplg_w);
909 break;
910 case snd_soc_dapm_mixer:
911 return audioreach_widget_load_mixer(component, index, w, tplg_w);
912 case snd_soc_dapm_pga:
913 return audioreach_widget_load_pga(component, index, w, tplg_w);
914 case snd_soc_dapm_dai_link:
915 case snd_soc_dapm_scheduler:
916 case snd_soc_dapm_out_drv:
917 default:
918 dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id);
919 break;
920 }
921
922 return 0;
923 }
924
audioreach_widget_unload(struct snd_soc_component * scomp,struct snd_soc_dobj * dobj)925 static int audioreach_widget_unload(struct snd_soc_component *scomp,
926 struct snd_soc_dobj *dobj)
927 {
928 struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
929 struct q6apm *apm = dev_get_drvdata(scomp->dev);
930 struct audioreach_container *cont;
931 struct audioreach_module *mod;
932
933 mod = dobj->private;
934 cont = mod->container;
935
936 if (w->id == snd_soc_dapm_mixer) {
937 /* virtual widget */
938 struct snd_ar_control *scontrol = dobj->private;
939
940 list_del(&scontrol->node);
941 kfree(scontrol);
942 return 0;
943 }
944
945 mutex_lock(&apm->lock);
946 idr_remove(&apm->modules_idr, mod->instance_id);
947 cont->num_modules--;
948
949 list_del(&mod->node);
950 kfree(mod);
951 /* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */
952 if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */
953 struct audioreach_sub_graph *sg = cont->sub_graph;
954
955 idr_remove(&apm->containers_idr, cont->container_id);
956 list_del(&cont->node);
957 sg->num_containers--;
958 kfree(cont);
959 /* check if there are no more containers in the sub graph and remove it */
960 if (list_empty(&sg->container_list)) {
961 struct audioreach_graph_info *info = sg->info;
962
963 idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id);
964 list_del(&sg->node);
965 info->num_sub_graphs--;
966 kfree(sg);
967 /* Check if there are no more sub-graphs left then remove graph info */
968 if (list_empty(&info->sg_list)) {
969 idr_remove(&apm->graph_info_idr, info->id);
970 kfree(info);
971 }
972 }
973 }
974
975 mutex_unlock(&apm->lock);
976
977 return 0;
978 }
979
audioreach_find_widget(struct snd_soc_component * comp,const char * name)980 static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp,
981 const char *name)
982 {
983 struct q6apm *apm = dev_get_drvdata(comp->dev);
984 struct snd_ar_control *control;
985
986 list_for_each_entry(control, &apm->widget_list, node) {
987 if (control->w && !strcmp(name, control->w->name))
988 return control;
989 }
990
991 return NULL;
992 }
993
audioreach_find_module(struct snd_soc_component * comp,const char * name)994 static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp,
995 const char *name)
996 {
997 struct q6apm *apm = dev_get_drvdata(comp->dev);
998 struct audioreach_module *module;
999 int id;
1000
1001 idr_for_each_entry(&apm->modules_idr, module, id) {
1002 if (!strcmp(name, module->widget->name))
1003 return module;
1004 }
1005
1006 return NULL;
1007 }
1008
audioreach_route_load(struct snd_soc_component * scomp,int index,struct snd_soc_dapm_route * route)1009 static int audioreach_route_load(struct snd_soc_component *scomp, int index,
1010 struct snd_soc_dapm_route *route)
1011 {
1012 struct audioreach_module *src_module, *sink_module;
1013 struct snd_ar_control *control;
1014 struct snd_soc_dapm_widget *w;
1015 int i;
1016
1017 /* check if these are actual modules */
1018 src_module = audioreach_find_module(scomp, route->source);
1019 sink_module = audioreach_find_module(scomp, route->sink);
1020
1021 if (sink_module && !src_module) {
1022 control = audioreach_find_widget(scomp, route->source);
1023 if (control)
1024 control->module_instance_id = sink_module->instance_id;
1025
1026 } else if (!sink_module && src_module && route->control) {
1027 /* check if this is a virtual mixer */
1028 control = audioreach_find_widget(scomp, route->sink);
1029 if (!control || !control->w)
1030 return 0;
1031
1032 w = control->w;
1033
1034 for (i = 0; i < w->num_kcontrols; i++) {
1035 if (!strcmp(route->control, w->kcontrol_news[i].name)) {
1036 struct soc_mixer_control *sm;
1037 struct snd_soc_dobj *dobj;
1038 struct snd_ar_control *scontrol;
1039
1040 sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value;
1041 dobj = &sm->dobj;
1042 scontrol = dobj->private;
1043 scontrol->module_instance_id = src_module->instance_id;
1044 }
1045 }
1046
1047 }
1048
1049 return 0;
1050 }
1051
audioreach_route_unload(struct snd_soc_component * scomp,struct snd_soc_dobj * dobj)1052 static int audioreach_route_unload(struct snd_soc_component *scomp,
1053 struct snd_soc_dobj *dobj)
1054 {
1055 return 0;
1056 }
1057
audioreach_tplg_complete(struct snd_soc_component * component)1058 static int audioreach_tplg_complete(struct snd_soc_component *component)
1059 {
1060 /* TBD */
1061 return 0;
1062 }
1063
1064 /* DAI link - used for any driver specific init */
audioreach_link_load(struct snd_soc_component * component,int index,struct snd_soc_dai_link * link,struct snd_soc_tplg_link_config * cfg)1065 static int audioreach_link_load(struct snd_soc_component *component, int index,
1066 struct snd_soc_dai_link *link,
1067 struct snd_soc_tplg_link_config *cfg)
1068 {
1069 link->nonatomic = true;
1070 link->dynamic = true;
1071 link->platforms->name = NULL;
1072 link->platforms->of_node = of_get_compatible_child(component->dev->of_node,
1073 "qcom,q6apm-dais");
1074 return 0;
1075 }
1076
audioreach_connect_sub_graphs(struct q6apm * apm,struct snd_ar_control * m1,struct snd_ar_control * m2,bool connect)1077 static void audioreach_connect_sub_graphs(struct q6apm *apm,
1078 struct snd_ar_control *m1,
1079 struct snd_ar_control *m2,
1080 bool connect)
1081 {
1082 struct audioreach_graph_info *info;
1083
1084 mutex_lock(&apm->lock);
1085 info = idr_find(&apm->graph_info_idr, m2->graph_id);
1086 mutex_unlock(&apm->lock);
1087
1088 if (connect) {
1089 info->src_mod_inst_id = m1->module_instance_id;
1090 info->src_mod_op_port_id = 1;
1091 info->dst_mod_inst_id = m2->module_instance_id;
1092 info->dst_mod_ip_port_id = 2;
1093
1094 } else {
1095 info->src_mod_inst_id = 0;
1096 info->src_mod_op_port_id = 0;
1097 info->dst_mod_inst_id = 0;
1098 info->dst_mod_ip_port_id = 0;
1099 }
1100 }
1101
audioreach_is_vmixer_connected(struct q6apm * apm,struct snd_ar_control * m1,struct snd_ar_control * m2)1102 static bool audioreach_is_vmixer_connected(struct q6apm *apm,
1103 struct snd_ar_control *m1,
1104 struct snd_ar_control *m2)
1105 {
1106 struct audioreach_graph_info *info;
1107
1108 mutex_lock(&apm->lock);
1109 info = idr_find(&apm->graph_info_idr, m2->graph_id);
1110 mutex_unlock(&apm->lock);
1111
1112 if (info->dst_mod_inst_id == m2->module_instance_id &&
1113 info->src_mod_inst_id == m1->module_instance_id)
1114 return true;
1115
1116 return false;
1117 }
1118
audioreach_get_audio_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1119 static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
1120 struct snd_ctl_elem_value *ucontrol)
1121 {
1122 struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1123 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1124 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1125 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1126 struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1127 struct snd_ar_control *scontrol = mc->dobj.private;
1128 struct q6apm *data = dev_get_drvdata(c->dev);
1129 bool connected;
1130
1131 connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol);
1132 if (connected)
1133 ucontrol->value.integer.value[0] = 1;
1134 else
1135 ucontrol->value.integer.value[0] = 0;
1136
1137 return 0;
1138 }
1139
audioreach_put_audio_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1140 static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
1141 struct snd_ctl_elem_value *ucontrol)
1142 {
1143 struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
1144 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
1145 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1146 struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
1147 struct snd_ar_control *dapm_scontrol = dw->dobj.private;
1148 struct snd_ar_control *scontrol = mc->dobj.private;
1149 struct q6apm *data = dev_get_drvdata(c->dev);
1150
1151 if (ucontrol->value.integer.value[0]) {
1152 audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true);
1153 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
1154 } else {
1155 audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false);
1156 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
1157 }
1158 return 0;
1159 }
1160
audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1161 static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1162 struct snd_ctl_elem_value *ucontrol)
1163 {
1164 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1165 struct audioreach_module *mod = dw->dobj.private;
1166
1167 ucontrol->value.integer.value[0] = mod->gain;
1168
1169 return 0;
1170 }
1171
audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1172 static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
1173 struct snd_ctl_elem_value *ucontrol)
1174 {
1175 struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
1176 struct audioreach_module *mod = dw->dobj.private;
1177
1178 mod->gain = ucontrol->value.integer.value[0];
1179
1180 return 1;
1181 }
1182
audioreach_control_load_mix(struct snd_soc_component * scomp,struct snd_ar_control * scontrol,struct snd_kcontrol_new * kc,struct snd_soc_tplg_ctl_hdr * hdr)1183 static int audioreach_control_load_mix(struct snd_soc_component *scomp,
1184 struct snd_ar_control *scontrol,
1185 struct snd_kcontrol_new *kc,
1186 struct snd_soc_tplg_ctl_hdr *hdr)
1187 {
1188 struct snd_soc_tplg_vendor_value_elem *c_elem;
1189 struct snd_soc_tplg_vendor_array *c_array;
1190 struct snd_soc_tplg_mixer_control *mc;
1191 int tkn_count = 0;
1192
1193 mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
1194 c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data;
1195
1196 c_elem = c_array->value;
1197
1198 while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) {
1199 switch (le32_to_cpu(c_elem->token)) {
1200 case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
1201 scontrol->sgid = le32_to_cpu(c_elem->value);
1202 break;
1203 case AR_TKN_DAI_INDEX:
1204 scontrol->graph_id = le32_to_cpu(c_elem->value);
1205 break;
1206 default:
1207 /* Ignore other tokens */
1208 break;
1209 }
1210 c_elem++;
1211 tkn_count++;
1212 }
1213
1214 return 0;
1215 }
1216
audioreach_control_load(struct snd_soc_component * scomp,int index,struct snd_kcontrol_new * kc,struct snd_soc_tplg_ctl_hdr * hdr)1217 static int audioreach_control_load(struct snd_soc_component *scomp, int index,
1218 struct snd_kcontrol_new *kc,
1219 struct snd_soc_tplg_ctl_hdr *hdr)
1220 {
1221 struct snd_ar_control *scontrol;
1222 struct soc_mixer_control *sm;
1223 struct snd_soc_dobj *dobj;
1224 int ret = 0;
1225
1226 scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
1227 if (!scontrol)
1228 return -ENOMEM;
1229
1230 scontrol->scomp = scomp;
1231
1232 switch (le32_to_cpu(hdr->ops.get)) {
1233 case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX:
1234 sm = (struct soc_mixer_control *)kc->private_value;
1235 dobj = &sm->dobj;
1236 ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr);
1237 break;
1238 case SND_SOC_AR_TPLG_VOL_CTL:
1239 sm = (struct soc_mixer_control *)kc->private_value;
1240 dobj = &sm->dobj;
1241 break;
1242 default:
1243 dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
1244 hdr->ops.get, hdr->ops.put, hdr->ops.info);
1245 kfree(scontrol);
1246 return -EINVAL;
1247 }
1248
1249 dobj->private = scontrol;
1250 return ret;
1251 }
1252
audioreach_control_unload(struct snd_soc_component * scomp,struct snd_soc_dobj * dobj)1253 static int audioreach_control_unload(struct snd_soc_component *scomp,
1254 struct snd_soc_dobj *dobj)
1255 {
1256 struct snd_ar_control *scontrol = dobj->private;
1257
1258 kfree(scontrol);
1259
1260 return 0;
1261 }
1262
1263 static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
1264 {SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer,
1265 audioreach_put_audio_mixer, snd_soc_info_volsw},
1266 {SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer,
1267 audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
1268 };
1269
1270 static const struct snd_soc_tplg_ops audioreach_tplg_ops = {
1271 .io_ops = audioreach_io_ops,
1272 .io_ops_count = ARRAY_SIZE(audioreach_io_ops),
1273
1274 .control_load = audioreach_control_load,
1275 .control_unload = audioreach_control_unload,
1276
1277 .widget_ready = audioreach_widget_ready,
1278 .widget_unload = audioreach_widget_unload,
1279
1280 .complete = audioreach_tplg_complete,
1281 .link_load = audioreach_link_load,
1282
1283 .dapm_route_load = audioreach_route_load,
1284 .dapm_route_unload = audioreach_route_unload,
1285 };
1286
audioreach_tplg_init(struct snd_soc_component * component)1287 int audioreach_tplg_init(struct snd_soc_component *component)
1288 {
1289 struct snd_soc_card *card = component->card;
1290 struct device *dev = component->dev;
1291 const struct firmware *fw;
1292 int ret;
1293
1294 /* Inline with Qualcomm UCM configs and linux-firmware path */
1295 char *tplg_fw_name __free(kfree) = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin",
1296 card->driver_name,
1297 card->name);
1298 if (!tplg_fw_name)
1299 return -ENOMEM;
1300
1301 ret = request_firmware(&fw, tplg_fw_name, dev);
1302 if (ret < 0) {
1303 dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret);
1304 return ret;
1305 }
1306
1307 ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
1308 if (ret < 0) {
1309 if (ret != -EPROBE_DEFER)
1310 dev_err(dev, "tplg component load failed: %d\n", ret);
1311 }
1312
1313 release_firmware(fw);
1314
1315 return ret;
1316 }
1317 EXPORT_SYMBOL_GPL(audioreach_tplg_init);
1318