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; 41536ad9bf1SSrinivas Kandagatla uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0; 41636ad9bf1SSrinivas Kandagatla uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0; 41736ad9bf1SSrinivas Kandagatla int module_id = 0, instance_id = 0, tkn_count = 0; 41836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 41936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 42036ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = NULL; 42136ad9bf1SSrinivas Kandagatla bool found; 42236ad9bf1SSrinivas Kandagatla 42336ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(private); 42436ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 42536ad9bf1SSrinivas Kandagatla 42636ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 42736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 42836ad9bf1SSrinivas Kandagatla /* common module info */ 42936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_ID: 43036ad9bf1SSrinivas Kandagatla module_id = le32_to_cpu(mod_elem->value); 43136ad9bf1SSrinivas Kandagatla break; 43236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_INSTANCE_ID: 43336ad9bf1SSrinivas Kandagatla instance_id = le32_to_cpu(mod_elem->value); 43436ad9bf1SSrinivas Kandagatla mod = audioreach_tplg_alloc_module(apm, cont, w, 43536ad9bf1SSrinivas Kandagatla instance_id, &found); 43636ad9bf1SSrinivas Kandagatla if (IS_ERR(mod)) { 43736ad9bf1SSrinivas Kandagatla return mod; 43836ad9bf1SSrinivas Kandagatla } else if (found) { 43936ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n", 44036ad9bf1SSrinivas Kandagatla instance_id); 44136ad9bf1SSrinivas Kandagatla return ERR_PTR(-EINVAL); 44236ad9bf1SSrinivas Kandagatla } 44336ad9bf1SSrinivas Kandagatla 44436ad9bf1SSrinivas Kandagatla break; 44536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_MAX_IP_PORTS: 44636ad9bf1SSrinivas Kandagatla max_ip_port = le32_to_cpu(mod_elem->value); 44736ad9bf1SSrinivas Kandagatla break; 44836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_MAX_OP_PORTS: 44936ad9bf1SSrinivas Kandagatla max_op_port = le32_to_cpu(mod_elem->value); 45036ad9bf1SSrinivas Kandagatla break; 45136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_IN_PORTS: 45236ad9bf1SSrinivas Kandagatla in_port = le32_to_cpu(mod_elem->value); 45336ad9bf1SSrinivas Kandagatla break; 45436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_OUT_PORTS: 45536ad9bf1SSrinivas Kandagatla out_port = le32_to_cpu(mod_elem->value); 45636ad9bf1SSrinivas Kandagatla break; 45736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID: 45836ad9bf1SSrinivas Kandagatla src_mod_op_port_id = le32_to_cpu(mod_elem->value); 45936ad9bf1SSrinivas Kandagatla break; 46036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_INSTANCE_ID: 46136ad9bf1SSrinivas Kandagatla src_mod_inst_id = le32_to_cpu(mod_elem->value); 46236ad9bf1SSrinivas Kandagatla break; 46336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID: 46436ad9bf1SSrinivas Kandagatla dst_mod_inst_id = le32_to_cpu(mod_elem->value); 46536ad9bf1SSrinivas Kandagatla break; 46636ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID: 46736ad9bf1SSrinivas Kandagatla dst_mod_ip_port_id = le32_to_cpu(mod_elem->value); 468c6c203bcSNathan Chancellor break; 46936ad9bf1SSrinivas Kandagatla default: 47036ad9bf1SSrinivas Kandagatla break; 47136ad9bf1SSrinivas Kandagatla 47236ad9bf1SSrinivas Kandagatla } 47336ad9bf1SSrinivas Kandagatla tkn_count++; 47436ad9bf1SSrinivas Kandagatla mod_elem++; 47536ad9bf1SSrinivas Kandagatla } 47636ad9bf1SSrinivas Kandagatla 47736ad9bf1SSrinivas Kandagatla if (mod) { 47836ad9bf1SSrinivas Kandagatla mod->module_id = module_id; 47936ad9bf1SSrinivas Kandagatla mod->max_ip_port = max_ip_port; 48036ad9bf1SSrinivas Kandagatla mod->max_op_port = max_op_port; 48136ad9bf1SSrinivas Kandagatla mod->in_port = in_port; 48236ad9bf1SSrinivas Kandagatla mod->out_port = out_port; 48336ad9bf1SSrinivas Kandagatla mod->src_mod_inst_id = src_mod_inst_id; 48436ad9bf1SSrinivas Kandagatla mod->src_mod_op_port_id = src_mod_op_port_id; 48536ad9bf1SSrinivas Kandagatla mod->dst_mod_inst_id = dst_mod_inst_id; 48636ad9bf1SSrinivas Kandagatla mod->dst_mod_ip_port_id = dst_mod_ip_port_id; 48736ad9bf1SSrinivas Kandagatla } 48836ad9bf1SSrinivas Kandagatla 48936ad9bf1SSrinivas Kandagatla return mod; 49036ad9bf1SSrinivas Kandagatla } 49136ad9bf1SSrinivas Kandagatla 49236ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_module_common(struct snd_soc_component *component, 49336ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 49436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 49536ad9bf1SSrinivas Kandagatla { 49636ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(component->dev); 49736ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 49836ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg; 49936ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 50036ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 50136ad9bf1SSrinivas Kandagatla 50236ad9bf1SSrinivas Kandagatla sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv); 50336ad9bf1SSrinivas Kandagatla if (IS_ERR(sg)) 50436ad9bf1SSrinivas Kandagatla return PTR_ERR(sg); 50536ad9bf1SSrinivas Kandagatla 50636ad9bf1SSrinivas Kandagatla cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv); 50736ad9bf1SSrinivas Kandagatla if (IS_ERR(cont)) 50836ad9bf1SSrinivas Kandagatla return PTR_ERR(cont); 50936ad9bf1SSrinivas Kandagatla 51036ad9bf1SSrinivas Kandagatla mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w); 51136ad9bf1SSrinivas Kandagatla if (IS_ERR(mod)) 51236ad9bf1SSrinivas Kandagatla return PTR_ERR(mod); 51336ad9bf1SSrinivas Kandagatla 51436ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 51536ad9bf1SSrinivas Kandagatla dobj->private = mod; 51636ad9bf1SSrinivas Kandagatla 51736ad9bf1SSrinivas Kandagatla return 0; 51836ad9bf1SSrinivas Kandagatla } 51936ad9bf1SSrinivas Kandagatla 52036ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component, 52136ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 52236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 52336ad9bf1SSrinivas Kandagatla { 52436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 52536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 52636ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 52736ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 52836ad9bf1SSrinivas Kandagatla int tkn_count = 0; 52936ad9bf1SSrinivas Kandagatla int ret; 53036ad9bf1SSrinivas Kandagatla 53136ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 53236ad9bf1SSrinivas Kandagatla if (ret) 53336ad9bf1SSrinivas Kandagatla return ret; 53436ad9bf1SSrinivas Kandagatla 53536ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 53636ad9bf1SSrinivas Kandagatla mod = dobj->private; 53736ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(&tplg_w->priv); 53836ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 53936ad9bf1SSrinivas Kandagatla 54036ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 54136ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 54236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_INTERLEAVE: 54336ad9bf1SSrinivas Kandagatla mod->interleave_type = le32_to_cpu(mod_elem->value); 54436ad9bf1SSrinivas Kandagatla break; 54536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE: 54636ad9bf1SSrinivas Kandagatla mod->rate = le32_to_cpu(mod_elem->value); 54736ad9bf1SSrinivas Kandagatla break; 54836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_BIT_DEPTH: 54936ad9bf1SSrinivas Kandagatla mod->bit_depth = le32_to_cpu(mod_elem->value); 55036ad9bf1SSrinivas Kandagatla break; 55136ad9bf1SSrinivas Kandagatla default: 55236ad9bf1SSrinivas Kandagatla break; 55336ad9bf1SSrinivas Kandagatla } 55436ad9bf1SSrinivas Kandagatla tkn_count++; 55536ad9bf1SSrinivas Kandagatla mod_elem++; 55636ad9bf1SSrinivas Kandagatla } 55736ad9bf1SSrinivas Kandagatla 55836ad9bf1SSrinivas Kandagatla return 0; 55936ad9bf1SSrinivas Kandagatla } 56036ad9bf1SSrinivas Kandagatla 56136ad9bf1SSrinivas Kandagatla static int audioreach_widget_log_module_load(struct audioreach_module *mod, 56236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 56336ad9bf1SSrinivas Kandagatla { 56436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 56536ad9bf1SSrinivas Kandagatla int tkn_count = 0; 56636ad9bf1SSrinivas Kandagatla 56736ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 56836ad9bf1SSrinivas Kandagatla 56936ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 57036ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 57136ad9bf1SSrinivas Kandagatla 57236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_CODE: 57336ad9bf1SSrinivas Kandagatla mod->log_code = le32_to_cpu(mod_elem->value); 57436ad9bf1SSrinivas Kandagatla break; 57536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID: 57636ad9bf1SSrinivas Kandagatla mod->log_tap_point_id = le32_to_cpu(mod_elem->value); 57736ad9bf1SSrinivas Kandagatla break; 57836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_MODE: 57936ad9bf1SSrinivas Kandagatla mod->log_mode = le32_to_cpu(mod_elem->value); 58036ad9bf1SSrinivas Kandagatla break; 58136ad9bf1SSrinivas Kandagatla default: 58236ad9bf1SSrinivas Kandagatla break; 58336ad9bf1SSrinivas Kandagatla } 58436ad9bf1SSrinivas Kandagatla tkn_count++; 58536ad9bf1SSrinivas Kandagatla mod_elem++; 58636ad9bf1SSrinivas Kandagatla } 58736ad9bf1SSrinivas Kandagatla 58836ad9bf1SSrinivas Kandagatla return 0; 58936ad9bf1SSrinivas Kandagatla } 59036ad9bf1SSrinivas Kandagatla 59136ad9bf1SSrinivas Kandagatla static int audioreach_widget_dma_module_load(struct audioreach_module *mod, 59236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 59336ad9bf1SSrinivas Kandagatla { 59436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 59536ad9bf1SSrinivas Kandagatla int tkn_count = 0; 59636ad9bf1SSrinivas Kandagatla 59736ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 59836ad9bf1SSrinivas Kandagatla 59936ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 60036ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 60136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_IDX: 60236ad9bf1SSrinivas Kandagatla mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 60336ad9bf1SSrinivas Kandagatla break; 60436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_DATA: 60536ad9bf1SSrinivas Kandagatla mod->data_format = le32_to_cpu(mod_elem->value); 60636ad9bf1SSrinivas Kandagatla break; 60736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_TYPE: 60836ad9bf1SSrinivas Kandagatla mod->hw_interface_type = le32_to_cpu(mod_elem->value); 60936ad9bf1SSrinivas Kandagatla break; 61036ad9bf1SSrinivas Kandagatla default: 61136ad9bf1SSrinivas Kandagatla break; 61236ad9bf1SSrinivas Kandagatla } 61336ad9bf1SSrinivas Kandagatla tkn_count++; 61436ad9bf1SSrinivas Kandagatla mod_elem++; 61536ad9bf1SSrinivas Kandagatla } 61636ad9bf1SSrinivas Kandagatla 61736ad9bf1SSrinivas Kandagatla return 0; 61836ad9bf1SSrinivas Kandagatla } 61936ad9bf1SSrinivas Kandagatla 62036ad9bf1SSrinivas Kandagatla static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, 62136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 62236ad9bf1SSrinivas Kandagatla { 62336ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 62436ad9bf1SSrinivas Kandagatla int tkn_count = 0; 62536ad9bf1SSrinivas Kandagatla 62636ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 62736ad9bf1SSrinivas Kandagatla 62836ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 62936ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 63036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_IDX: 63136ad9bf1SSrinivas Kandagatla mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 63236ad9bf1SSrinivas Kandagatla break; 63336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_DATA: 63436ad9bf1SSrinivas Kandagatla mod->data_format = le32_to_cpu(mod_elem->value); 63536ad9bf1SSrinivas Kandagatla break; 63636ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_TYPE: 63736ad9bf1SSrinivas Kandagatla mod->hw_interface_type = le32_to_cpu(mod_elem->value); 63836ad9bf1SSrinivas Kandagatla break; 63936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SD_LINE_IDX: 64036ad9bf1SSrinivas Kandagatla mod->sd_line_idx = le32_to_cpu(mod_elem->value); 64136ad9bf1SSrinivas Kandagatla break; 64236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_WS_SRC: 64336ad9bf1SSrinivas Kandagatla mod->ws_src = le32_to_cpu(mod_elem->value); 64436ad9bf1SSrinivas Kandagatla break; 64536ad9bf1SSrinivas Kandagatla default: 64636ad9bf1SSrinivas Kandagatla break; 64736ad9bf1SSrinivas Kandagatla } 64836ad9bf1SSrinivas Kandagatla tkn_count++; 64936ad9bf1SSrinivas Kandagatla mod_elem++; 65036ad9bf1SSrinivas Kandagatla } 65136ad9bf1SSrinivas Kandagatla 65236ad9bf1SSrinivas Kandagatla return 0; 65336ad9bf1SSrinivas Kandagatla } 65436ad9bf1SSrinivas Kandagatla 65536ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_buffer(struct snd_soc_component *component, 65636ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 65736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 65836ad9bf1SSrinivas Kandagatla { 65936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 66036ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 66136ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 66236ad9bf1SSrinivas Kandagatla int ret; 66336ad9bf1SSrinivas Kandagatla 66436ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 66536ad9bf1SSrinivas Kandagatla if (ret) 66636ad9bf1SSrinivas Kandagatla return ret; 66736ad9bf1SSrinivas Kandagatla 66836ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 66936ad9bf1SSrinivas Kandagatla mod = dobj->private; 67036ad9bf1SSrinivas Kandagatla 67136ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(&tplg_w->priv); 67236ad9bf1SSrinivas Kandagatla 67336ad9bf1SSrinivas Kandagatla switch (mod->module_id) { 67436ad9bf1SSrinivas Kandagatla case MODULE_ID_CODEC_DMA_SINK: 67536ad9bf1SSrinivas Kandagatla case MODULE_ID_CODEC_DMA_SOURCE: 67636ad9bf1SSrinivas Kandagatla audioreach_widget_dma_module_load(mod, mod_array); 67736ad9bf1SSrinivas Kandagatla break; 67836ad9bf1SSrinivas Kandagatla case MODULE_ID_DATA_LOGGING: 67936ad9bf1SSrinivas Kandagatla audioreach_widget_log_module_load(mod, mod_array); 68036ad9bf1SSrinivas Kandagatla break; 68136ad9bf1SSrinivas Kandagatla case MODULE_ID_I2S_SINK: 68236ad9bf1SSrinivas Kandagatla case MODULE_ID_I2S_SOURCE: 68336ad9bf1SSrinivas Kandagatla audioreach_widget_i2s_module_load(mod, mod_array); 68436ad9bf1SSrinivas Kandagatla break; 68536ad9bf1SSrinivas Kandagatla default: 68636ad9bf1SSrinivas Kandagatla return -EINVAL; 68736ad9bf1SSrinivas Kandagatla } 68836ad9bf1SSrinivas Kandagatla 68936ad9bf1SSrinivas Kandagatla return 0; 69036ad9bf1SSrinivas Kandagatla } 69136ad9bf1SSrinivas Kandagatla 69236ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_mixer(struct snd_soc_component *component, 69336ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 69436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 69536ad9bf1SSrinivas Kandagatla { 69636ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *w_elem; 69736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *w_array; 69836ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol; 6991c87d381SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(component->dev); 70036ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 70136ad9bf1SSrinivas Kandagatla int tkn_count = 0; 70236ad9bf1SSrinivas Kandagatla 70336ad9bf1SSrinivas Kandagatla w_array = &tplg_w->priv.array[0]; 70436ad9bf1SSrinivas Kandagatla 70536ad9bf1SSrinivas Kandagatla scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 70636ad9bf1SSrinivas Kandagatla if (!scontrol) 70736ad9bf1SSrinivas Kandagatla return -ENOMEM; 70836ad9bf1SSrinivas Kandagatla 70936ad9bf1SSrinivas Kandagatla scontrol->scomp = component; 71036ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 71136ad9bf1SSrinivas Kandagatla dobj->private = scontrol; 71236ad9bf1SSrinivas Kandagatla 71336ad9bf1SSrinivas Kandagatla w_elem = w_array->value; 71436ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) { 71536ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(w_elem->token)) { 71636ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 71736ad9bf1SSrinivas Kandagatla scontrol->sgid = le32_to_cpu(w_elem->value); 71836ad9bf1SSrinivas Kandagatla break; 7191c87d381SSrinivas Kandagatla case AR_TKN_DAI_INDEX: 7201c87d381SSrinivas Kandagatla scontrol->graph_id = le32_to_cpu(w_elem->value); 7211c87d381SSrinivas Kandagatla break; 72236ad9bf1SSrinivas Kandagatla default: /* ignore other tokens */ 72336ad9bf1SSrinivas Kandagatla break; 72436ad9bf1SSrinivas Kandagatla } 72536ad9bf1SSrinivas Kandagatla tkn_count++; 72636ad9bf1SSrinivas Kandagatla w_elem++; 72736ad9bf1SSrinivas Kandagatla } 72836ad9bf1SSrinivas Kandagatla 7291c87d381SSrinivas Kandagatla scontrol->w = w; 7301c87d381SSrinivas Kandagatla list_add_tail(&scontrol->node, &data->widget_list); 7311c87d381SSrinivas Kandagatla 73236ad9bf1SSrinivas Kandagatla return 0; 73336ad9bf1SSrinivas Kandagatla } 73436ad9bf1SSrinivas Kandagatla 73536ad9bf1SSrinivas Kandagatla static int audioreach_pga_event(struct snd_soc_dapm_widget *w, 73636ad9bf1SSrinivas Kandagatla struct snd_kcontrol *kcontrol, int event) 73736ad9bf1SSrinivas Kandagatla 73836ad9bf1SSrinivas Kandagatla { 73936ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = w->dapm; 74036ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 74136ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = w->dobj.private; 74236ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(c->dev); 74336ad9bf1SSrinivas Kandagatla 74436ad9bf1SSrinivas Kandagatla switch (event) { 74536ad9bf1SSrinivas Kandagatla case SND_SOC_DAPM_POST_PMU: 74636ad9bf1SSrinivas Kandagatla /* apply gain after power up of widget */ 74736ad9bf1SSrinivas Kandagatla audioreach_gain_set_vol_ctrl(apm, mod, mod->gain); 74836ad9bf1SSrinivas Kandagatla break; 74936ad9bf1SSrinivas Kandagatla default: 75036ad9bf1SSrinivas Kandagatla break; 75136ad9bf1SSrinivas Kandagatla } 75236ad9bf1SSrinivas Kandagatla 75336ad9bf1SSrinivas Kandagatla return 0; 75436ad9bf1SSrinivas Kandagatla } 75536ad9bf1SSrinivas Kandagatla 75636ad9bf1SSrinivas Kandagatla static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = { 75736ad9bf1SSrinivas Kandagatla { AR_PGA_DAPM_EVENT, audioreach_pga_event }, 75836ad9bf1SSrinivas Kandagatla }; 75936ad9bf1SSrinivas Kandagatla 76036ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_pga(struct snd_soc_component *component, 76136ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 76236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 76336ad9bf1SSrinivas Kandagatla { 76436ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 76536ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 76636ad9bf1SSrinivas Kandagatla int ret; 76736ad9bf1SSrinivas Kandagatla 76836ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 76936ad9bf1SSrinivas Kandagatla if (ret) 77036ad9bf1SSrinivas Kandagatla return ret; 77136ad9bf1SSrinivas Kandagatla 77236ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 77336ad9bf1SSrinivas Kandagatla mod = dobj->private; 77436ad9bf1SSrinivas Kandagatla mod->gain = VOL_CTRL_DEFAULT_GAIN; 77536ad9bf1SSrinivas Kandagatla 77636ad9bf1SSrinivas Kandagatla ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops, 77736ad9bf1SSrinivas Kandagatla ARRAY_SIZE(audioreach_widget_ops), 77836ad9bf1SSrinivas Kandagatla le16_to_cpu(tplg_w->event_type)); 77936ad9bf1SSrinivas Kandagatla if (ret) { 78036ad9bf1SSrinivas Kandagatla dev_err(component->dev, "matching event handlers NOT found for %d\n", 78136ad9bf1SSrinivas Kandagatla le16_to_cpu(tplg_w->event_type)); 78236ad9bf1SSrinivas Kandagatla return -EINVAL; 78336ad9bf1SSrinivas Kandagatla } 78436ad9bf1SSrinivas Kandagatla 78536ad9bf1SSrinivas Kandagatla return 0; 78636ad9bf1SSrinivas Kandagatla } 78736ad9bf1SSrinivas Kandagatla 78836ad9bf1SSrinivas Kandagatla static int audioreach_widget_ready(struct snd_soc_component *component, 78936ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 79036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 79136ad9bf1SSrinivas Kandagatla { 79236ad9bf1SSrinivas Kandagatla switch (w->id) { 79336ad9bf1SSrinivas Kandagatla case snd_soc_dapm_aif_in: 79436ad9bf1SSrinivas Kandagatla case snd_soc_dapm_aif_out: 79536ad9bf1SSrinivas Kandagatla audioreach_widget_load_buffer(component, index, w, tplg_w); 79636ad9bf1SSrinivas Kandagatla break; 79736ad9bf1SSrinivas Kandagatla case snd_soc_dapm_decoder: 79836ad9bf1SSrinivas Kandagatla case snd_soc_dapm_encoder: 79936ad9bf1SSrinivas Kandagatla case snd_soc_dapm_src: 80036ad9bf1SSrinivas Kandagatla audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w); 80136ad9bf1SSrinivas Kandagatla break; 80236ad9bf1SSrinivas Kandagatla case snd_soc_dapm_buffer: 80336ad9bf1SSrinivas Kandagatla audioreach_widget_load_buffer(component, index, w, tplg_w); 80436ad9bf1SSrinivas Kandagatla break; 80536ad9bf1SSrinivas Kandagatla case snd_soc_dapm_mixer: 80636ad9bf1SSrinivas Kandagatla return audioreach_widget_load_mixer(component, index, w, tplg_w); 80736ad9bf1SSrinivas Kandagatla case snd_soc_dapm_pga: 80836ad9bf1SSrinivas Kandagatla return audioreach_widget_load_pga(component, index, w, tplg_w); 80936ad9bf1SSrinivas Kandagatla case snd_soc_dapm_dai_link: 81036ad9bf1SSrinivas Kandagatla case snd_soc_dapm_scheduler: 81136ad9bf1SSrinivas Kandagatla case snd_soc_dapm_out_drv: 81236ad9bf1SSrinivas Kandagatla default: 81336ad9bf1SSrinivas Kandagatla dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id); 81436ad9bf1SSrinivas Kandagatla break; 81536ad9bf1SSrinivas Kandagatla } 81636ad9bf1SSrinivas Kandagatla 81736ad9bf1SSrinivas Kandagatla return 0; 81836ad9bf1SSrinivas Kandagatla } 81936ad9bf1SSrinivas Kandagatla 82036ad9bf1SSrinivas Kandagatla static int audioreach_widget_unload(struct snd_soc_component *scomp, 82136ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 82236ad9bf1SSrinivas Kandagatla { 82336ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj); 82436ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(scomp->dev); 82536ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 82636ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 82736ad9bf1SSrinivas Kandagatla 82836ad9bf1SSrinivas Kandagatla mod = dobj->private; 82936ad9bf1SSrinivas Kandagatla cont = mod->container; 83036ad9bf1SSrinivas Kandagatla 83136ad9bf1SSrinivas Kandagatla if (w->id == snd_soc_dapm_mixer) { 83236ad9bf1SSrinivas Kandagatla /* virtual widget */ 8331c87d381SSrinivas Kandagatla struct snd_ar_control *scontrol = dobj->private; 8341c87d381SSrinivas Kandagatla 8351c87d381SSrinivas Kandagatla list_del(&scontrol->node); 8361c87d381SSrinivas Kandagatla kfree(scontrol); 83736ad9bf1SSrinivas Kandagatla return 0; 83836ad9bf1SSrinivas Kandagatla } 83936ad9bf1SSrinivas Kandagatla 84036ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 84136ad9bf1SSrinivas Kandagatla idr_remove(&apm->modules_idr, mod->instance_id); 84236ad9bf1SSrinivas Kandagatla cont->num_modules--; 84336ad9bf1SSrinivas Kandagatla 84436ad9bf1SSrinivas Kandagatla list_del(&mod->node); 84536ad9bf1SSrinivas Kandagatla kfree(mod); 84636ad9bf1SSrinivas Kandagatla /* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */ 84736ad9bf1SSrinivas Kandagatla if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */ 84836ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg = cont->sub_graph; 84936ad9bf1SSrinivas Kandagatla 85036ad9bf1SSrinivas Kandagatla idr_remove(&apm->containers_idr, cont->container_id); 85136ad9bf1SSrinivas Kandagatla list_del(&cont->node); 85236ad9bf1SSrinivas Kandagatla sg->num_containers--; 85336ad9bf1SSrinivas Kandagatla kfree(cont); 85436ad9bf1SSrinivas Kandagatla /* check if there are no more containers in the sub graph and remove it */ 85536ad9bf1SSrinivas Kandagatla if (list_empty(&sg->container_list)) { 85636ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info = sg->info; 85736ad9bf1SSrinivas Kandagatla 85836ad9bf1SSrinivas Kandagatla idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id); 85936ad9bf1SSrinivas Kandagatla list_del(&sg->node); 86036ad9bf1SSrinivas Kandagatla info->num_sub_graphs--; 86136ad9bf1SSrinivas Kandagatla kfree(sg); 86236ad9bf1SSrinivas Kandagatla /* Check if there are no more sub-graphs left then remove graph info */ 86336ad9bf1SSrinivas Kandagatla if (list_empty(&info->sg_list)) { 86436ad9bf1SSrinivas Kandagatla idr_remove(&apm->graph_info_idr, info->id); 86536ad9bf1SSrinivas Kandagatla kfree(info); 86636ad9bf1SSrinivas Kandagatla } 86736ad9bf1SSrinivas Kandagatla } 86836ad9bf1SSrinivas Kandagatla } 86936ad9bf1SSrinivas Kandagatla 87036ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 87136ad9bf1SSrinivas Kandagatla 87236ad9bf1SSrinivas Kandagatla return 0; 87336ad9bf1SSrinivas Kandagatla } 87436ad9bf1SSrinivas Kandagatla 875*e4977b91SSrinivas Kandagatla static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp, 876*e4977b91SSrinivas Kandagatla const char *name) 877*e4977b91SSrinivas Kandagatla { 878*e4977b91SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(comp->dev); 879*e4977b91SSrinivas Kandagatla struct snd_ar_control *control; 880*e4977b91SSrinivas Kandagatla 881*e4977b91SSrinivas Kandagatla list_for_each_entry(control, &apm->widget_list, node) { 882*e4977b91SSrinivas Kandagatla if (control->w && !strcmp(name, control->w->name)) 883*e4977b91SSrinivas Kandagatla return control; 884*e4977b91SSrinivas Kandagatla } 885*e4977b91SSrinivas Kandagatla 886*e4977b91SSrinivas Kandagatla return NULL; 887*e4977b91SSrinivas Kandagatla } 888*e4977b91SSrinivas Kandagatla 889*e4977b91SSrinivas Kandagatla static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp, 89036ad9bf1SSrinivas Kandagatla const char *name) 89136ad9bf1SSrinivas Kandagatla { 89236ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(comp->dev); 89336ad9bf1SSrinivas Kandagatla struct audioreach_module *module; 89436ad9bf1SSrinivas Kandagatla int id; 89536ad9bf1SSrinivas Kandagatla 89636ad9bf1SSrinivas Kandagatla idr_for_each_entry(&apm->modules_idr, module, id) { 89736ad9bf1SSrinivas Kandagatla if (!strcmp(name, module->widget->name)) 89836ad9bf1SSrinivas Kandagatla return module; 89936ad9bf1SSrinivas Kandagatla } 90036ad9bf1SSrinivas Kandagatla 90136ad9bf1SSrinivas Kandagatla return NULL; 90236ad9bf1SSrinivas Kandagatla } 90336ad9bf1SSrinivas Kandagatla 90436ad9bf1SSrinivas Kandagatla static int audioreach_route_load(struct snd_soc_component *scomp, int index, 90536ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_route *route) 90636ad9bf1SSrinivas Kandagatla { 907*e4977b91SSrinivas Kandagatla struct audioreach_module *src_module, *sink_module; 908*e4977b91SSrinivas Kandagatla struct snd_ar_control *control; 909*e4977b91SSrinivas Kandagatla struct snd_soc_dapm_widget *w; 910*e4977b91SSrinivas Kandagatla int i; 91136ad9bf1SSrinivas Kandagatla 912*e4977b91SSrinivas Kandagatla /* check if these are actual modules */ 913*e4977b91SSrinivas Kandagatla src_module = audioreach_find_module(scomp, route->source); 914*e4977b91SSrinivas Kandagatla sink_module = audioreach_find_module(scomp, route->sink); 91536ad9bf1SSrinivas Kandagatla 916*e4977b91SSrinivas Kandagatla if (sink_module && !src_module) { 917*e4977b91SSrinivas Kandagatla control = audioreach_find_widget(scomp, route->source); 918*e4977b91SSrinivas Kandagatla if (control) 919*e4977b91SSrinivas Kandagatla control->module_instance_id = sink_module->instance_id; 920*e4977b91SSrinivas Kandagatla 921*e4977b91SSrinivas Kandagatla } else if (!sink_module && src_module && route->control) { 922*e4977b91SSrinivas Kandagatla /* check if this is a virtual mixer */ 923*e4977b91SSrinivas Kandagatla control = audioreach_find_widget(scomp, route->sink); 924*e4977b91SSrinivas Kandagatla if (!control || !control->w) 925*e4977b91SSrinivas Kandagatla return 0; 926*e4977b91SSrinivas Kandagatla 927*e4977b91SSrinivas Kandagatla w = control->w; 928*e4977b91SSrinivas Kandagatla 929*e4977b91SSrinivas Kandagatla for (i = 0; i < w->num_kcontrols; i++) { 930*e4977b91SSrinivas Kandagatla if (!strcmp(route->control, w->kcontrol_news[i].name)) { 931*e4977b91SSrinivas Kandagatla struct soc_mixer_control *sm; 932*e4977b91SSrinivas Kandagatla struct snd_soc_dobj *dobj; 933*e4977b91SSrinivas Kandagatla struct snd_ar_control *scontrol; 934*e4977b91SSrinivas Kandagatla 935*e4977b91SSrinivas Kandagatla sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value; 936*e4977b91SSrinivas Kandagatla dobj = &sm->dobj; 937*e4977b91SSrinivas Kandagatla scontrol = dobj->private; 938*e4977b91SSrinivas Kandagatla scontrol->module_instance_id = src_module->instance_id; 939*e4977b91SSrinivas Kandagatla } 940*e4977b91SSrinivas Kandagatla } 941*e4977b91SSrinivas Kandagatla 94236ad9bf1SSrinivas Kandagatla } 94336ad9bf1SSrinivas Kandagatla 94436ad9bf1SSrinivas Kandagatla return 0; 94536ad9bf1SSrinivas Kandagatla } 94636ad9bf1SSrinivas Kandagatla 94736ad9bf1SSrinivas Kandagatla static int audioreach_route_unload(struct snd_soc_component *scomp, 94836ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 94936ad9bf1SSrinivas Kandagatla { 95036ad9bf1SSrinivas Kandagatla return 0; 95136ad9bf1SSrinivas Kandagatla } 95236ad9bf1SSrinivas Kandagatla 95336ad9bf1SSrinivas Kandagatla static int audioreach_tplg_complete(struct snd_soc_component *component) 95436ad9bf1SSrinivas Kandagatla { 95536ad9bf1SSrinivas Kandagatla /* TBD */ 95636ad9bf1SSrinivas Kandagatla return 0; 95736ad9bf1SSrinivas Kandagatla } 95836ad9bf1SSrinivas Kandagatla 95936ad9bf1SSrinivas Kandagatla /* DAI link - used for any driver specific init */ 96036ad9bf1SSrinivas Kandagatla static int audioreach_link_load(struct snd_soc_component *component, int index, 96136ad9bf1SSrinivas Kandagatla struct snd_soc_dai_link *link, 96236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_link_config *cfg) 96336ad9bf1SSrinivas Kandagatla { 96436ad9bf1SSrinivas Kandagatla link->nonatomic = true; 96536ad9bf1SSrinivas Kandagatla link->dynamic = true; 96636ad9bf1SSrinivas Kandagatla link->platforms->name = NULL; 96736ad9bf1SSrinivas Kandagatla link->platforms->of_node = of_get_compatible_child(component->dev->of_node, 96836ad9bf1SSrinivas Kandagatla "qcom,q6apm-dais"); 96936ad9bf1SSrinivas Kandagatla return 0; 97036ad9bf1SSrinivas Kandagatla } 97136ad9bf1SSrinivas Kandagatla 972*e4977b91SSrinivas Kandagatla static void audioreach_connect_sub_graphs(struct q6apm *apm, 973*e4977b91SSrinivas Kandagatla struct snd_ar_control *m1, 974*e4977b91SSrinivas Kandagatla struct snd_ar_control *m2, 975*e4977b91SSrinivas Kandagatla bool connect) 976*e4977b91SSrinivas Kandagatla { 977*e4977b91SSrinivas Kandagatla struct audioreach_graph_info *info; 978*e4977b91SSrinivas Kandagatla 979*e4977b91SSrinivas Kandagatla mutex_lock(&apm->lock); 980*e4977b91SSrinivas Kandagatla info = idr_find(&apm->graph_info_idr, m2->graph_id); 981*e4977b91SSrinivas Kandagatla mutex_unlock(&apm->lock); 982*e4977b91SSrinivas Kandagatla 983*e4977b91SSrinivas Kandagatla if (connect) { 984*e4977b91SSrinivas Kandagatla info->src_mod_inst_id = m1->module_instance_id; 985*e4977b91SSrinivas Kandagatla info->src_mod_op_port_id = 1; 986*e4977b91SSrinivas Kandagatla info->dst_mod_inst_id = m2->module_instance_id; 987*e4977b91SSrinivas Kandagatla info->dst_mod_ip_port_id = 2; 988*e4977b91SSrinivas Kandagatla 989*e4977b91SSrinivas Kandagatla } else { 990*e4977b91SSrinivas Kandagatla info->src_mod_inst_id = 0; 991*e4977b91SSrinivas Kandagatla info->src_mod_op_port_id = 0; 992*e4977b91SSrinivas Kandagatla info->dst_mod_inst_id = 0; 993*e4977b91SSrinivas Kandagatla info->dst_mod_ip_port_id = 0; 994*e4977b91SSrinivas Kandagatla } 995*e4977b91SSrinivas Kandagatla } 996*e4977b91SSrinivas Kandagatla 997*e4977b91SSrinivas Kandagatla static bool audioreach_is_vmixer_connected(struct q6apm *apm, 998*e4977b91SSrinivas Kandagatla struct snd_ar_control *m1, 999*e4977b91SSrinivas Kandagatla struct snd_ar_control *m2) 1000*e4977b91SSrinivas Kandagatla { 1001*e4977b91SSrinivas Kandagatla struct audioreach_graph_info *info; 1002*e4977b91SSrinivas Kandagatla 1003*e4977b91SSrinivas Kandagatla mutex_lock(&apm->lock); 1004*e4977b91SSrinivas Kandagatla info = idr_find(&apm->graph_info_idr, m2->graph_id); 1005*e4977b91SSrinivas Kandagatla mutex_unlock(&apm->lock); 1006*e4977b91SSrinivas Kandagatla 1007*e4977b91SSrinivas Kandagatla if (info->dst_mod_inst_id == m2->module_instance_id && 1008*e4977b91SSrinivas Kandagatla info->src_mod_inst_id == m1->module_instance_id) 1009*e4977b91SSrinivas Kandagatla return true; 1010*e4977b91SSrinivas Kandagatla 1011*e4977b91SSrinivas Kandagatla return false; 1012*e4977b91SSrinivas Kandagatla } 1013*e4977b91SSrinivas Kandagatla 101436ad9bf1SSrinivas Kandagatla static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol, 101536ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 101636ad9bf1SSrinivas Kandagatla { 101736ad9bf1SSrinivas Kandagatla struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 101836ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 101936ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 102036ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 102136ad9bf1SSrinivas Kandagatla struct snd_ar_control *dapm_scontrol = dw->dobj.private; 102236ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = mc->dobj.private; 102336ad9bf1SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(c->dev); 102436ad9bf1SSrinivas Kandagatla bool connected; 102536ad9bf1SSrinivas Kandagatla 1026*e4977b91SSrinivas Kandagatla connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol); 102736ad9bf1SSrinivas Kandagatla if (connected) 102836ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = 1; 102936ad9bf1SSrinivas Kandagatla else 103036ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = 0; 103136ad9bf1SSrinivas Kandagatla 103236ad9bf1SSrinivas Kandagatla return 0; 103336ad9bf1SSrinivas Kandagatla } 103436ad9bf1SSrinivas Kandagatla 103536ad9bf1SSrinivas Kandagatla static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol, 103636ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 103736ad9bf1SSrinivas Kandagatla { 103836ad9bf1SSrinivas Kandagatla struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 103936ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 104036ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 104136ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 104236ad9bf1SSrinivas Kandagatla struct snd_ar_control *dapm_scontrol = dw->dobj.private; 104336ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = mc->dobj.private; 104436ad9bf1SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(c->dev); 104536ad9bf1SSrinivas Kandagatla 104636ad9bf1SSrinivas Kandagatla if (ucontrol->value.integer.value[0]) { 1047*e4977b91SSrinivas Kandagatla audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true); 104836ad9bf1SSrinivas Kandagatla snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL); 104936ad9bf1SSrinivas Kandagatla } else { 1050*e4977b91SSrinivas Kandagatla audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false); 105136ad9bf1SSrinivas Kandagatla snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL); 105236ad9bf1SSrinivas Kandagatla } 105336ad9bf1SSrinivas Kandagatla return 0; 105436ad9bf1SSrinivas Kandagatla } 105536ad9bf1SSrinivas Kandagatla 105636ad9bf1SSrinivas Kandagatla static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 105736ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 105836ad9bf1SSrinivas Kandagatla { 105936ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 106036ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = dw->dobj.private; 106136ad9bf1SSrinivas Kandagatla 106236ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = mod->gain; 106336ad9bf1SSrinivas Kandagatla 106436ad9bf1SSrinivas Kandagatla return 0; 106536ad9bf1SSrinivas Kandagatla } 106636ad9bf1SSrinivas Kandagatla 106736ad9bf1SSrinivas Kandagatla static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 106836ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 106936ad9bf1SSrinivas Kandagatla { 107036ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 107136ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = dw->dobj.private; 107236ad9bf1SSrinivas Kandagatla 107336ad9bf1SSrinivas Kandagatla mod->gain = ucontrol->value.integer.value[0]; 107436ad9bf1SSrinivas Kandagatla 107536ad9bf1SSrinivas Kandagatla return 1; 107636ad9bf1SSrinivas Kandagatla } 107736ad9bf1SSrinivas Kandagatla 107836ad9bf1SSrinivas Kandagatla static int audioreach_control_load_mix(struct snd_soc_component *scomp, 107936ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol, 108036ad9bf1SSrinivas Kandagatla struct snd_kcontrol_new *kc, 108136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_ctl_hdr *hdr) 108236ad9bf1SSrinivas Kandagatla { 108336ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *c_elem; 108436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *c_array; 108536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_mixer_control *mc; 108636ad9bf1SSrinivas Kandagatla int tkn_count = 0; 108736ad9bf1SSrinivas Kandagatla 108836ad9bf1SSrinivas Kandagatla mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); 108936ad9bf1SSrinivas Kandagatla c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data; 109036ad9bf1SSrinivas Kandagatla 109136ad9bf1SSrinivas Kandagatla c_elem = c_array->value; 109236ad9bf1SSrinivas Kandagatla 109336ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) { 109436ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(c_elem->token)) { 109536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 109636ad9bf1SSrinivas Kandagatla scontrol->sgid = le32_to_cpu(c_elem->value); 109736ad9bf1SSrinivas Kandagatla break; 10981c87d381SSrinivas Kandagatla case AR_TKN_DAI_INDEX: 10991c87d381SSrinivas Kandagatla scontrol->graph_id = le32_to_cpu(c_elem->value); 11001c87d381SSrinivas Kandagatla break; 110136ad9bf1SSrinivas Kandagatla default: 110236ad9bf1SSrinivas Kandagatla /* Ignore other tokens */ 110336ad9bf1SSrinivas Kandagatla break; 110436ad9bf1SSrinivas Kandagatla } 110536ad9bf1SSrinivas Kandagatla c_elem++; 110636ad9bf1SSrinivas Kandagatla tkn_count++; 110736ad9bf1SSrinivas Kandagatla } 110836ad9bf1SSrinivas Kandagatla 110936ad9bf1SSrinivas Kandagatla return 0; 111036ad9bf1SSrinivas Kandagatla } 111136ad9bf1SSrinivas Kandagatla 111236ad9bf1SSrinivas Kandagatla static int audioreach_control_load(struct snd_soc_component *scomp, int index, 111336ad9bf1SSrinivas Kandagatla struct snd_kcontrol_new *kc, 111436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_ctl_hdr *hdr) 111536ad9bf1SSrinivas Kandagatla { 111636ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol; 111736ad9bf1SSrinivas Kandagatla struct soc_mixer_control *sm; 111836ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 111936ad9bf1SSrinivas Kandagatla int ret = 0; 112036ad9bf1SSrinivas Kandagatla 112136ad9bf1SSrinivas Kandagatla scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 112236ad9bf1SSrinivas Kandagatla if (!scontrol) 112336ad9bf1SSrinivas Kandagatla return -ENOMEM; 112436ad9bf1SSrinivas Kandagatla 112536ad9bf1SSrinivas Kandagatla scontrol->scomp = scomp; 112636ad9bf1SSrinivas Kandagatla 112736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(hdr->ops.get)) { 112836ad9bf1SSrinivas Kandagatla case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX: 112936ad9bf1SSrinivas Kandagatla sm = (struct soc_mixer_control *)kc->private_value; 113036ad9bf1SSrinivas Kandagatla dobj = &sm->dobj; 113136ad9bf1SSrinivas Kandagatla ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr); 113236ad9bf1SSrinivas Kandagatla break; 113336ad9bf1SSrinivas Kandagatla case SND_SOC_AR_TPLG_VOL_CTL: 113436ad9bf1SSrinivas Kandagatla sm = (struct soc_mixer_control *)kc->private_value; 113536ad9bf1SSrinivas Kandagatla dobj = &sm->dobj; 113636ad9bf1SSrinivas Kandagatla break; 113736ad9bf1SSrinivas Kandagatla default: 113836ad9bf1SSrinivas Kandagatla dev_warn(scomp->dev, "control type not supported %d:%d:%d\n", 113936ad9bf1SSrinivas Kandagatla hdr->ops.get, hdr->ops.put, hdr->ops.info); 114036ad9bf1SSrinivas Kandagatla kfree(scontrol); 114136ad9bf1SSrinivas Kandagatla return -EINVAL; 114236ad9bf1SSrinivas Kandagatla } 114336ad9bf1SSrinivas Kandagatla 114436ad9bf1SSrinivas Kandagatla dobj->private = scontrol; 114536ad9bf1SSrinivas Kandagatla return ret; 114636ad9bf1SSrinivas Kandagatla } 114736ad9bf1SSrinivas Kandagatla 114836ad9bf1SSrinivas Kandagatla static int audioreach_control_unload(struct snd_soc_component *scomp, 114936ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 115036ad9bf1SSrinivas Kandagatla { 115136ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = dobj->private; 115236ad9bf1SSrinivas Kandagatla 115336ad9bf1SSrinivas Kandagatla kfree(scontrol); 115436ad9bf1SSrinivas Kandagatla 115536ad9bf1SSrinivas Kandagatla return 0; 115636ad9bf1SSrinivas Kandagatla } 115736ad9bf1SSrinivas Kandagatla 115836ad9bf1SSrinivas Kandagatla static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = { 115936ad9bf1SSrinivas Kandagatla {SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer, 116036ad9bf1SSrinivas Kandagatla audioreach_put_audio_mixer, snd_soc_info_volsw}, 116136ad9bf1SSrinivas Kandagatla {SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer, 116236ad9bf1SSrinivas Kandagatla audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw}, 116336ad9bf1SSrinivas Kandagatla }; 116436ad9bf1SSrinivas Kandagatla 116536ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_ops audioreach_tplg_ops = { 116636ad9bf1SSrinivas Kandagatla .io_ops = audioreach_io_ops, 116736ad9bf1SSrinivas Kandagatla .io_ops_count = ARRAY_SIZE(audioreach_io_ops), 116836ad9bf1SSrinivas Kandagatla 116936ad9bf1SSrinivas Kandagatla .control_load = audioreach_control_load, 117036ad9bf1SSrinivas Kandagatla .control_unload = audioreach_control_unload, 117136ad9bf1SSrinivas Kandagatla 117236ad9bf1SSrinivas Kandagatla .widget_ready = audioreach_widget_ready, 117336ad9bf1SSrinivas Kandagatla .widget_unload = audioreach_widget_unload, 117436ad9bf1SSrinivas Kandagatla 117536ad9bf1SSrinivas Kandagatla .complete = audioreach_tplg_complete, 117636ad9bf1SSrinivas Kandagatla .link_load = audioreach_link_load, 117736ad9bf1SSrinivas Kandagatla 117836ad9bf1SSrinivas Kandagatla .dapm_route_load = audioreach_route_load, 117936ad9bf1SSrinivas Kandagatla .dapm_route_unload = audioreach_route_unload, 118036ad9bf1SSrinivas Kandagatla }; 118136ad9bf1SSrinivas Kandagatla 118236ad9bf1SSrinivas Kandagatla int audioreach_tplg_init(struct snd_soc_component *component) 118336ad9bf1SSrinivas Kandagatla { 118436ad9bf1SSrinivas Kandagatla struct snd_soc_card *card = component->card; 118536ad9bf1SSrinivas Kandagatla struct device *dev = component->dev; 118636ad9bf1SSrinivas Kandagatla const struct firmware *fw; 118736ad9bf1SSrinivas Kandagatla char *tplg_fw_name; 118836ad9bf1SSrinivas Kandagatla int ret; 118936ad9bf1SSrinivas Kandagatla 119036ad9bf1SSrinivas Kandagatla /* Inline with Qualcomm UCM configs and linux-firmware path */ 119136ad9bf1SSrinivas Kandagatla tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name); 119236ad9bf1SSrinivas Kandagatla if (!tplg_fw_name) 119336ad9bf1SSrinivas Kandagatla return -ENOMEM; 119436ad9bf1SSrinivas Kandagatla 119536ad9bf1SSrinivas Kandagatla ret = request_firmware(&fw, tplg_fw_name, dev); 119636ad9bf1SSrinivas Kandagatla if (ret < 0) { 119736ad9bf1SSrinivas Kandagatla dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); 119836ad9bf1SSrinivas Kandagatla goto err; 119936ad9bf1SSrinivas Kandagatla } 120036ad9bf1SSrinivas Kandagatla 120136ad9bf1SSrinivas Kandagatla ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw); 120236ad9bf1SSrinivas Kandagatla if (ret < 0) { 120336ad9bf1SSrinivas Kandagatla dev_err(dev, "tplg component load failed%d\n", ret); 120436ad9bf1SSrinivas Kandagatla ret = -EINVAL; 120536ad9bf1SSrinivas Kandagatla } 120636ad9bf1SSrinivas Kandagatla 120736ad9bf1SSrinivas Kandagatla release_firmware(fw); 120836ad9bf1SSrinivas Kandagatla err: 120936ad9bf1SSrinivas Kandagatla kfree(tplg_fw_name); 121036ad9bf1SSrinivas Kandagatla 121136ad9bf1SSrinivas Kandagatla return ret; 121236ad9bf1SSrinivas Kandagatla } 121336ad9bf1SSrinivas Kandagatla EXPORT_SYMBOL_GPL(audioreach_tplg_init); 1214