136ad9bf1SSrinivas Kandagatla // SPDX-License-Identifier: GPL-2.0 236ad9bf1SSrinivas Kandagatla // Copyright (c) 2020, Linaro Limited 336ad9bf1SSrinivas Kandagatla 436ad9bf1SSrinivas Kandagatla #include <sound/soc.h> 536ad9bf1SSrinivas Kandagatla #include <sound/soc-dapm.h> 636ad9bf1SSrinivas Kandagatla #include <sound/pcm.h> 736ad9bf1SSrinivas Kandagatla #include <sound/control.h> 836ad9bf1SSrinivas Kandagatla #include <sound/asound.h> 936ad9bf1SSrinivas Kandagatla #include <linux/firmware.h> 1036ad9bf1SSrinivas Kandagatla #include <sound/soc-topology.h> 1136ad9bf1SSrinivas Kandagatla #include <sound/soc-dpcm.h> 1236ad9bf1SSrinivas Kandagatla #include <uapi/sound/snd_ar_tokens.h> 1336ad9bf1SSrinivas Kandagatla #include <linux/kernel.h> 1436ad9bf1SSrinivas Kandagatla #include <linux/wait.h> 1536ad9bf1SSrinivas Kandagatla #include "q6apm.h" 1636ad9bf1SSrinivas Kandagatla #include "audioreach.h" 1736ad9bf1SSrinivas Kandagatla 1836ad9bf1SSrinivas Kandagatla struct snd_ar_control { 191c87d381SSrinivas Kandagatla u32 graph_id; /* Graph ID */ 2036ad9bf1SSrinivas Kandagatla u32 sgid; /* Sub Graph ID */ 211c87d381SSrinivas Kandagatla u32 module_instance_id; /* Connected Module Instance ID */ 221c87d381SSrinivas Kandagatla struct snd_soc_dapm_widget *w; 231c87d381SSrinivas Kandagatla struct list_head node; 2436ad9bf1SSrinivas Kandagatla struct snd_soc_component *scomp; 2536ad9bf1SSrinivas Kandagatla }; 2636ad9bf1SSrinivas Kandagatla 2736ad9bf1SSrinivas Kandagatla static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm, 2836ad9bf1SSrinivas Kandagatla uint32_t graph_id, 2936ad9bf1SSrinivas Kandagatla bool *found) 3036ad9bf1SSrinivas Kandagatla { 3136ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info; 3236ad9bf1SSrinivas Kandagatla int ret; 3336ad9bf1SSrinivas Kandagatla 3436ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 3536ad9bf1SSrinivas Kandagatla info = idr_find(&apm->graph_info_idr, graph_id); 3636ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 3736ad9bf1SSrinivas Kandagatla 3836ad9bf1SSrinivas Kandagatla if (info) { 3936ad9bf1SSrinivas Kandagatla *found = true; 4036ad9bf1SSrinivas Kandagatla return info; 4136ad9bf1SSrinivas Kandagatla } 4236ad9bf1SSrinivas Kandagatla 4336ad9bf1SSrinivas Kandagatla *found = false; 4436ad9bf1SSrinivas Kandagatla info = kzalloc(sizeof(*info), GFP_KERNEL); 4536ad9bf1SSrinivas Kandagatla if (!info) 4636ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 4736ad9bf1SSrinivas Kandagatla 4836ad9bf1SSrinivas Kandagatla INIT_LIST_HEAD(&info->sg_list); 4936ad9bf1SSrinivas Kandagatla 5036ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 51af7ed7ebSSrinivas Kandagatla ret = idr_alloc_u32(&apm->graph_info_idr, info, &graph_id, graph_id, GFP_KERNEL); 5236ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 5336ad9bf1SSrinivas Kandagatla 5436ad9bf1SSrinivas Kandagatla if (ret < 0) { 5536ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id); 5636ad9bf1SSrinivas Kandagatla kfree(info); 5736ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 5836ad9bf1SSrinivas Kandagatla } 5936ad9bf1SSrinivas Kandagatla 60af7ed7ebSSrinivas Kandagatla info->id = graph_id; 6136ad9bf1SSrinivas Kandagatla 6236ad9bf1SSrinivas Kandagatla return info; 6336ad9bf1SSrinivas Kandagatla } 6436ad9bf1SSrinivas Kandagatla 6536ad9bf1SSrinivas Kandagatla static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg, 6636ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info) 6736ad9bf1SSrinivas Kandagatla { 6836ad9bf1SSrinivas Kandagatla list_add_tail(&sg->node, &info->sg_list); 6936ad9bf1SSrinivas Kandagatla sg->info = info; 7036ad9bf1SSrinivas Kandagatla info->num_sub_graphs++; 7136ad9bf1SSrinivas Kandagatla } 7236ad9bf1SSrinivas Kandagatla 7336ad9bf1SSrinivas Kandagatla static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm, 7436ad9bf1SSrinivas Kandagatla uint32_t sub_graph_id, 7536ad9bf1SSrinivas Kandagatla bool *found) 7636ad9bf1SSrinivas Kandagatla { 7736ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg; 7836ad9bf1SSrinivas Kandagatla int ret; 7936ad9bf1SSrinivas Kandagatla 8036ad9bf1SSrinivas Kandagatla if (!sub_graph_id) 8136ad9bf1SSrinivas Kandagatla return ERR_PTR(-EINVAL); 8236ad9bf1SSrinivas Kandagatla 8336ad9bf1SSrinivas Kandagatla /* Find if there is already a matching sub-graph */ 8436ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 8536ad9bf1SSrinivas Kandagatla sg = idr_find(&apm->sub_graphs_idr, sub_graph_id); 8636ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 8736ad9bf1SSrinivas Kandagatla 8836ad9bf1SSrinivas Kandagatla if (sg) { 8936ad9bf1SSrinivas Kandagatla *found = true; 9036ad9bf1SSrinivas Kandagatla return sg; 9136ad9bf1SSrinivas Kandagatla } 9236ad9bf1SSrinivas Kandagatla 9336ad9bf1SSrinivas Kandagatla *found = false; 9436ad9bf1SSrinivas Kandagatla sg = kzalloc(sizeof(*sg), GFP_KERNEL); 9536ad9bf1SSrinivas Kandagatla if (!sg) 9636ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 9736ad9bf1SSrinivas Kandagatla 9836ad9bf1SSrinivas Kandagatla INIT_LIST_HEAD(&sg->container_list); 9936ad9bf1SSrinivas Kandagatla 10036ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 101af7ed7ebSSrinivas Kandagatla ret = idr_alloc_u32(&apm->sub_graphs_idr, sg, &sub_graph_id, sub_graph_id, GFP_KERNEL); 10236ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 10336ad9bf1SSrinivas Kandagatla 10436ad9bf1SSrinivas Kandagatla if (ret < 0) { 10536ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id); 10636ad9bf1SSrinivas Kandagatla kfree(sg); 10736ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 10836ad9bf1SSrinivas Kandagatla } 10936ad9bf1SSrinivas Kandagatla 110af7ed7ebSSrinivas Kandagatla sg->sub_graph_id = sub_graph_id; 11136ad9bf1SSrinivas Kandagatla 11236ad9bf1SSrinivas Kandagatla return sg; 11336ad9bf1SSrinivas Kandagatla } 11436ad9bf1SSrinivas Kandagatla 11536ad9bf1SSrinivas Kandagatla static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm, 11636ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg, 11736ad9bf1SSrinivas Kandagatla uint32_t container_id, 11836ad9bf1SSrinivas Kandagatla bool *found) 11936ad9bf1SSrinivas Kandagatla { 12036ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 12136ad9bf1SSrinivas Kandagatla int ret; 12236ad9bf1SSrinivas Kandagatla 12336ad9bf1SSrinivas Kandagatla if (!container_id) 12436ad9bf1SSrinivas Kandagatla return ERR_PTR(-EINVAL); 12536ad9bf1SSrinivas Kandagatla 12636ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 12736ad9bf1SSrinivas Kandagatla cont = idr_find(&apm->containers_idr, container_id); 12836ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 12936ad9bf1SSrinivas Kandagatla 13036ad9bf1SSrinivas Kandagatla if (cont) { 13136ad9bf1SSrinivas Kandagatla *found = true; 13236ad9bf1SSrinivas Kandagatla return cont; 13336ad9bf1SSrinivas Kandagatla } 13436ad9bf1SSrinivas Kandagatla *found = false; 13536ad9bf1SSrinivas Kandagatla 13636ad9bf1SSrinivas Kandagatla cont = kzalloc(sizeof(*cont), GFP_KERNEL); 13736ad9bf1SSrinivas Kandagatla if (!cont) 13836ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 13936ad9bf1SSrinivas Kandagatla 14036ad9bf1SSrinivas Kandagatla INIT_LIST_HEAD(&cont->modules_list); 14136ad9bf1SSrinivas Kandagatla 14236ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 143af7ed7ebSSrinivas Kandagatla ret = idr_alloc_u32(&apm->containers_idr, cont, &container_id, container_id, GFP_KERNEL); 14436ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 14536ad9bf1SSrinivas Kandagatla 14636ad9bf1SSrinivas Kandagatla if (ret < 0) { 14736ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id); 14836ad9bf1SSrinivas Kandagatla kfree(cont); 14936ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 15036ad9bf1SSrinivas Kandagatla } 15136ad9bf1SSrinivas Kandagatla 152af7ed7ebSSrinivas Kandagatla cont->container_id = container_id; 15336ad9bf1SSrinivas Kandagatla cont->sub_graph = sg; 15436ad9bf1SSrinivas Kandagatla /* add to container list */ 15536ad9bf1SSrinivas Kandagatla list_add_tail(&cont->node, &sg->container_list); 15636ad9bf1SSrinivas Kandagatla sg->num_containers++; 15736ad9bf1SSrinivas Kandagatla 15836ad9bf1SSrinivas Kandagatla return cont; 15936ad9bf1SSrinivas Kandagatla } 16036ad9bf1SSrinivas Kandagatla 16136ad9bf1SSrinivas Kandagatla static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm, 16236ad9bf1SSrinivas Kandagatla struct audioreach_container *cont, 16336ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *w, 16436ad9bf1SSrinivas Kandagatla uint32_t module_id, bool *found) 16536ad9bf1SSrinivas Kandagatla { 16636ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 16736ad9bf1SSrinivas Kandagatla int ret; 16836ad9bf1SSrinivas Kandagatla 16936ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 17036ad9bf1SSrinivas Kandagatla mod = idr_find(&apm->modules_idr, module_id); 17136ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 17236ad9bf1SSrinivas Kandagatla 17336ad9bf1SSrinivas Kandagatla if (mod) { 17436ad9bf1SSrinivas Kandagatla *found = true; 17536ad9bf1SSrinivas Kandagatla return mod; 17636ad9bf1SSrinivas Kandagatla } 17736ad9bf1SSrinivas Kandagatla *found = false; 17836ad9bf1SSrinivas Kandagatla mod = kzalloc(sizeof(*mod), GFP_KERNEL); 17936ad9bf1SSrinivas Kandagatla if (!mod) 18036ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 18136ad9bf1SSrinivas Kandagatla 18236ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 18336ad9bf1SSrinivas Kandagatla if (!module_id) { /* alloc module id dynamically */ 18436ad9bf1SSrinivas Kandagatla ret = idr_alloc_cyclic(&apm->modules_idr, mod, 18536ad9bf1SSrinivas Kandagatla AR_MODULE_DYNAMIC_INSTANCE_ID_START, 18636ad9bf1SSrinivas Kandagatla AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL); 18736ad9bf1SSrinivas Kandagatla } else { 188af7ed7ebSSrinivas Kandagatla ret = idr_alloc_u32(&apm->modules_idr, mod, &module_id, module_id, GFP_KERNEL); 18936ad9bf1SSrinivas Kandagatla } 19036ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 19136ad9bf1SSrinivas Kandagatla 19236ad9bf1SSrinivas Kandagatla if (ret < 0) { 19336ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id); 19436ad9bf1SSrinivas Kandagatla kfree(mod); 19536ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 19636ad9bf1SSrinivas Kandagatla } 19736ad9bf1SSrinivas Kandagatla 198af7ed7ebSSrinivas Kandagatla mod->instance_id = module_id; 19936ad9bf1SSrinivas Kandagatla /* add to module list */ 20036ad9bf1SSrinivas Kandagatla list_add_tail(&mod->node, &cont->modules_list); 20136ad9bf1SSrinivas Kandagatla mod->container = cont; 20236ad9bf1SSrinivas Kandagatla mod->widget = w; 20336ad9bf1SSrinivas Kandagatla cont->num_modules++; 20436ad9bf1SSrinivas Kandagatla 20536ad9bf1SSrinivas Kandagatla return mod; 20636ad9bf1SSrinivas Kandagatla } 20736ad9bf1SSrinivas Kandagatla 20836ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array( 20936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 21036ad9bf1SSrinivas Kandagatla { 21136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *sg_array = NULL; 21236ad9bf1SSrinivas Kandagatla bool found = false; 21336ad9bf1SSrinivas Kandagatla int sz; 21436ad9bf1SSrinivas Kandagatla 21536ad9bf1SSrinivas Kandagatla for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 21636ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *sg_elem; 21736ad9bf1SSrinivas Kandagatla int tkn_count = 0; 21836ad9bf1SSrinivas Kandagatla 21936ad9bf1SSrinivas Kandagatla sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 22036ad9bf1SSrinivas Kandagatla sg_elem = sg_array->value; 22136ad9bf1SSrinivas Kandagatla sz = sz + le32_to_cpu(sg_array->size); 22236ad9bf1SSrinivas Kandagatla while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { 22336ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(sg_elem->token)) { 22436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 22536ad9bf1SSrinivas Kandagatla found = true; 22636ad9bf1SSrinivas Kandagatla break; 22736ad9bf1SSrinivas Kandagatla default: 22836ad9bf1SSrinivas Kandagatla break; 22936ad9bf1SSrinivas Kandagatla } 23036ad9bf1SSrinivas Kandagatla tkn_count++; 23136ad9bf1SSrinivas Kandagatla sg_elem++; 23236ad9bf1SSrinivas Kandagatla } 23336ad9bf1SSrinivas Kandagatla } 23436ad9bf1SSrinivas Kandagatla 23536ad9bf1SSrinivas Kandagatla if (found) 23636ad9bf1SSrinivas Kandagatla return sg_array; 23736ad9bf1SSrinivas Kandagatla 23836ad9bf1SSrinivas Kandagatla return NULL; 23936ad9bf1SSrinivas Kandagatla } 24036ad9bf1SSrinivas Kandagatla 24136ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array( 24236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 24336ad9bf1SSrinivas Kandagatla { 24436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *cont_array = NULL; 24536ad9bf1SSrinivas Kandagatla bool found = false; 24636ad9bf1SSrinivas Kandagatla int sz; 24736ad9bf1SSrinivas Kandagatla 24836ad9bf1SSrinivas Kandagatla for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 24936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *cont_elem; 25036ad9bf1SSrinivas Kandagatla int tkn_count = 0; 25136ad9bf1SSrinivas Kandagatla 25236ad9bf1SSrinivas Kandagatla cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 25336ad9bf1SSrinivas Kandagatla cont_elem = cont_array->value; 25436ad9bf1SSrinivas Kandagatla sz = sz + le32_to_cpu(cont_array->size); 25536ad9bf1SSrinivas Kandagatla while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { 25636ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(cont_elem->token)) { 25736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_INSTANCE_ID: 25836ad9bf1SSrinivas Kandagatla found = true; 25936ad9bf1SSrinivas Kandagatla break; 26036ad9bf1SSrinivas Kandagatla default: 26136ad9bf1SSrinivas Kandagatla break; 26236ad9bf1SSrinivas Kandagatla } 26336ad9bf1SSrinivas Kandagatla tkn_count++; 26436ad9bf1SSrinivas Kandagatla cont_elem++; 26536ad9bf1SSrinivas Kandagatla } 26636ad9bf1SSrinivas Kandagatla } 26736ad9bf1SSrinivas Kandagatla 26836ad9bf1SSrinivas Kandagatla if (found) 26936ad9bf1SSrinivas Kandagatla return cont_array; 27036ad9bf1SSrinivas Kandagatla 27136ad9bf1SSrinivas Kandagatla return NULL; 27236ad9bf1SSrinivas Kandagatla } 27336ad9bf1SSrinivas Kandagatla 27436ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_vendor_array *audioreach_get_module_array( 27536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 27636ad9bf1SSrinivas Kandagatla { 27736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array = NULL; 27836ad9bf1SSrinivas Kandagatla bool found = false; 27936ad9bf1SSrinivas Kandagatla int sz = 0; 28036ad9bf1SSrinivas Kandagatla 28136ad9bf1SSrinivas Kandagatla for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 28236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 28336ad9bf1SSrinivas Kandagatla int tkn_count = 0; 28436ad9bf1SSrinivas Kandagatla 28536ad9bf1SSrinivas Kandagatla mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 28636ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 28736ad9bf1SSrinivas Kandagatla sz = sz + le32_to_cpu(mod_array->size); 28836ad9bf1SSrinivas Kandagatla while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 28936ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 29036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_INSTANCE_ID: 29136ad9bf1SSrinivas Kandagatla found = true; 29236ad9bf1SSrinivas Kandagatla break; 29336ad9bf1SSrinivas Kandagatla default: 29436ad9bf1SSrinivas Kandagatla break; 29536ad9bf1SSrinivas Kandagatla } 29636ad9bf1SSrinivas Kandagatla tkn_count++; 29736ad9bf1SSrinivas Kandagatla mod_elem++; 29836ad9bf1SSrinivas Kandagatla } 29936ad9bf1SSrinivas Kandagatla } 30036ad9bf1SSrinivas Kandagatla 30136ad9bf1SSrinivas Kandagatla if (found) 30236ad9bf1SSrinivas Kandagatla return mod_array; 30336ad9bf1SSrinivas Kandagatla 30436ad9bf1SSrinivas Kandagatla return NULL; 30536ad9bf1SSrinivas Kandagatla } 30636ad9bf1SSrinivas Kandagatla 30736ad9bf1SSrinivas Kandagatla static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm, 30836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 30936ad9bf1SSrinivas Kandagatla { 31036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *sg_elem; 31136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *sg_array; 31236ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info = NULL; 31336ad9bf1SSrinivas Kandagatla int graph_id, sub_graph_id, tkn_count = 0; 31436ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg; 31536ad9bf1SSrinivas Kandagatla bool found; 31636ad9bf1SSrinivas Kandagatla 31736ad9bf1SSrinivas Kandagatla sg_array = audioreach_get_sg_array(private); 31836ad9bf1SSrinivas Kandagatla sg_elem = sg_array->value; 31936ad9bf1SSrinivas Kandagatla 32036ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { 32136ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(sg_elem->token)) { 32236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 32336ad9bf1SSrinivas Kandagatla sub_graph_id = le32_to_cpu(sg_elem->value); 32436ad9bf1SSrinivas Kandagatla sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found); 32536ad9bf1SSrinivas Kandagatla if (IS_ERR(sg)) { 32636ad9bf1SSrinivas Kandagatla return sg; 32736ad9bf1SSrinivas Kandagatla } else if (found) { 32836ad9bf1SSrinivas Kandagatla /* Already parsed data for this sub-graph */ 32936ad9bf1SSrinivas Kandagatla return sg; 33036ad9bf1SSrinivas Kandagatla } 33136ad9bf1SSrinivas Kandagatla break; 33236ad9bf1SSrinivas Kandagatla case AR_TKN_DAI_INDEX: 33336ad9bf1SSrinivas Kandagatla /* Sub graph is associated with predefined graph */ 33436ad9bf1SSrinivas Kandagatla graph_id = le32_to_cpu(sg_elem->value); 33536ad9bf1SSrinivas Kandagatla info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found); 33636ad9bf1SSrinivas Kandagatla if (IS_ERR(info)) 33736ad9bf1SSrinivas Kandagatla return ERR_CAST(info); 33836ad9bf1SSrinivas Kandagatla break; 33936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_PERF_MODE: 34036ad9bf1SSrinivas Kandagatla sg->perf_mode = le32_to_cpu(sg_elem->value); 34136ad9bf1SSrinivas Kandagatla break; 34236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_DIRECTION: 34336ad9bf1SSrinivas Kandagatla sg->direction = le32_to_cpu(sg_elem->value); 34436ad9bf1SSrinivas Kandagatla break; 34536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID: 34636ad9bf1SSrinivas Kandagatla sg->scenario_id = le32_to_cpu(sg_elem->value); 34736ad9bf1SSrinivas Kandagatla break; 34836ad9bf1SSrinivas Kandagatla default: 34936ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token); 35036ad9bf1SSrinivas Kandagatla break; 35136ad9bf1SSrinivas Kandagatla 35236ad9bf1SSrinivas Kandagatla } 35336ad9bf1SSrinivas Kandagatla tkn_count++; 35436ad9bf1SSrinivas Kandagatla sg_elem++; 35536ad9bf1SSrinivas Kandagatla } 35636ad9bf1SSrinivas Kandagatla 35736ad9bf1SSrinivas Kandagatla /* Sub graph is associated with predefined graph */ 35836ad9bf1SSrinivas Kandagatla if (info) 35936ad9bf1SSrinivas Kandagatla audioreach_tplg_add_sub_graph(sg, info); 36036ad9bf1SSrinivas Kandagatla 36136ad9bf1SSrinivas Kandagatla return sg; 36236ad9bf1SSrinivas Kandagatla } 36336ad9bf1SSrinivas Kandagatla 36436ad9bf1SSrinivas Kandagatla static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm, 36536ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg, 36636ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 36736ad9bf1SSrinivas Kandagatla { 36836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *cont_elem; 36936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *cont_array; 37036ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 37136ad9bf1SSrinivas Kandagatla int container_id, tkn_count = 0; 37236ad9bf1SSrinivas Kandagatla bool found = false; 37336ad9bf1SSrinivas Kandagatla 37436ad9bf1SSrinivas Kandagatla cont_array = audioreach_get_cont_array(private); 37536ad9bf1SSrinivas Kandagatla cont_elem = cont_array->value; 37636ad9bf1SSrinivas Kandagatla 37736ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { 37836ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(cont_elem->token)) { 37936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_INSTANCE_ID: 38036ad9bf1SSrinivas Kandagatla container_id = le32_to_cpu(cont_elem->value); 38136ad9bf1SSrinivas Kandagatla cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found); 38236ad9bf1SSrinivas Kandagatla if (IS_ERR(cont) || found)/* Error or Already parsed container data */ 38336ad9bf1SSrinivas Kandagatla return cont; 38436ad9bf1SSrinivas Kandagatla break; 38536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_CAPABILITY_ID: 38636ad9bf1SSrinivas Kandagatla cont->capability_id = le32_to_cpu(cont_elem->value); 38736ad9bf1SSrinivas Kandagatla break; 38836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_STACK_SIZE: 38936ad9bf1SSrinivas Kandagatla cont->stack_size = le32_to_cpu(cont_elem->value); 39036ad9bf1SSrinivas Kandagatla break; 39136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_GRAPH_POS: 39236ad9bf1SSrinivas Kandagatla cont->graph_pos = le32_to_cpu(cont_elem->value); 39336ad9bf1SSrinivas Kandagatla break; 39436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_PROC_DOMAIN: 39536ad9bf1SSrinivas Kandagatla cont->proc_domain = le32_to_cpu(cont_elem->value); 39636ad9bf1SSrinivas Kandagatla break; 39736ad9bf1SSrinivas Kandagatla default: 39836ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token); 39936ad9bf1SSrinivas Kandagatla break; 40036ad9bf1SSrinivas Kandagatla 40136ad9bf1SSrinivas Kandagatla } 40236ad9bf1SSrinivas Kandagatla tkn_count++; 40336ad9bf1SSrinivas Kandagatla cont_elem++; 40436ad9bf1SSrinivas Kandagatla } 40536ad9bf1SSrinivas Kandagatla 40636ad9bf1SSrinivas Kandagatla return cont; 40736ad9bf1SSrinivas Kandagatla } 40836ad9bf1SSrinivas Kandagatla 40936ad9bf1SSrinivas Kandagatla static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm, 41036ad9bf1SSrinivas Kandagatla struct audioreach_container *cont, 41136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private, 41236ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *w) 41336ad9bf1SSrinivas Kandagatla { 41436ad9bf1SSrinivas Kandagatla uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0; 415*03365d6aSSrinivas Kandagatla uint32_t src_mod_op_port_id[AR_MAX_MOD_LINKS] = { 0, }; 416*03365d6aSSrinivas Kandagatla uint32_t dst_mod_inst_id[AR_MAX_MOD_LINKS] = { 0, }; 417*03365d6aSSrinivas Kandagatla uint32_t dst_mod_ip_port_id[AR_MAX_MOD_LINKS] = { 0, }; 418*03365d6aSSrinivas Kandagatla uint32_t src_mod_inst_id = 0; 419*03365d6aSSrinivas Kandagatla 42036ad9bf1SSrinivas Kandagatla int module_id = 0, instance_id = 0, tkn_count = 0; 42136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 42236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 42336ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = NULL; 424*03365d6aSSrinivas Kandagatla uint32_t token; 42536ad9bf1SSrinivas Kandagatla bool found; 426*03365d6aSSrinivas Kandagatla int max_tokens; 42736ad9bf1SSrinivas Kandagatla 42836ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(private); 42936ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 430*03365d6aSSrinivas Kandagatla max_tokens = le32_to_cpu(mod_array->num_elems); 431*03365d6aSSrinivas Kandagatla while (tkn_count <= (max_tokens - 1)) { 432*03365d6aSSrinivas Kandagatla token = le32_to_cpu(mod_elem->token); 433*03365d6aSSrinivas Kandagatla switch (token) { 43436ad9bf1SSrinivas Kandagatla /* common module info */ 43536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_ID: 43636ad9bf1SSrinivas Kandagatla module_id = le32_to_cpu(mod_elem->value); 43736ad9bf1SSrinivas Kandagatla break; 43836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_INSTANCE_ID: 43936ad9bf1SSrinivas Kandagatla instance_id = le32_to_cpu(mod_elem->value); 44036ad9bf1SSrinivas Kandagatla mod = audioreach_tplg_alloc_module(apm, cont, w, 44136ad9bf1SSrinivas Kandagatla instance_id, &found); 44236ad9bf1SSrinivas Kandagatla if (IS_ERR(mod)) { 44336ad9bf1SSrinivas Kandagatla return mod; 44436ad9bf1SSrinivas Kandagatla } else if (found) { 44536ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n", 44636ad9bf1SSrinivas Kandagatla instance_id); 44736ad9bf1SSrinivas Kandagatla return ERR_PTR(-EINVAL); 44836ad9bf1SSrinivas Kandagatla } 44936ad9bf1SSrinivas Kandagatla 45036ad9bf1SSrinivas Kandagatla break; 45136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_MAX_IP_PORTS: 45236ad9bf1SSrinivas Kandagatla max_ip_port = le32_to_cpu(mod_elem->value); 45336ad9bf1SSrinivas Kandagatla break; 45436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_MAX_OP_PORTS: 45536ad9bf1SSrinivas Kandagatla max_op_port = le32_to_cpu(mod_elem->value); 45636ad9bf1SSrinivas Kandagatla break; 45736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_IN_PORTS: 45836ad9bf1SSrinivas Kandagatla in_port = le32_to_cpu(mod_elem->value); 45936ad9bf1SSrinivas Kandagatla break; 46036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_OUT_PORTS: 46136ad9bf1SSrinivas Kandagatla out_port = le32_to_cpu(mod_elem->value); 46236ad9bf1SSrinivas Kandagatla break; 46336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_INSTANCE_ID: 46436ad9bf1SSrinivas Kandagatla src_mod_inst_id = le32_to_cpu(mod_elem->value); 46536ad9bf1SSrinivas Kandagatla break; 466*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID: 467*03365d6aSSrinivas Kandagatla src_mod_op_port_id[0] = le32_to_cpu(mod_elem->value); 468*03365d6aSSrinivas Kandagatla break; 469*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID1: 470*03365d6aSSrinivas Kandagatla src_mod_op_port_id[1] = le32_to_cpu(mod_elem->value); 471*03365d6aSSrinivas Kandagatla break; 472*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID2: 473*03365d6aSSrinivas Kandagatla src_mod_op_port_id[2] = le32_to_cpu(mod_elem->value); 474*03365d6aSSrinivas Kandagatla break; 475*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID3: 476*03365d6aSSrinivas Kandagatla src_mod_op_port_id[3] = le32_to_cpu(mod_elem->value); 477*03365d6aSSrinivas Kandagatla break; 478*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID4: 479*03365d6aSSrinivas Kandagatla src_mod_op_port_id[4] = le32_to_cpu(mod_elem->value); 480*03365d6aSSrinivas Kandagatla break; 481*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID5: 482*03365d6aSSrinivas Kandagatla src_mod_op_port_id[5] = le32_to_cpu(mod_elem->value); 483*03365d6aSSrinivas Kandagatla break; 484*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID6: 485*03365d6aSSrinivas Kandagatla src_mod_op_port_id[6] = le32_to_cpu(mod_elem->value); 486*03365d6aSSrinivas Kandagatla break; 487*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID7: 488*03365d6aSSrinivas Kandagatla src_mod_op_port_id[7] = le32_to_cpu(mod_elem->value); 489*03365d6aSSrinivas Kandagatla break; 49036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID: 491*03365d6aSSrinivas Kandagatla dst_mod_inst_id[0] = le32_to_cpu(mod_elem->value); 492*03365d6aSSrinivas Kandagatla break; 493*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID1: 494*03365d6aSSrinivas Kandagatla dst_mod_inst_id[1] = le32_to_cpu(mod_elem->value); 495*03365d6aSSrinivas Kandagatla break; 496*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID2: 497*03365d6aSSrinivas Kandagatla dst_mod_inst_id[2] = le32_to_cpu(mod_elem->value); 498*03365d6aSSrinivas Kandagatla break; 499*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID3: 500*03365d6aSSrinivas Kandagatla dst_mod_inst_id[3] = le32_to_cpu(mod_elem->value); 501*03365d6aSSrinivas Kandagatla break; 502*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID4: 503*03365d6aSSrinivas Kandagatla dst_mod_inst_id[4] = le32_to_cpu(mod_elem->value); 504*03365d6aSSrinivas Kandagatla break; 505*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID5: 506*03365d6aSSrinivas Kandagatla dst_mod_inst_id[5] = le32_to_cpu(mod_elem->value); 507*03365d6aSSrinivas Kandagatla break; 508*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID6: 509*03365d6aSSrinivas Kandagatla dst_mod_inst_id[6] = le32_to_cpu(mod_elem->value); 510*03365d6aSSrinivas Kandagatla break; 511*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID7: 512*03365d6aSSrinivas Kandagatla dst_mod_inst_id[7] = le32_to_cpu(mod_elem->value); 51336ad9bf1SSrinivas Kandagatla break; 51436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID: 515*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[0] = le32_to_cpu(mod_elem->value); 516*03365d6aSSrinivas Kandagatla break; 517*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID1: 518*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[1] = le32_to_cpu(mod_elem->value); 519*03365d6aSSrinivas Kandagatla break; 520*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID2: 521*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[2] = le32_to_cpu(mod_elem->value); 522*03365d6aSSrinivas Kandagatla break; 523*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID3: 524*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[3] = le32_to_cpu(mod_elem->value); 525*03365d6aSSrinivas Kandagatla break; 526*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID4: 527*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[4] = le32_to_cpu(mod_elem->value); 528*03365d6aSSrinivas Kandagatla break; 529*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID5: 530*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[5] = le32_to_cpu(mod_elem->value); 531*03365d6aSSrinivas Kandagatla break; 532*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID6: 533*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[6] = le32_to_cpu(mod_elem->value); 534*03365d6aSSrinivas Kandagatla break; 535*03365d6aSSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID7: 536*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[7] = le32_to_cpu(mod_elem->value); 537c6c203bcSNathan Chancellor break; 53836ad9bf1SSrinivas Kandagatla default: 53936ad9bf1SSrinivas Kandagatla break; 54036ad9bf1SSrinivas Kandagatla 54136ad9bf1SSrinivas Kandagatla } 54236ad9bf1SSrinivas Kandagatla tkn_count++; 54336ad9bf1SSrinivas Kandagatla mod_elem++; 54436ad9bf1SSrinivas Kandagatla } 54536ad9bf1SSrinivas Kandagatla 54636ad9bf1SSrinivas Kandagatla if (mod) { 547*03365d6aSSrinivas Kandagatla int pn, id = 0; 54836ad9bf1SSrinivas Kandagatla mod->module_id = module_id; 54936ad9bf1SSrinivas Kandagatla mod->max_ip_port = max_ip_port; 55036ad9bf1SSrinivas Kandagatla mod->max_op_port = max_op_port; 55136ad9bf1SSrinivas Kandagatla mod->in_port = in_port; 55236ad9bf1SSrinivas Kandagatla mod->out_port = out_port; 55336ad9bf1SSrinivas Kandagatla mod->src_mod_inst_id = src_mod_inst_id; 554*03365d6aSSrinivas Kandagatla for (pn = 0; pn < mod->max_op_port; pn++) { 555*03365d6aSSrinivas Kandagatla if (src_mod_op_port_id[pn] && dst_mod_inst_id[pn] && 556*03365d6aSSrinivas Kandagatla dst_mod_ip_port_id[pn]) { 557*03365d6aSSrinivas Kandagatla mod->src_mod_op_port_id[id] = src_mod_op_port_id[pn]; 558*03365d6aSSrinivas Kandagatla mod->dst_mod_inst_id[id] = dst_mod_inst_id[pn]; 559*03365d6aSSrinivas Kandagatla mod->dst_mod_ip_port_id[id] = dst_mod_ip_port_id[pn]; 560*03365d6aSSrinivas Kandagatla id++; 561*03365d6aSSrinivas Kandagatla mod->num_connections = id; 562*03365d6aSSrinivas Kandagatla } 563*03365d6aSSrinivas Kandagatla } 56436ad9bf1SSrinivas Kandagatla } 56536ad9bf1SSrinivas Kandagatla 56636ad9bf1SSrinivas Kandagatla return mod; 56736ad9bf1SSrinivas Kandagatla } 56836ad9bf1SSrinivas Kandagatla 56936ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_module_common(struct snd_soc_component *component, 57036ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 57136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 57236ad9bf1SSrinivas Kandagatla { 57336ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(component->dev); 57436ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 57536ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg; 57636ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 57736ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 57836ad9bf1SSrinivas Kandagatla 57936ad9bf1SSrinivas Kandagatla sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv); 58036ad9bf1SSrinivas Kandagatla if (IS_ERR(sg)) 58136ad9bf1SSrinivas Kandagatla return PTR_ERR(sg); 58236ad9bf1SSrinivas Kandagatla 58336ad9bf1SSrinivas Kandagatla cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv); 58436ad9bf1SSrinivas Kandagatla if (IS_ERR(cont)) 58536ad9bf1SSrinivas Kandagatla return PTR_ERR(cont); 58636ad9bf1SSrinivas Kandagatla 58736ad9bf1SSrinivas Kandagatla mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w); 58836ad9bf1SSrinivas Kandagatla if (IS_ERR(mod)) 58936ad9bf1SSrinivas Kandagatla return PTR_ERR(mod); 59036ad9bf1SSrinivas Kandagatla 59136ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 59236ad9bf1SSrinivas Kandagatla dobj->private = mod; 59336ad9bf1SSrinivas Kandagatla 59436ad9bf1SSrinivas Kandagatla return 0; 59536ad9bf1SSrinivas Kandagatla } 59636ad9bf1SSrinivas Kandagatla 59736ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component, 59836ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 59936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 60036ad9bf1SSrinivas Kandagatla { 60136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 60236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 60336ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 60436ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 60536ad9bf1SSrinivas Kandagatla int tkn_count = 0; 60636ad9bf1SSrinivas Kandagatla int ret; 60736ad9bf1SSrinivas Kandagatla 60836ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 60936ad9bf1SSrinivas Kandagatla if (ret) 61036ad9bf1SSrinivas Kandagatla return ret; 61136ad9bf1SSrinivas Kandagatla 61236ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 61336ad9bf1SSrinivas Kandagatla mod = dobj->private; 61436ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(&tplg_w->priv); 61536ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 61636ad9bf1SSrinivas Kandagatla 61736ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 61836ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 61936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_INTERLEAVE: 62036ad9bf1SSrinivas Kandagatla mod->interleave_type = le32_to_cpu(mod_elem->value); 62136ad9bf1SSrinivas Kandagatla break; 62236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE: 62336ad9bf1SSrinivas Kandagatla mod->rate = le32_to_cpu(mod_elem->value); 62436ad9bf1SSrinivas Kandagatla break; 62536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_BIT_DEPTH: 62636ad9bf1SSrinivas Kandagatla mod->bit_depth = le32_to_cpu(mod_elem->value); 62736ad9bf1SSrinivas Kandagatla break; 62836ad9bf1SSrinivas Kandagatla default: 62936ad9bf1SSrinivas Kandagatla break; 63036ad9bf1SSrinivas Kandagatla } 63136ad9bf1SSrinivas Kandagatla tkn_count++; 63236ad9bf1SSrinivas Kandagatla mod_elem++; 63336ad9bf1SSrinivas Kandagatla } 63436ad9bf1SSrinivas Kandagatla 63536ad9bf1SSrinivas Kandagatla return 0; 63636ad9bf1SSrinivas Kandagatla } 63736ad9bf1SSrinivas Kandagatla 63836ad9bf1SSrinivas Kandagatla static int audioreach_widget_log_module_load(struct audioreach_module *mod, 63936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 64036ad9bf1SSrinivas Kandagatla { 64136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 64236ad9bf1SSrinivas Kandagatla int tkn_count = 0; 64336ad9bf1SSrinivas Kandagatla 64436ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 64536ad9bf1SSrinivas Kandagatla 64636ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 64736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 64836ad9bf1SSrinivas Kandagatla 64936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_CODE: 65036ad9bf1SSrinivas Kandagatla mod->log_code = le32_to_cpu(mod_elem->value); 65136ad9bf1SSrinivas Kandagatla break; 65236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID: 65336ad9bf1SSrinivas Kandagatla mod->log_tap_point_id = le32_to_cpu(mod_elem->value); 65436ad9bf1SSrinivas Kandagatla break; 65536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_MODE: 65636ad9bf1SSrinivas Kandagatla mod->log_mode = le32_to_cpu(mod_elem->value); 65736ad9bf1SSrinivas Kandagatla break; 65836ad9bf1SSrinivas Kandagatla default: 65936ad9bf1SSrinivas Kandagatla break; 66036ad9bf1SSrinivas Kandagatla } 66136ad9bf1SSrinivas Kandagatla tkn_count++; 66236ad9bf1SSrinivas Kandagatla mod_elem++; 66336ad9bf1SSrinivas Kandagatla } 66436ad9bf1SSrinivas Kandagatla 66536ad9bf1SSrinivas Kandagatla return 0; 66636ad9bf1SSrinivas Kandagatla } 66736ad9bf1SSrinivas Kandagatla 66836ad9bf1SSrinivas Kandagatla static int audioreach_widget_dma_module_load(struct audioreach_module *mod, 66936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 67036ad9bf1SSrinivas Kandagatla { 67136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 67236ad9bf1SSrinivas Kandagatla int tkn_count = 0; 67336ad9bf1SSrinivas Kandagatla 67436ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 67536ad9bf1SSrinivas Kandagatla 67636ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 67736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 67836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_IDX: 67936ad9bf1SSrinivas Kandagatla mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 68036ad9bf1SSrinivas Kandagatla break; 68136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_DATA: 68236ad9bf1SSrinivas Kandagatla mod->data_format = le32_to_cpu(mod_elem->value); 68336ad9bf1SSrinivas Kandagatla break; 68436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_TYPE: 68536ad9bf1SSrinivas Kandagatla mod->hw_interface_type = le32_to_cpu(mod_elem->value); 68636ad9bf1SSrinivas Kandagatla break; 68736ad9bf1SSrinivas Kandagatla default: 68836ad9bf1SSrinivas Kandagatla break; 68936ad9bf1SSrinivas Kandagatla } 69036ad9bf1SSrinivas Kandagatla tkn_count++; 69136ad9bf1SSrinivas Kandagatla mod_elem++; 69236ad9bf1SSrinivas Kandagatla } 69336ad9bf1SSrinivas Kandagatla 69436ad9bf1SSrinivas Kandagatla return 0; 69536ad9bf1SSrinivas Kandagatla } 69636ad9bf1SSrinivas Kandagatla 69736ad9bf1SSrinivas Kandagatla static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, 69836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 69936ad9bf1SSrinivas Kandagatla { 70036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 70136ad9bf1SSrinivas Kandagatla int tkn_count = 0; 70236ad9bf1SSrinivas Kandagatla 70336ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 70436ad9bf1SSrinivas Kandagatla 70536ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 70636ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 70736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_IDX: 70836ad9bf1SSrinivas Kandagatla mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 70936ad9bf1SSrinivas Kandagatla break; 71036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_DATA: 71136ad9bf1SSrinivas Kandagatla mod->data_format = le32_to_cpu(mod_elem->value); 71236ad9bf1SSrinivas Kandagatla break; 71336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_TYPE: 71436ad9bf1SSrinivas Kandagatla mod->hw_interface_type = le32_to_cpu(mod_elem->value); 71536ad9bf1SSrinivas Kandagatla break; 71636ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SD_LINE_IDX: 71736ad9bf1SSrinivas Kandagatla mod->sd_line_idx = le32_to_cpu(mod_elem->value); 71836ad9bf1SSrinivas Kandagatla break; 71936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_WS_SRC: 72036ad9bf1SSrinivas Kandagatla mod->ws_src = le32_to_cpu(mod_elem->value); 72136ad9bf1SSrinivas Kandagatla break; 72236ad9bf1SSrinivas Kandagatla default: 72336ad9bf1SSrinivas Kandagatla break; 72436ad9bf1SSrinivas Kandagatla } 72536ad9bf1SSrinivas Kandagatla tkn_count++; 72636ad9bf1SSrinivas Kandagatla mod_elem++; 72736ad9bf1SSrinivas Kandagatla } 72836ad9bf1SSrinivas Kandagatla 72936ad9bf1SSrinivas Kandagatla return 0; 73036ad9bf1SSrinivas Kandagatla } 73136ad9bf1SSrinivas Kandagatla 73236ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_buffer(struct snd_soc_component *component, 73336ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 73436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 73536ad9bf1SSrinivas Kandagatla { 73636ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 73736ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 73836ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 73936ad9bf1SSrinivas Kandagatla int ret; 74036ad9bf1SSrinivas Kandagatla 74136ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 74236ad9bf1SSrinivas Kandagatla if (ret) 74336ad9bf1SSrinivas Kandagatla return ret; 74436ad9bf1SSrinivas Kandagatla 74536ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 74636ad9bf1SSrinivas Kandagatla mod = dobj->private; 74736ad9bf1SSrinivas Kandagatla 74836ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(&tplg_w->priv); 74936ad9bf1SSrinivas Kandagatla 75036ad9bf1SSrinivas Kandagatla switch (mod->module_id) { 75136ad9bf1SSrinivas Kandagatla case MODULE_ID_CODEC_DMA_SINK: 75236ad9bf1SSrinivas Kandagatla case MODULE_ID_CODEC_DMA_SOURCE: 75336ad9bf1SSrinivas Kandagatla audioreach_widget_dma_module_load(mod, mod_array); 75436ad9bf1SSrinivas Kandagatla break; 75536ad9bf1SSrinivas Kandagatla case MODULE_ID_DATA_LOGGING: 75636ad9bf1SSrinivas Kandagatla audioreach_widget_log_module_load(mod, mod_array); 75736ad9bf1SSrinivas Kandagatla break; 75836ad9bf1SSrinivas Kandagatla case MODULE_ID_I2S_SINK: 75936ad9bf1SSrinivas Kandagatla case MODULE_ID_I2S_SOURCE: 76036ad9bf1SSrinivas Kandagatla audioreach_widget_i2s_module_load(mod, mod_array); 76136ad9bf1SSrinivas Kandagatla break; 76236ad9bf1SSrinivas Kandagatla default: 76336ad9bf1SSrinivas Kandagatla return -EINVAL; 76436ad9bf1SSrinivas Kandagatla } 76536ad9bf1SSrinivas Kandagatla 76636ad9bf1SSrinivas Kandagatla return 0; 76736ad9bf1SSrinivas Kandagatla } 76836ad9bf1SSrinivas Kandagatla 76936ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_mixer(struct snd_soc_component *component, 77036ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 77136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 77236ad9bf1SSrinivas Kandagatla { 77336ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *w_elem; 77436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *w_array; 77536ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol; 7761c87d381SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(component->dev); 77736ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 77836ad9bf1SSrinivas Kandagatla int tkn_count = 0; 77936ad9bf1SSrinivas Kandagatla 78036ad9bf1SSrinivas Kandagatla w_array = &tplg_w->priv.array[0]; 78136ad9bf1SSrinivas Kandagatla 78236ad9bf1SSrinivas Kandagatla scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 78336ad9bf1SSrinivas Kandagatla if (!scontrol) 78436ad9bf1SSrinivas Kandagatla return -ENOMEM; 78536ad9bf1SSrinivas Kandagatla 78636ad9bf1SSrinivas Kandagatla scontrol->scomp = component; 78736ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 78836ad9bf1SSrinivas Kandagatla dobj->private = scontrol; 78936ad9bf1SSrinivas Kandagatla 79036ad9bf1SSrinivas Kandagatla w_elem = w_array->value; 79136ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) { 79236ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(w_elem->token)) { 79336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 79436ad9bf1SSrinivas Kandagatla scontrol->sgid = le32_to_cpu(w_elem->value); 79536ad9bf1SSrinivas Kandagatla break; 7961c87d381SSrinivas Kandagatla case AR_TKN_DAI_INDEX: 7971c87d381SSrinivas Kandagatla scontrol->graph_id = le32_to_cpu(w_elem->value); 7981c87d381SSrinivas Kandagatla break; 79936ad9bf1SSrinivas Kandagatla default: /* ignore other tokens */ 80036ad9bf1SSrinivas Kandagatla break; 80136ad9bf1SSrinivas Kandagatla } 80236ad9bf1SSrinivas Kandagatla tkn_count++; 80336ad9bf1SSrinivas Kandagatla w_elem++; 80436ad9bf1SSrinivas Kandagatla } 80536ad9bf1SSrinivas Kandagatla 8061c87d381SSrinivas Kandagatla scontrol->w = w; 8071c87d381SSrinivas Kandagatla list_add_tail(&scontrol->node, &data->widget_list); 8081c87d381SSrinivas Kandagatla 80936ad9bf1SSrinivas Kandagatla return 0; 81036ad9bf1SSrinivas Kandagatla } 81136ad9bf1SSrinivas Kandagatla 81236ad9bf1SSrinivas Kandagatla static int audioreach_pga_event(struct snd_soc_dapm_widget *w, 81336ad9bf1SSrinivas Kandagatla struct snd_kcontrol *kcontrol, int event) 81436ad9bf1SSrinivas Kandagatla 81536ad9bf1SSrinivas Kandagatla { 81636ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = w->dapm; 81736ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 81836ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = w->dobj.private; 81936ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(c->dev); 82036ad9bf1SSrinivas Kandagatla 82136ad9bf1SSrinivas Kandagatla switch (event) { 82236ad9bf1SSrinivas Kandagatla case SND_SOC_DAPM_POST_PMU: 82336ad9bf1SSrinivas Kandagatla /* apply gain after power up of widget */ 82436ad9bf1SSrinivas Kandagatla audioreach_gain_set_vol_ctrl(apm, mod, mod->gain); 82536ad9bf1SSrinivas Kandagatla break; 82636ad9bf1SSrinivas Kandagatla default: 82736ad9bf1SSrinivas Kandagatla break; 82836ad9bf1SSrinivas Kandagatla } 82936ad9bf1SSrinivas Kandagatla 83036ad9bf1SSrinivas Kandagatla return 0; 83136ad9bf1SSrinivas Kandagatla } 83236ad9bf1SSrinivas Kandagatla 83336ad9bf1SSrinivas Kandagatla static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = { 83436ad9bf1SSrinivas Kandagatla { AR_PGA_DAPM_EVENT, audioreach_pga_event }, 83536ad9bf1SSrinivas Kandagatla }; 83636ad9bf1SSrinivas Kandagatla 83736ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_pga(struct snd_soc_component *component, 83836ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 83936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 84036ad9bf1SSrinivas Kandagatla { 84136ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 84236ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 84336ad9bf1SSrinivas Kandagatla int ret; 84436ad9bf1SSrinivas Kandagatla 84536ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 84636ad9bf1SSrinivas Kandagatla if (ret) 84736ad9bf1SSrinivas Kandagatla return ret; 84836ad9bf1SSrinivas Kandagatla 84936ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 85036ad9bf1SSrinivas Kandagatla mod = dobj->private; 85136ad9bf1SSrinivas Kandagatla mod->gain = VOL_CTRL_DEFAULT_GAIN; 85236ad9bf1SSrinivas Kandagatla 85336ad9bf1SSrinivas Kandagatla ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops, 85436ad9bf1SSrinivas Kandagatla ARRAY_SIZE(audioreach_widget_ops), 85536ad9bf1SSrinivas Kandagatla le16_to_cpu(tplg_w->event_type)); 85636ad9bf1SSrinivas Kandagatla if (ret) { 85736ad9bf1SSrinivas Kandagatla dev_err(component->dev, "matching event handlers NOT found for %d\n", 85836ad9bf1SSrinivas Kandagatla le16_to_cpu(tplg_w->event_type)); 85936ad9bf1SSrinivas Kandagatla return -EINVAL; 86036ad9bf1SSrinivas Kandagatla } 86136ad9bf1SSrinivas Kandagatla 86236ad9bf1SSrinivas Kandagatla return 0; 86336ad9bf1SSrinivas Kandagatla } 86436ad9bf1SSrinivas Kandagatla 86536ad9bf1SSrinivas Kandagatla static int audioreach_widget_ready(struct snd_soc_component *component, 86636ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 86736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 86836ad9bf1SSrinivas Kandagatla { 86936ad9bf1SSrinivas Kandagatla switch (w->id) { 87036ad9bf1SSrinivas Kandagatla case snd_soc_dapm_aif_in: 87136ad9bf1SSrinivas Kandagatla case snd_soc_dapm_aif_out: 87236ad9bf1SSrinivas Kandagatla audioreach_widget_load_buffer(component, index, w, tplg_w); 87336ad9bf1SSrinivas Kandagatla break; 87436ad9bf1SSrinivas Kandagatla case snd_soc_dapm_decoder: 87536ad9bf1SSrinivas Kandagatla case snd_soc_dapm_encoder: 87636ad9bf1SSrinivas Kandagatla case snd_soc_dapm_src: 87736ad9bf1SSrinivas Kandagatla audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w); 87836ad9bf1SSrinivas Kandagatla break; 87936ad9bf1SSrinivas Kandagatla case snd_soc_dapm_buffer: 88036ad9bf1SSrinivas Kandagatla audioreach_widget_load_buffer(component, index, w, tplg_w); 88136ad9bf1SSrinivas Kandagatla break; 88236ad9bf1SSrinivas Kandagatla case snd_soc_dapm_mixer: 88336ad9bf1SSrinivas Kandagatla return audioreach_widget_load_mixer(component, index, w, tplg_w); 88436ad9bf1SSrinivas Kandagatla case snd_soc_dapm_pga: 88536ad9bf1SSrinivas Kandagatla return audioreach_widget_load_pga(component, index, w, tplg_w); 88636ad9bf1SSrinivas Kandagatla case snd_soc_dapm_dai_link: 88736ad9bf1SSrinivas Kandagatla case snd_soc_dapm_scheduler: 88836ad9bf1SSrinivas Kandagatla case snd_soc_dapm_out_drv: 88936ad9bf1SSrinivas Kandagatla default: 89036ad9bf1SSrinivas Kandagatla dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id); 89136ad9bf1SSrinivas Kandagatla break; 89236ad9bf1SSrinivas Kandagatla } 89336ad9bf1SSrinivas Kandagatla 89436ad9bf1SSrinivas Kandagatla return 0; 89536ad9bf1SSrinivas Kandagatla } 89636ad9bf1SSrinivas Kandagatla 89736ad9bf1SSrinivas Kandagatla static int audioreach_widget_unload(struct snd_soc_component *scomp, 89836ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 89936ad9bf1SSrinivas Kandagatla { 90036ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj); 90136ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(scomp->dev); 90236ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 90336ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 90436ad9bf1SSrinivas Kandagatla 90536ad9bf1SSrinivas Kandagatla mod = dobj->private; 90636ad9bf1SSrinivas Kandagatla cont = mod->container; 90736ad9bf1SSrinivas Kandagatla 90836ad9bf1SSrinivas Kandagatla if (w->id == snd_soc_dapm_mixer) { 90936ad9bf1SSrinivas Kandagatla /* virtual widget */ 9101c87d381SSrinivas Kandagatla struct snd_ar_control *scontrol = dobj->private; 9111c87d381SSrinivas Kandagatla 9121c87d381SSrinivas Kandagatla list_del(&scontrol->node); 9131c87d381SSrinivas Kandagatla kfree(scontrol); 91436ad9bf1SSrinivas Kandagatla return 0; 91536ad9bf1SSrinivas Kandagatla } 91636ad9bf1SSrinivas Kandagatla 91736ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 91836ad9bf1SSrinivas Kandagatla idr_remove(&apm->modules_idr, mod->instance_id); 91936ad9bf1SSrinivas Kandagatla cont->num_modules--; 92036ad9bf1SSrinivas Kandagatla 92136ad9bf1SSrinivas Kandagatla list_del(&mod->node); 92236ad9bf1SSrinivas Kandagatla kfree(mod); 92336ad9bf1SSrinivas Kandagatla /* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */ 92436ad9bf1SSrinivas Kandagatla if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */ 92536ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg = cont->sub_graph; 92636ad9bf1SSrinivas Kandagatla 92736ad9bf1SSrinivas Kandagatla idr_remove(&apm->containers_idr, cont->container_id); 92836ad9bf1SSrinivas Kandagatla list_del(&cont->node); 92936ad9bf1SSrinivas Kandagatla sg->num_containers--; 93036ad9bf1SSrinivas Kandagatla kfree(cont); 93136ad9bf1SSrinivas Kandagatla /* check if there are no more containers in the sub graph and remove it */ 93236ad9bf1SSrinivas Kandagatla if (list_empty(&sg->container_list)) { 93336ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info = sg->info; 93436ad9bf1SSrinivas Kandagatla 93536ad9bf1SSrinivas Kandagatla idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id); 93636ad9bf1SSrinivas Kandagatla list_del(&sg->node); 93736ad9bf1SSrinivas Kandagatla info->num_sub_graphs--; 93836ad9bf1SSrinivas Kandagatla kfree(sg); 93936ad9bf1SSrinivas Kandagatla /* Check if there are no more sub-graphs left then remove graph info */ 94036ad9bf1SSrinivas Kandagatla if (list_empty(&info->sg_list)) { 94136ad9bf1SSrinivas Kandagatla idr_remove(&apm->graph_info_idr, info->id); 94236ad9bf1SSrinivas Kandagatla kfree(info); 94336ad9bf1SSrinivas Kandagatla } 94436ad9bf1SSrinivas Kandagatla } 94536ad9bf1SSrinivas Kandagatla } 94636ad9bf1SSrinivas Kandagatla 94736ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 94836ad9bf1SSrinivas Kandagatla 94936ad9bf1SSrinivas Kandagatla return 0; 95036ad9bf1SSrinivas Kandagatla } 95136ad9bf1SSrinivas Kandagatla 952e4977b91SSrinivas Kandagatla static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp, 953e4977b91SSrinivas Kandagatla const char *name) 954e4977b91SSrinivas Kandagatla { 955e4977b91SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(comp->dev); 956e4977b91SSrinivas Kandagatla struct snd_ar_control *control; 957e4977b91SSrinivas Kandagatla 958e4977b91SSrinivas Kandagatla list_for_each_entry(control, &apm->widget_list, node) { 959e4977b91SSrinivas Kandagatla if (control->w && !strcmp(name, control->w->name)) 960e4977b91SSrinivas Kandagatla return control; 961e4977b91SSrinivas Kandagatla } 962e4977b91SSrinivas Kandagatla 963e4977b91SSrinivas Kandagatla return NULL; 964e4977b91SSrinivas Kandagatla } 965e4977b91SSrinivas Kandagatla 966e4977b91SSrinivas Kandagatla static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp, 96736ad9bf1SSrinivas Kandagatla const char *name) 96836ad9bf1SSrinivas Kandagatla { 96936ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(comp->dev); 97036ad9bf1SSrinivas Kandagatla struct audioreach_module *module; 97136ad9bf1SSrinivas Kandagatla int id; 97236ad9bf1SSrinivas Kandagatla 97336ad9bf1SSrinivas Kandagatla idr_for_each_entry(&apm->modules_idr, module, id) { 97436ad9bf1SSrinivas Kandagatla if (!strcmp(name, module->widget->name)) 97536ad9bf1SSrinivas Kandagatla return module; 97636ad9bf1SSrinivas Kandagatla } 97736ad9bf1SSrinivas Kandagatla 97836ad9bf1SSrinivas Kandagatla return NULL; 97936ad9bf1SSrinivas Kandagatla } 98036ad9bf1SSrinivas Kandagatla 98136ad9bf1SSrinivas Kandagatla static int audioreach_route_load(struct snd_soc_component *scomp, int index, 98236ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_route *route) 98336ad9bf1SSrinivas Kandagatla { 984e4977b91SSrinivas Kandagatla struct audioreach_module *src_module, *sink_module; 985e4977b91SSrinivas Kandagatla struct snd_ar_control *control; 986e4977b91SSrinivas Kandagatla struct snd_soc_dapm_widget *w; 987e4977b91SSrinivas Kandagatla int i; 98836ad9bf1SSrinivas Kandagatla 989e4977b91SSrinivas Kandagatla /* check if these are actual modules */ 990e4977b91SSrinivas Kandagatla src_module = audioreach_find_module(scomp, route->source); 991e4977b91SSrinivas Kandagatla sink_module = audioreach_find_module(scomp, route->sink); 99236ad9bf1SSrinivas Kandagatla 993e4977b91SSrinivas Kandagatla if (sink_module && !src_module) { 994e4977b91SSrinivas Kandagatla control = audioreach_find_widget(scomp, route->source); 995e4977b91SSrinivas Kandagatla if (control) 996e4977b91SSrinivas Kandagatla control->module_instance_id = sink_module->instance_id; 997e4977b91SSrinivas Kandagatla 998e4977b91SSrinivas Kandagatla } else if (!sink_module && src_module && route->control) { 999e4977b91SSrinivas Kandagatla /* check if this is a virtual mixer */ 1000e4977b91SSrinivas Kandagatla control = audioreach_find_widget(scomp, route->sink); 1001e4977b91SSrinivas Kandagatla if (!control || !control->w) 1002e4977b91SSrinivas Kandagatla return 0; 1003e4977b91SSrinivas Kandagatla 1004e4977b91SSrinivas Kandagatla w = control->w; 1005e4977b91SSrinivas Kandagatla 1006e4977b91SSrinivas Kandagatla for (i = 0; i < w->num_kcontrols; i++) { 1007e4977b91SSrinivas Kandagatla if (!strcmp(route->control, w->kcontrol_news[i].name)) { 1008e4977b91SSrinivas Kandagatla struct soc_mixer_control *sm; 1009e4977b91SSrinivas Kandagatla struct snd_soc_dobj *dobj; 1010e4977b91SSrinivas Kandagatla struct snd_ar_control *scontrol; 1011e4977b91SSrinivas Kandagatla 1012e4977b91SSrinivas Kandagatla sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value; 1013e4977b91SSrinivas Kandagatla dobj = &sm->dobj; 1014e4977b91SSrinivas Kandagatla scontrol = dobj->private; 1015e4977b91SSrinivas Kandagatla scontrol->module_instance_id = src_module->instance_id; 1016e4977b91SSrinivas Kandagatla } 1017e4977b91SSrinivas Kandagatla } 1018e4977b91SSrinivas Kandagatla 101936ad9bf1SSrinivas Kandagatla } 102036ad9bf1SSrinivas Kandagatla 102136ad9bf1SSrinivas Kandagatla return 0; 102236ad9bf1SSrinivas Kandagatla } 102336ad9bf1SSrinivas Kandagatla 102436ad9bf1SSrinivas Kandagatla static int audioreach_route_unload(struct snd_soc_component *scomp, 102536ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 102636ad9bf1SSrinivas Kandagatla { 102736ad9bf1SSrinivas Kandagatla return 0; 102836ad9bf1SSrinivas Kandagatla } 102936ad9bf1SSrinivas Kandagatla 103036ad9bf1SSrinivas Kandagatla static int audioreach_tplg_complete(struct snd_soc_component *component) 103136ad9bf1SSrinivas Kandagatla { 103236ad9bf1SSrinivas Kandagatla /* TBD */ 103336ad9bf1SSrinivas Kandagatla return 0; 103436ad9bf1SSrinivas Kandagatla } 103536ad9bf1SSrinivas Kandagatla 103636ad9bf1SSrinivas Kandagatla /* DAI link - used for any driver specific init */ 103736ad9bf1SSrinivas Kandagatla static int audioreach_link_load(struct snd_soc_component *component, int index, 103836ad9bf1SSrinivas Kandagatla struct snd_soc_dai_link *link, 103936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_link_config *cfg) 104036ad9bf1SSrinivas Kandagatla { 104136ad9bf1SSrinivas Kandagatla link->nonatomic = true; 104236ad9bf1SSrinivas Kandagatla link->dynamic = true; 104336ad9bf1SSrinivas Kandagatla link->platforms->name = NULL; 104436ad9bf1SSrinivas Kandagatla link->platforms->of_node = of_get_compatible_child(component->dev->of_node, 104536ad9bf1SSrinivas Kandagatla "qcom,q6apm-dais"); 104636ad9bf1SSrinivas Kandagatla return 0; 104736ad9bf1SSrinivas Kandagatla } 104836ad9bf1SSrinivas Kandagatla 1049e4977b91SSrinivas Kandagatla static void audioreach_connect_sub_graphs(struct q6apm *apm, 1050e4977b91SSrinivas Kandagatla struct snd_ar_control *m1, 1051e4977b91SSrinivas Kandagatla struct snd_ar_control *m2, 1052e4977b91SSrinivas Kandagatla bool connect) 1053e4977b91SSrinivas Kandagatla { 1054e4977b91SSrinivas Kandagatla struct audioreach_graph_info *info; 1055e4977b91SSrinivas Kandagatla 1056e4977b91SSrinivas Kandagatla mutex_lock(&apm->lock); 1057e4977b91SSrinivas Kandagatla info = idr_find(&apm->graph_info_idr, m2->graph_id); 1058e4977b91SSrinivas Kandagatla mutex_unlock(&apm->lock); 1059e4977b91SSrinivas Kandagatla 1060e4977b91SSrinivas Kandagatla if (connect) { 1061e4977b91SSrinivas Kandagatla info->src_mod_inst_id = m1->module_instance_id; 1062e4977b91SSrinivas Kandagatla info->src_mod_op_port_id = 1; 1063e4977b91SSrinivas Kandagatla info->dst_mod_inst_id = m2->module_instance_id; 1064e4977b91SSrinivas Kandagatla info->dst_mod_ip_port_id = 2; 1065e4977b91SSrinivas Kandagatla 1066e4977b91SSrinivas Kandagatla } else { 1067e4977b91SSrinivas Kandagatla info->src_mod_inst_id = 0; 1068e4977b91SSrinivas Kandagatla info->src_mod_op_port_id = 0; 1069e4977b91SSrinivas Kandagatla info->dst_mod_inst_id = 0; 1070e4977b91SSrinivas Kandagatla info->dst_mod_ip_port_id = 0; 1071e4977b91SSrinivas Kandagatla } 1072e4977b91SSrinivas Kandagatla } 1073e4977b91SSrinivas Kandagatla 1074e4977b91SSrinivas Kandagatla static bool audioreach_is_vmixer_connected(struct q6apm *apm, 1075e4977b91SSrinivas Kandagatla struct snd_ar_control *m1, 1076e4977b91SSrinivas Kandagatla struct snd_ar_control *m2) 1077e4977b91SSrinivas Kandagatla { 1078e4977b91SSrinivas Kandagatla struct audioreach_graph_info *info; 1079e4977b91SSrinivas Kandagatla 1080e4977b91SSrinivas Kandagatla mutex_lock(&apm->lock); 1081e4977b91SSrinivas Kandagatla info = idr_find(&apm->graph_info_idr, m2->graph_id); 1082e4977b91SSrinivas Kandagatla mutex_unlock(&apm->lock); 1083e4977b91SSrinivas Kandagatla 1084e4977b91SSrinivas Kandagatla if (info->dst_mod_inst_id == m2->module_instance_id && 1085e4977b91SSrinivas Kandagatla info->src_mod_inst_id == m1->module_instance_id) 1086e4977b91SSrinivas Kandagatla return true; 1087e4977b91SSrinivas Kandagatla 1088e4977b91SSrinivas Kandagatla return false; 1089e4977b91SSrinivas Kandagatla } 1090e4977b91SSrinivas Kandagatla 109136ad9bf1SSrinivas Kandagatla static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol, 109236ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 109336ad9bf1SSrinivas Kandagatla { 109436ad9bf1SSrinivas Kandagatla struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 109536ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 109636ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 109736ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 109836ad9bf1SSrinivas Kandagatla struct snd_ar_control *dapm_scontrol = dw->dobj.private; 109936ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = mc->dobj.private; 110036ad9bf1SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(c->dev); 110136ad9bf1SSrinivas Kandagatla bool connected; 110236ad9bf1SSrinivas Kandagatla 1103e4977b91SSrinivas Kandagatla connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol); 110436ad9bf1SSrinivas Kandagatla if (connected) 110536ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = 1; 110636ad9bf1SSrinivas Kandagatla else 110736ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = 0; 110836ad9bf1SSrinivas Kandagatla 110936ad9bf1SSrinivas Kandagatla return 0; 111036ad9bf1SSrinivas Kandagatla } 111136ad9bf1SSrinivas Kandagatla 111236ad9bf1SSrinivas Kandagatla static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol, 111336ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 111436ad9bf1SSrinivas Kandagatla { 111536ad9bf1SSrinivas Kandagatla struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 111636ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 111736ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 111836ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 111936ad9bf1SSrinivas Kandagatla struct snd_ar_control *dapm_scontrol = dw->dobj.private; 112036ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = mc->dobj.private; 112136ad9bf1SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(c->dev); 112236ad9bf1SSrinivas Kandagatla 112336ad9bf1SSrinivas Kandagatla if (ucontrol->value.integer.value[0]) { 1124e4977b91SSrinivas Kandagatla audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true); 112536ad9bf1SSrinivas Kandagatla snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL); 112636ad9bf1SSrinivas Kandagatla } else { 1127e4977b91SSrinivas Kandagatla audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false); 112836ad9bf1SSrinivas Kandagatla snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL); 112936ad9bf1SSrinivas Kandagatla } 113036ad9bf1SSrinivas Kandagatla return 0; 113136ad9bf1SSrinivas Kandagatla } 113236ad9bf1SSrinivas Kandagatla 113336ad9bf1SSrinivas Kandagatla static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 113436ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 113536ad9bf1SSrinivas Kandagatla { 113636ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 113736ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = dw->dobj.private; 113836ad9bf1SSrinivas Kandagatla 113936ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = mod->gain; 114036ad9bf1SSrinivas Kandagatla 114136ad9bf1SSrinivas Kandagatla return 0; 114236ad9bf1SSrinivas Kandagatla } 114336ad9bf1SSrinivas Kandagatla 114436ad9bf1SSrinivas Kandagatla static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 114536ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 114636ad9bf1SSrinivas Kandagatla { 114736ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 114836ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = dw->dobj.private; 114936ad9bf1SSrinivas Kandagatla 115036ad9bf1SSrinivas Kandagatla mod->gain = ucontrol->value.integer.value[0]; 115136ad9bf1SSrinivas Kandagatla 115236ad9bf1SSrinivas Kandagatla return 1; 115336ad9bf1SSrinivas Kandagatla } 115436ad9bf1SSrinivas Kandagatla 115536ad9bf1SSrinivas Kandagatla static int audioreach_control_load_mix(struct snd_soc_component *scomp, 115636ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol, 115736ad9bf1SSrinivas Kandagatla struct snd_kcontrol_new *kc, 115836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_ctl_hdr *hdr) 115936ad9bf1SSrinivas Kandagatla { 116036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *c_elem; 116136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *c_array; 116236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_mixer_control *mc; 116336ad9bf1SSrinivas Kandagatla int tkn_count = 0; 116436ad9bf1SSrinivas Kandagatla 116536ad9bf1SSrinivas Kandagatla mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); 116636ad9bf1SSrinivas Kandagatla c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data; 116736ad9bf1SSrinivas Kandagatla 116836ad9bf1SSrinivas Kandagatla c_elem = c_array->value; 116936ad9bf1SSrinivas Kandagatla 117036ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) { 117136ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(c_elem->token)) { 117236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 117336ad9bf1SSrinivas Kandagatla scontrol->sgid = le32_to_cpu(c_elem->value); 117436ad9bf1SSrinivas Kandagatla break; 11751c87d381SSrinivas Kandagatla case AR_TKN_DAI_INDEX: 11761c87d381SSrinivas Kandagatla scontrol->graph_id = le32_to_cpu(c_elem->value); 11771c87d381SSrinivas Kandagatla break; 117836ad9bf1SSrinivas Kandagatla default: 117936ad9bf1SSrinivas Kandagatla /* Ignore other tokens */ 118036ad9bf1SSrinivas Kandagatla break; 118136ad9bf1SSrinivas Kandagatla } 118236ad9bf1SSrinivas Kandagatla c_elem++; 118336ad9bf1SSrinivas Kandagatla tkn_count++; 118436ad9bf1SSrinivas Kandagatla } 118536ad9bf1SSrinivas Kandagatla 118636ad9bf1SSrinivas Kandagatla return 0; 118736ad9bf1SSrinivas Kandagatla } 118836ad9bf1SSrinivas Kandagatla 118936ad9bf1SSrinivas Kandagatla static int audioreach_control_load(struct snd_soc_component *scomp, int index, 119036ad9bf1SSrinivas Kandagatla struct snd_kcontrol_new *kc, 119136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_ctl_hdr *hdr) 119236ad9bf1SSrinivas Kandagatla { 119336ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol; 119436ad9bf1SSrinivas Kandagatla struct soc_mixer_control *sm; 119536ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 119636ad9bf1SSrinivas Kandagatla int ret = 0; 119736ad9bf1SSrinivas Kandagatla 119836ad9bf1SSrinivas Kandagatla scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 119936ad9bf1SSrinivas Kandagatla if (!scontrol) 120036ad9bf1SSrinivas Kandagatla return -ENOMEM; 120136ad9bf1SSrinivas Kandagatla 120236ad9bf1SSrinivas Kandagatla scontrol->scomp = scomp; 120336ad9bf1SSrinivas Kandagatla 120436ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(hdr->ops.get)) { 120536ad9bf1SSrinivas Kandagatla case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX: 120636ad9bf1SSrinivas Kandagatla sm = (struct soc_mixer_control *)kc->private_value; 120736ad9bf1SSrinivas Kandagatla dobj = &sm->dobj; 120836ad9bf1SSrinivas Kandagatla ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr); 120936ad9bf1SSrinivas Kandagatla break; 121036ad9bf1SSrinivas Kandagatla case SND_SOC_AR_TPLG_VOL_CTL: 121136ad9bf1SSrinivas Kandagatla sm = (struct soc_mixer_control *)kc->private_value; 121236ad9bf1SSrinivas Kandagatla dobj = &sm->dobj; 121336ad9bf1SSrinivas Kandagatla break; 121436ad9bf1SSrinivas Kandagatla default: 121536ad9bf1SSrinivas Kandagatla dev_warn(scomp->dev, "control type not supported %d:%d:%d\n", 121636ad9bf1SSrinivas Kandagatla hdr->ops.get, hdr->ops.put, hdr->ops.info); 121736ad9bf1SSrinivas Kandagatla kfree(scontrol); 121836ad9bf1SSrinivas Kandagatla return -EINVAL; 121936ad9bf1SSrinivas Kandagatla } 122036ad9bf1SSrinivas Kandagatla 122136ad9bf1SSrinivas Kandagatla dobj->private = scontrol; 122236ad9bf1SSrinivas Kandagatla return ret; 122336ad9bf1SSrinivas Kandagatla } 122436ad9bf1SSrinivas Kandagatla 122536ad9bf1SSrinivas Kandagatla static int audioreach_control_unload(struct snd_soc_component *scomp, 122636ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 122736ad9bf1SSrinivas Kandagatla { 122836ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = dobj->private; 122936ad9bf1SSrinivas Kandagatla 123036ad9bf1SSrinivas Kandagatla kfree(scontrol); 123136ad9bf1SSrinivas Kandagatla 123236ad9bf1SSrinivas Kandagatla return 0; 123336ad9bf1SSrinivas Kandagatla } 123436ad9bf1SSrinivas Kandagatla 123536ad9bf1SSrinivas Kandagatla static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = { 123636ad9bf1SSrinivas Kandagatla {SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer, 123736ad9bf1SSrinivas Kandagatla audioreach_put_audio_mixer, snd_soc_info_volsw}, 123836ad9bf1SSrinivas Kandagatla {SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer, 123936ad9bf1SSrinivas Kandagatla audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw}, 124036ad9bf1SSrinivas Kandagatla }; 124136ad9bf1SSrinivas Kandagatla 124236ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_ops audioreach_tplg_ops = { 124336ad9bf1SSrinivas Kandagatla .io_ops = audioreach_io_ops, 124436ad9bf1SSrinivas Kandagatla .io_ops_count = ARRAY_SIZE(audioreach_io_ops), 124536ad9bf1SSrinivas Kandagatla 124636ad9bf1SSrinivas Kandagatla .control_load = audioreach_control_load, 124736ad9bf1SSrinivas Kandagatla .control_unload = audioreach_control_unload, 124836ad9bf1SSrinivas Kandagatla 124936ad9bf1SSrinivas Kandagatla .widget_ready = audioreach_widget_ready, 125036ad9bf1SSrinivas Kandagatla .widget_unload = audioreach_widget_unload, 125136ad9bf1SSrinivas Kandagatla 125236ad9bf1SSrinivas Kandagatla .complete = audioreach_tplg_complete, 125336ad9bf1SSrinivas Kandagatla .link_load = audioreach_link_load, 125436ad9bf1SSrinivas Kandagatla 125536ad9bf1SSrinivas Kandagatla .dapm_route_load = audioreach_route_load, 125636ad9bf1SSrinivas Kandagatla .dapm_route_unload = audioreach_route_unload, 125736ad9bf1SSrinivas Kandagatla }; 125836ad9bf1SSrinivas Kandagatla 125936ad9bf1SSrinivas Kandagatla int audioreach_tplg_init(struct snd_soc_component *component) 126036ad9bf1SSrinivas Kandagatla { 126136ad9bf1SSrinivas Kandagatla struct snd_soc_card *card = component->card; 126236ad9bf1SSrinivas Kandagatla struct device *dev = component->dev; 126336ad9bf1SSrinivas Kandagatla const struct firmware *fw; 126436ad9bf1SSrinivas Kandagatla char *tplg_fw_name; 126536ad9bf1SSrinivas Kandagatla int ret; 126636ad9bf1SSrinivas Kandagatla 126736ad9bf1SSrinivas Kandagatla /* Inline with Qualcomm UCM configs and linux-firmware path */ 126836ad9bf1SSrinivas Kandagatla tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name); 126936ad9bf1SSrinivas Kandagatla if (!tplg_fw_name) 127036ad9bf1SSrinivas Kandagatla return -ENOMEM; 127136ad9bf1SSrinivas Kandagatla 127236ad9bf1SSrinivas Kandagatla ret = request_firmware(&fw, tplg_fw_name, dev); 127336ad9bf1SSrinivas Kandagatla if (ret < 0) { 127436ad9bf1SSrinivas Kandagatla dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); 127536ad9bf1SSrinivas Kandagatla goto err; 127636ad9bf1SSrinivas Kandagatla } 127736ad9bf1SSrinivas Kandagatla 127836ad9bf1SSrinivas Kandagatla ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw); 127936ad9bf1SSrinivas Kandagatla if (ret < 0) { 128036ad9bf1SSrinivas Kandagatla dev_err(dev, "tplg component load failed%d\n", ret); 128136ad9bf1SSrinivas Kandagatla ret = -EINVAL; 128236ad9bf1SSrinivas Kandagatla } 128336ad9bf1SSrinivas Kandagatla 128436ad9bf1SSrinivas Kandagatla release_firmware(fw); 128536ad9bf1SSrinivas Kandagatla err: 128636ad9bf1SSrinivas Kandagatla kfree(tplg_fw_name); 128736ad9bf1SSrinivas Kandagatla 128836ad9bf1SSrinivas Kandagatla return ret; 128936ad9bf1SSrinivas Kandagatla } 129036ad9bf1SSrinivas Kandagatla EXPORT_SYMBOL_GPL(audioreach_tplg_init); 1291