~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/qcom/qdsp6/topology.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 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 
 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 
 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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
1052 static int audioreach_route_unload(struct snd_soc_component *scomp,
1053                                    struct snd_soc_dobj *dobj)
1054 {
1055         return 0;
1056 }
1057 
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 */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php