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 { 1936ad9bf1SSrinivas Kandagatla u32 sgid; /* Sub Graph ID */ 2036ad9bf1SSrinivas Kandagatla struct snd_soc_component *scomp; 2136ad9bf1SSrinivas Kandagatla }; 2236ad9bf1SSrinivas Kandagatla 2336ad9bf1SSrinivas Kandagatla static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm, 2436ad9bf1SSrinivas Kandagatla uint32_t graph_id, 2536ad9bf1SSrinivas Kandagatla bool *found) 2636ad9bf1SSrinivas Kandagatla { 2736ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info; 2836ad9bf1SSrinivas Kandagatla int ret; 2936ad9bf1SSrinivas Kandagatla 3036ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 3136ad9bf1SSrinivas Kandagatla info = idr_find(&apm->graph_info_idr, graph_id); 3236ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 3336ad9bf1SSrinivas Kandagatla 3436ad9bf1SSrinivas Kandagatla if (info) { 3536ad9bf1SSrinivas Kandagatla *found = true; 3636ad9bf1SSrinivas Kandagatla return info; 3736ad9bf1SSrinivas Kandagatla } 3836ad9bf1SSrinivas Kandagatla 3936ad9bf1SSrinivas Kandagatla *found = false; 4036ad9bf1SSrinivas Kandagatla info = kzalloc(sizeof(*info), GFP_KERNEL); 4136ad9bf1SSrinivas Kandagatla if (!info) 4236ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 4336ad9bf1SSrinivas Kandagatla 4436ad9bf1SSrinivas Kandagatla INIT_LIST_HEAD(&info->sg_list); 4536ad9bf1SSrinivas Kandagatla 4636ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 4736ad9bf1SSrinivas Kandagatla ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL); 4836ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 4936ad9bf1SSrinivas Kandagatla 5036ad9bf1SSrinivas Kandagatla if (ret < 0) { 5136ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id); 5236ad9bf1SSrinivas Kandagatla kfree(info); 5336ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 5436ad9bf1SSrinivas Kandagatla } 5536ad9bf1SSrinivas Kandagatla 5636ad9bf1SSrinivas Kandagatla info->id = ret; 5736ad9bf1SSrinivas Kandagatla 5836ad9bf1SSrinivas Kandagatla return info; 5936ad9bf1SSrinivas Kandagatla } 6036ad9bf1SSrinivas Kandagatla 6136ad9bf1SSrinivas Kandagatla static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg, 6236ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info) 6336ad9bf1SSrinivas Kandagatla { 6436ad9bf1SSrinivas Kandagatla list_add_tail(&sg->node, &info->sg_list); 6536ad9bf1SSrinivas Kandagatla sg->info = info; 6636ad9bf1SSrinivas Kandagatla info->num_sub_graphs++; 6736ad9bf1SSrinivas Kandagatla } 6836ad9bf1SSrinivas Kandagatla 6936ad9bf1SSrinivas Kandagatla static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm, 7036ad9bf1SSrinivas Kandagatla uint32_t sub_graph_id, 7136ad9bf1SSrinivas Kandagatla bool *found) 7236ad9bf1SSrinivas Kandagatla { 7336ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg; 7436ad9bf1SSrinivas Kandagatla int ret; 7536ad9bf1SSrinivas Kandagatla 7636ad9bf1SSrinivas Kandagatla if (!sub_graph_id) 7736ad9bf1SSrinivas Kandagatla return ERR_PTR(-EINVAL); 7836ad9bf1SSrinivas Kandagatla 7936ad9bf1SSrinivas Kandagatla /* Find if there is already a matching sub-graph */ 8036ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 8136ad9bf1SSrinivas Kandagatla sg = idr_find(&apm->sub_graphs_idr, sub_graph_id); 8236ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 8336ad9bf1SSrinivas Kandagatla 8436ad9bf1SSrinivas Kandagatla if (sg) { 8536ad9bf1SSrinivas Kandagatla *found = true; 8636ad9bf1SSrinivas Kandagatla return sg; 8736ad9bf1SSrinivas Kandagatla } 8836ad9bf1SSrinivas Kandagatla 8936ad9bf1SSrinivas Kandagatla *found = false; 9036ad9bf1SSrinivas Kandagatla sg = kzalloc(sizeof(*sg), GFP_KERNEL); 9136ad9bf1SSrinivas Kandagatla if (!sg) 9236ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 9336ad9bf1SSrinivas Kandagatla 9436ad9bf1SSrinivas Kandagatla INIT_LIST_HEAD(&sg->container_list); 9536ad9bf1SSrinivas Kandagatla 9636ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 9736ad9bf1SSrinivas Kandagatla ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL); 9836ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 9936ad9bf1SSrinivas Kandagatla 10036ad9bf1SSrinivas Kandagatla if (ret < 0) { 10136ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id); 10236ad9bf1SSrinivas Kandagatla kfree(sg); 10336ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 10436ad9bf1SSrinivas Kandagatla } 10536ad9bf1SSrinivas Kandagatla 10636ad9bf1SSrinivas Kandagatla sg->sub_graph_id = ret; 10736ad9bf1SSrinivas Kandagatla 10836ad9bf1SSrinivas Kandagatla return sg; 10936ad9bf1SSrinivas Kandagatla } 11036ad9bf1SSrinivas Kandagatla 11136ad9bf1SSrinivas Kandagatla static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm, 11236ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg, 11336ad9bf1SSrinivas Kandagatla uint32_t container_id, 11436ad9bf1SSrinivas Kandagatla bool *found) 11536ad9bf1SSrinivas Kandagatla { 11636ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 11736ad9bf1SSrinivas Kandagatla int ret; 11836ad9bf1SSrinivas Kandagatla 11936ad9bf1SSrinivas Kandagatla if (!container_id) 12036ad9bf1SSrinivas Kandagatla return ERR_PTR(-EINVAL); 12136ad9bf1SSrinivas Kandagatla 12236ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 12336ad9bf1SSrinivas Kandagatla cont = idr_find(&apm->containers_idr, container_id); 12436ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 12536ad9bf1SSrinivas Kandagatla 12636ad9bf1SSrinivas Kandagatla if (cont) { 12736ad9bf1SSrinivas Kandagatla *found = true; 12836ad9bf1SSrinivas Kandagatla return cont; 12936ad9bf1SSrinivas Kandagatla } 13036ad9bf1SSrinivas Kandagatla *found = false; 13136ad9bf1SSrinivas Kandagatla 13236ad9bf1SSrinivas Kandagatla cont = kzalloc(sizeof(*cont), GFP_KERNEL); 13336ad9bf1SSrinivas Kandagatla if (!cont) 13436ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 13536ad9bf1SSrinivas Kandagatla 13636ad9bf1SSrinivas Kandagatla INIT_LIST_HEAD(&cont->modules_list); 13736ad9bf1SSrinivas Kandagatla 13836ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 13936ad9bf1SSrinivas Kandagatla ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL); 14036ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 14136ad9bf1SSrinivas Kandagatla 14236ad9bf1SSrinivas Kandagatla if (ret < 0) { 14336ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id); 14436ad9bf1SSrinivas Kandagatla kfree(cont); 14536ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 14636ad9bf1SSrinivas Kandagatla } 14736ad9bf1SSrinivas Kandagatla 14836ad9bf1SSrinivas Kandagatla cont->container_id = ret; 14936ad9bf1SSrinivas Kandagatla cont->sub_graph = sg; 15036ad9bf1SSrinivas Kandagatla /* add to container list */ 15136ad9bf1SSrinivas Kandagatla list_add_tail(&cont->node, &sg->container_list); 15236ad9bf1SSrinivas Kandagatla sg->num_containers++; 15336ad9bf1SSrinivas Kandagatla 15436ad9bf1SSrinivas Kandagatla return cont; 15536ad9bf1SSrinivas Kandagatla } 15636ad9bf1SSrinivas Kandagatla 15736ad9bf1SSrinivas Kandagatla static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm, 15836ad9bf1SSrinivas Kandagatla struct audioreach_container *cont, 15936ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *w, 16036ad9bf1SSrinivas Kandagatla uint32_t module_id, bool *found) 16136ad9bf1SSrinivas Kandagatla { 16236ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 16336ad9bf1SSrinivas Kandagatla int ret; 16436ad9bf1SSrinivas Kandagatla 16536ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 16636ad9bf1SSrinivas Kandagatla mod = idr_find(&apm->modules_idr, module_id); 16736ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 16836ad9bf1SSrinivas Kandagatla 16936ad9bf1SSrinivas Kandagatla if (mod) { 17036ad9bf1SSrinivas Kandagatla *found = true; 17136ad9bf1SSrinivas Kandagatla return mod; 17236ad9bf1SSrinivas Kandagatla } 17336ad9bf1SSrinivas Kandagatla *found = false; 17436ad9bf1SSrinivas Kandagatla mod = kzalloc(sizeof(*mod), GFP_KERNEL); 17536ad9bf1SSrinivas Kandagatla if (!mod) 17636ad9bf1SSrinivas Kandagatla return ERR_PTR(-ENOMEM); 17736ad9bf1SSrinivas Kandagatla 17836ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 17936ad9bf1SSrinivas Kandagatla if (!module_id) { /* alloc module id dynamically */ 18036ad9bf1SSrinivas Kandagatla ret = idr_alloc_cyclic(&apm->modules_idr, mod, 18136ad9bf1SSrinivas Kandagatla AR_MODULE_DYNAMIC_INSTANCE_ID_START, 18236ad9bf1SSrinivas Kandagatla AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL); 18336ad9bf1SSrinivas Kandagatla } else { 18436ad9bf1SSrinivas Kandagatla ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL); 18536ad9bf1SSrinivas Kandagatla } 18636ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 18736ad9bf1SSrinivas Kandagatla 18836ad9bf1SSrinivas Kandagatla if (ret < 0) { 18936ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id); 19036ad9bf1SSrinivas Kandagatla kfree(mod); 19136ad9bf1SSrinivas Kandagatla return ERR_PTR(ret); 19236ad9bf1SSrinivas Kandagatla } 19336ad9bf1SSrinivas Kandagatla 19436ad9bf1SSrinivas Kandagatla mod->instance_id = ret; 19536ad9bf1SSrinivas Kandagatla /* add to module list */ 19636ad9bf1SSrinivas Kandagatla list_add_tail(&mod->node, &cont->modules_list); 19736ad9bf1SSrinivas Kandagatla mod->container = cont; 19836ad9bf1SSrinivas Kandagatla mod->widget = w; 19936ad9bf1SSrinivas Kandagatla cont->num_modules++; 20036ad9bf1SSrinivas Kandagatla 20136ad9bf1SSrinivas Kandagatla return mod; 20236ad9bf1SSrinivas Kandagatla } 20336ad9bf1SSrinivas Kandagatla 20436ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array( 20536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 20636ad9bf1SSrinivas Kandagatla { 20736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *sg_array = NULL; 20836ad9bf1SSrinivas Kandagatla bool found = false; 20936ad9bf1SSrinivas Kandagatla int sz; 21036ad9bf1SSrinivas Kandagatla 21136ad9bf1SSrinivas Kandagatla for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 21236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *sg_elem; 21336ad9bf1SSrinivas Kandagatla int tkn_count = 0; 21436ad9bf1SSrinivas Kandagatla 21536ad9bf1SSrinivas Kandagatla sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 21636ad9bf1SSrinivas Kandagatla sg_elem = sg_array->value; 21736ad9bf1SSrinivas Kandagatla sz = sz + le32_to_cpu(sg_array->size); 21836ad9bf1SSrinivas Kandagatla while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { 21936ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(sg_elem->token)) { 22036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 22136ad9bf1SSrinivas Kandagatla found = true; 22236ad9bf1SSrinivas Kandagatla break; 22336ad9bf1SSrinivas Kandagatla default: 22436ad9bf1SSrinivas Kandagatla break; 22536ad9bf1SSrinivas Kandagatla } 22636ad9bf1SSrinivas Kandagatla tkn_count++; 22736ad9bf1SSrinivas Kandagatla sg_elem++; 22836ad9bf1SSrinivas Kandagatla } 22936ad9bf1SSrinivas Kandagatla } 23036ad9bf1SSrinivas Kandagatla 23136ad9bf1SSrinivas Kandagatla if (found) 23236ad9bf1SSrinivas Kandagatla return sg_array; 23336ad9bf1SSrinivas Kandagatla 23436ad9bf1SSrinivas Kandagatla return NULL; 23536ad9bf1SSrinivas Kandagatla } 23636ad9bf1SSrinivas Kandagatla 23736ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array( 23836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 23936ad9bf1SSrinivas Kandagatla { 24036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *cont_array = NULL; 24136ad9bf1SSrinivas Kandagatla bool found = false; 24236ad9bf1SSrinivas Kandagatla int sz; 24336ad9bf1SSrinivas Kandagatla 24436ad9bf1SSrinivas Kandagatla for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 24536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *cont_elem; 24636ad9bf1SSrinivas Kandagatla int tkn_count = 0; 24736ad9bf1SSrinivas Kandagatla 24836ad9bf1SSrinivas Kandagatla cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 24936ad9bf1SSrinivas Kandagatla cont_elem = cont_array->value; 25036ad9bf1SSrinivas Kandagatla sz = sz + le32_to_cpu(cont_array->size); 25136ad9bf1SSrinivas Kandagatla while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { 25236ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(cont_elem->token)) { 25336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_INSTANCE_ID: 25436ad9bf1SSrinivas Kandagatla found = true; 25536ad9bf1SSrinivas Kandagatla break; 25636ad9bf1SSrinivas Kandagatla default: 25736ad9bf1SSrinivas Kandagatla break; 25836ad9bf1SSrinivas Kandagatla } 25936ad9bf1SSrinivas Kandagatla tkn_count++; 26036ad9bf1SSrinivas Kandagatla cont_elem++; 26136ad9bf1SSrinivas Kandagatla } 26236ad9bf1SSrinivas Kandagatla } 26336ad9bf1SSrinivas Kandagatla 26436ad9bf1SSrinivas Kandagatla if (found) 26536ad9bf1SSrinivas Kandagatla return cont_array; 26636ad9bf1SSrinivas Kandagatla 26736ad9bf1SSrinivas Kandagatla return NULL; 26836ad9bf1SSrinivas Kandagatla } 26936ad9bf1SSrinivas Kandagatla 27036ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_vendor_array *audioreach_get_module_array( 27136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 27236ad9bf1SSrinivas Kandagatla { 27336ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array = NULL; 27436ad9bf1SSrinivas Kandagatla bool found = false; 27536ad9bf1SSrinivas Kandagatla int sz = 0; 27636ad9bf1SSrinivas Kandagatla 27736ad9bf1SSrinivas Kandagatla for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { 27836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 27936ad9bf1SSrinivas Kandagatla int tkn_count = 0; 28036ad9bf1SSrinivas Kandagatla 28136ad9bf1SSrinivas Kandagatla mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); 28236ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 28336ad9bf1SSrinivas Kandagatla sz = sz + le32_to_cpu(mod_array->size); 28436ad9bf1SSrinivas Kandagatla while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 28536ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 28636ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_INSTANCE_ID: 28736ad9bf1SSrinivas Kandagatla found = true; 28836ad9bf1SSrinivas Kandagatla break; 28936ad9bf1SSrinivas Kandagatla default: 29036ad9bf1SSrinivas Kandagatla break; 29136ad9bf1SSrinivas Kandagatla } 29236ad9bf1SSrinivas Kandagatla tkn_count++; 29336ad9bf1SSrinivas Kandagatla mod_elem++; 29436ad9bf1SSrinivas Kandagatla } 29536ad9bf1SSrinivas Kandagatla } 29636ad9bf1SSrinivas Kandagatla 29736ad9bf1SSrinivas Kandagatla if (found) 29836ad9bf1SSrinivas Kandagatla return mod_array; 29936ad9bf1SSrinivas Kandagatla 30036ad9bf1SSrinivas Kandagatla return NULL; 30136ad9bf1SSrinivas Kandagatla } 30236ad9bf1SSrinivas Kandagatla 30336ad9bf1SSrinivas Kandagatla static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm, 30436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 30536ad9bf1SSrinivas Kandagatla { 30636ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *sg_elem; 30736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *sg_array; 30836ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info = NULL; 30936ad9bf1SSrinivas Kandagatla int graph_id, sub_graph_id, tkn_count = 0; 31036ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg; 31136ad9bf1SSrinivas Kandagatla bool found; 31236ad9bf1SSrinivas Kandagatla 31336ad9bf1SSrinivas Kandagatla sg_array = audioreach_get_sg_array(private); 31436ad9bf1SSrinivas Kandagatla sg_elem = sg_array->value; 31536ad9bf1SSrinivas Kandagatla 31636ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { 31736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(sg_elem->token)) { 31836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 31936ad9bf1SSrinivas Kandagatla sub_graph_id = le32_to_cpu(sg_elem->value); 32036ad9bf1SSrinivas Kandagatla sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found); 32136ad9bf1SSrinivas Kandagatla if (IS_ERR(sg)) { 32236ad9bf1SSrinivas Kandagatla return sg; 32336ad9bf1SSrinivas Kandagatla } else if (found) { 32436ad9bf1SSrinivas Kandagatla /* Already parsed data for this sub-graph */ 32536ad9bf1SSrinivas Kandagatla return sg; 32636ad9bf1SSrinivas Kandagatla } 32736ad9bf1SSrinivas Kandagatla break; 32836ad9bf1SSrinivas Kandagatla case AR_TKN_DAI_INDEX: 32936ad9bf1SSrinivas Kandagatla /* Sub graph is associated with predefined graph */ 33036ad9bf1SSrinivas Kandagatla graph_id = le32_to_cpu(sg_elem->value); 33136ad9bf1SSrinivas Kandagatla info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found); 33236ad9bf1SSrinivas Kandagatla if (IS_ERR(info)) 33336ad9bf1SSrinivas Kandagatla return ERR_CAST(info); 33436ad9bf1SSrinivas Kandagatla break; 33536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_PERF_MODE: 33636ad9bf1SSrinivas Kandagatla sg->perf_mode = le32_to_cpu(sg_elem->value); 33736ad9bf1SSrinivas Kandagatla break; 33836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_DIRECTION: 33936ad9bf1SSrinivas Kandagatla sg->direction = le32_to_cpu(sg_elem->value); 34036ad9bf1SSrinivas Kandagatla break; 34136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID: 34236ad9bf1SSrinivas Kandagatla sg->scenario_id = le32_to_cpu(sg_elem->value); 34336ad9bf1SSrinivas Kandagatla break; 34436ad9bf1SSrinivas Kandagatla default: 34536ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token); 34636ad9bf1SSrinivas Kandagatla break; 34736ad9bf1SSrinivas Kandagatla 34836ad9bf1SSrinivas Kandagatla } 34936ad9bf1SSrinivas Kandagatla tkn_count++; 35036ad9bf1SSrinivas Kandagatla sg_elem++; 35136ad9bf1SSrinivas Kandagatla } 35236ad9bf1SSrinivas Kandagatla 35336ad9bf1SSrinivas Kandagatla /* Sub graph is associated with predefined graph */ 35436ad9bf1SSrinivas Kandagatla if (info) 35536ad9bf1SSrinivas Kandagatla audioreach_tplg_add_sub_graph(sg, info); 35636ad9bf1SSrinivas Kandagatla 35736ad9bf1SSrinivas Kandagatla return sg; 35836ad9bf1SSrinivas Kandagatla } 35936ad9bf1SSrinivas Kandagatla 36036ad9bf1SSrinivas Kandagatla static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm, 36136ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg, 36236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private) 36336ad9bf1SSrinivas Kandagatla { 36436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *cont_elem; 36536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *cont_array; 36636ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 36736ad9bf1SSrinivas Kandagatla int container_id, tkn_count = 0; 36836ad9bf1SSrinivas Kandagatla bool found = false; 36936ad9bf1SSrinivas Kandagatla 37036ad9bf1SSrinivas Kandagatla cont_array = audioreach_get_cont_array(private); 37136ad9bf1SSrinivas Kandagatla cont_elem = cont_array->value; 37236ad9bf1SSrinivas Kandagatla 37336ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { 37436ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(cont_elem->token)) { 37536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_INSTANCE_ID: 37636ad9bf1SSrinivas Kandagatla container_id = le32_to_cpu(cont_elem->value); 37736ad9bf1SSrinivas Kandagatla cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found); 37836ad9bf1SSrinivas Kandagatla if (IS_ERR(cont) || found)/* Error or Already parsed container data */ 37936ad9bf1SSrinivas Kandagatla return cont; 38036ad9bf1SSrinivas Kandagatla break; 38136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_CAPABILITY_ID: 38236ad9bf1SSrinivas Kandagatla cont->capability_id = le32_to_cpu(cont_elem->value); 38336ad9bf1SSrinivas Kandagatla break; 38436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_STACK_SIZE: 38536ad9bf1SSrinivas Kandagatla cont->stack_size = le32_to_cpu(cont_elem->value); 38636ad9bf1SSrinivas Kandagatla break; 38736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_GRAPH_POS: 38836ad9bf1SSrinivas Kandagatla cont->graph_pos = le32_to_cpu(cont_elem->value); 38936ad9bf1SSrinivas Kandagatla break; 39036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_CONTAINER_PROC_DOMAIN: 39136ad9bf1SSrinivas Kandagatla cont->proc_domain = le32_to_cpu(cont_elem->value); 39236ad9bf1SSrinivas Kandagatla break; 39336ad9bf1SSrinivas Kandagatla default: 39436ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token); 39536ad9bf1SSrinivas Kandagatla break; 39636ad9bf1SSrinivas Kandagatla 39736ad9bf1SSrinivas Kandagatla } 39836ad9bf1SSrinivas Kandagatla tkn_count++; 39936ad9bf1SSrinivas Kandagatla cont_elem++; 40036ad9bf1SSrinivas Kandagatla } 40136ad9bf1SSrinivas Kandagatla 40236ad9bf1SSrinivas Kandagatla return cont; 40336ad9bf1SSrinivas Kandagatla } 40436ad9bf1SSrinivas Kandagatla 40536ad9bf1SSrinivas Kandagatla static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm, 40636ad9bf1SSrinivas Kandagatla struct audioreach_container *cont, 40736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_private *private, 40836ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *w) 40936ad9bf1SSrinivas Kandagatla { 41036ad9bf1SSrinivas Kandagatla uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0; 41136ad9bf1SSrinivas Kandagatla uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0; 41236ad9bf1SSrinivas Kandagatla uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0; 41336ad9bf1SSrinivas Kandagatla int module_id = 0, instance_id = 0, tkn_count = 0; 41436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 41536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 41636ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = NULL; 41736ad9bf1SSrinivas Kandagatla bool found; 41836ad9bf1SSrinivas Kandagatla 41936ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(private); 42036ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 42136ad9bf1SSrinivas Kandagatla 42236ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 42336ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 42436ad9bf1SSrinivas Kandagatla /* common module info */ 42536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_ID: 42636ad9bf1SSrinivas Kandagatla module_id = le32_to_cpu(mod_elem->value); 42736ad9bf1SSrinivas Kandagatla break; 42836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_INSTANCE_ID: 42936ad9bf1SSrinivas Kandagatla instance_id = le32_to_cpu(mod_elem->value); 43036ad9bf1SSrinivas Kandagatla mod = audioreach_tplg_alloc_module(apm, cont, w, 43136ad9bf1SSrinivas Kandagatla instance_id, &found); 43236ad9bf1SSrinivas Kandagatla if (IS_ERR(mod)) { 43336ad9bf1SSrinivas Kandagatla return mod; 43436ad9bf1SSrinivas Kandagatla } else if (found) { 43536ad9bf1SSrinivas Kandagatla dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n", 43636ad9bf1SSrinivas Kandagatla instance_id); 43736ad9bf1SSrinivas Kandagatla return ERR_PTR(-EINVAL); 43836ad9bf1SSrinivas Kandagatla } 43936ad9bf1SSrinivas Kandagatla 44036ad9bf1SSrinivas Kandagatla break; 44136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_MAX_IP_PORTS: 44236ad9bf1SSrinivas Kandagatla max_ip_port = le32_to_cpu(mod_elem->value); 44336ad9bf1SSrinivas Kandagatla break; 44436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_MAX_OP_PORTS: 44536ad9bf1SSrinivas Kandagatla max_op_port = le32_to_cpu(mod_elem->value); 44636ad9bf1SSrinivas Kandagatla break; 44736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_IN_PORTS: 44836ad9bf1SSrinivas Kandagatla in_port = le32_to_cpu(mod_elem->value); 44936ad9bf1SSrinivas Kandagatla break; 45036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_OUT_PORTS: 45136ad9bf1SSrinivas Kandagatla out_port = le32_to_cpu(mod_elem->value); 45236ad9bf1SSrinivas Kandagatla break; 45336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_OP_PORT_ID: 45436ad9bf1SSrinivas Kandagatla src_mod_op_port_id = le32_to_cpu(mod_elem->value); 45536ad9bf1SSrinivas Kandagatla break; 45636ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SRC_INSTANCE_ID: 45736ad9bf1SSrinivas Kandagatla src_mod_inst_id = le32_to_cpu(mod_elem->value); 45836ad9bf1SSrinivas Kandagatla break; 45936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_INSTANCE_ID: 46036ad9bf1SSrinivas Kandagatla dst_mod_inst_id = le32_to_cpu(mod_elem->value); 46136ad9bf1SSrinivas Kandagatla break; 46236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_DST_IN_PORT_ID: 46336ad9bf1SSrinivas Kandagatla dst_mod_ip_port_id = le32_to_cpu(mod_elem->value); 464*c6c203bcSNathan Chancellor break; 46536ad9bf1SSrinivas Kandagatla default: 46636ad9bf1SSrinivas Kandagatla break; 46736ad9bf1SSrinivas Kandagatla 46836ad9bf1SSrinivas Kandagatla } 46936ad9bf1SSrinivas Kandagatla tkn_count++; 47036ad9bf1SSrinivas Kandagatla mod_elem++; 47136ad9bf1SSrinivas Kandagatla } 47236ad9bf1SSrinivas Kandagatla 47336ad9bf1SSrinivas Kandagatla if (mod) { 47436ad9bf1SSrinivas Kandagatla mod->module_id = module_id; 47536ad9bf1SSrinivas Kandagatla mod->max_ip_port = max_ip_port; 47636ad9bf1SSrinivas Kandagatla mod->max_op_port = max_op_port; 47736ad9bf1SSrinivas Kandagatla mod->in_port = in_port; 47836ad9bf1SSrinivas Kandagatla mod->out_port = out_port; 47936ad9bf1SSrinivas Kandagatla mod->src_mod_inst_id = src_mod_inst_id; 48036ad9bf1SSrinivas Kandagatla mod->src_mod_op_port_id = src_mod_op_port_id; 48136ad9bf1SSrinivas Kandagatla mod->dst_mod_inst_id = dst_mod_inst_id; 48236ad9bf1SSrinivas Kandagatla mod->dst_mod_ip_port_id = dst_mod_ip_port_id; 48336ad9bf1SSrinivas Kandagatla } 48436ad9bf1SSrinivas Kandagatla 48536ad9bf1SSrinivas Kandagatla return mod; 48636ad9bf1SSrinivas Kandagatla } 48736ad9bf1SSrinivas Kandagatla 48836ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_module_common(struct snd_soc_component *component, 48936ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 49036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 49136ad9bf1SSrinivas Kandagatla { 49236ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(component->dev); 49336ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 49436ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg; 49536ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 49636ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 49736ad9bf1SSrinivas Kandagatla 49836ad9bf1SSrinivas Kandagatla sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv); 49936ad9bf1SSrinivas Kandagatla if (IS_ERR(sg)) 50036ad9bf1SSrinivas Kandagatla return PTR_ERR(sg); 50136ad9bf1SSrinivas Kandagatla 50236ad9bf1SSrinivas Kandagatla cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv); 50336ad9bf1SSrinivas Kandagatla if (IS_ERR(cont)) 50436ad9bf1SSrinivas Kandagatla return PTR_ERR(cont); 50536ad9bf1SSrinivas Kandagatla 50636ad9bf1SSrinivas Kandagatla mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w); 50736ad9bf1SSrinivas Kandagatla if (IS_ERR(mod)) 50836ad9bf1SSrinivas Kandagatla return PTR_ERR(mod); 50936ad9bf1SSrinivas Kandagatla 51036ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 51136ad9bf1SSrinivas Kandagatla dobj->private = mod; 51236ad9bf1SSrinivas Kandagatla 51336ad9bf1SSrinivas Kandagatla return 0; 51436ad9bf1SSrinivas Kandagatla } 51536ad9bf1SSrinivas Kandagatla 51636ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component, 51736ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 51836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 51936ad9bf1SSrinivas Kandagatla { 52036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 52136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 52236ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 52336ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 52436ad9bf1SSrinivas Kandagatla int tkn_count = 0; 52536ad9bf1SSrinivas Kandagatla int ret; 52636ad9bf1SSrinivas Kandagatla 52736ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 52836ad9bf1SSrinivas Kandagatla if (ret) 52936ad9bf1SSrinivas Kandagatla return ret; 53036ad9bf1SSrinivas Kandagatla 53136ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 53236ad9bf1SSrinivas Kandagatla mod = dobj->private; 53336ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(&tplg_w->priv); 53436ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 53536ad9bf1SSrinivas Kandagatla 53636ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 53736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 53836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_INTERLEAVE: 53936ad9bf1SSrinivas Kandagatla mod->interleave_type = le32_to_cpu(mod_elem->value); 54036ad9bf1SSrinivas Kandagatla break; 54136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE: 54236ad9bf1SSrinivas Kandagatla mod->rate = le32_to_cpu(mod_elem->value); 54336ad9bf1SSrinivas Kandagatla break; 54436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_BIT_DEPTH: 54536ad9bf1SSrinivas Kandagatla mod->bit_depth = le32_to_cpu(mod_elem->value); 54636ad9bf1SSrinivas Kandagatla break; 54736ad9bf1SSrinivas Kandagatla default: 54836ad9bf1SSrinivas Kandagatla break; 54936ad9bf1SSrinivas Kandagatla } 55036ad9bf1SSrinivas Kandagatla tkn_count++; 55136ad9bf1SSrinivas Kandagatla mod_elem++; 55236ad9bf1SSrinivas Kandagatla } 55336ad9bf1SSrinivas Kandagatla 55436ad9bf1SSrinivas Kandagatla return 0; 55536ad9bf1SSrinivas Kandagatla } 55636ad9bf1SSrinivas Kandagatla 55736ad9bf1SSrinivas Kandagatla static int audioreach_widget_log_module_load(struct audioreach_module *mod, 55836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 55936ad9bf1SSrinivas Kandagatla { 56036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 56136ad9bf1SSrinivas Kandagatla int tkn_count = 0; 56236ad9bf1SSrinivas Kandagatla 56336ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 56436ad9bf1SSrinivas Kandagatla 56536ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 56636ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 56736ad9bf1SSrinivas Kandagatla 56836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_CODE: 56936ad9bf1SSrinivas Kandagatla mod->log_code = le32_to_cpu(mod_elem->value); 57036ad9bf1SSrinivas Kandagatla break; 57136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID: 57236ad9bf1SSrinivas Kandagatla mod->log_tap_point_id = le32_to_cpu(mod_elem->value); 57336ad9bf1SSrinivas Kandagatla break; 57436ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_LOG_MODE: 57536ad9bf1SSrinivas Kandagatla mod->log_mode = le32_to_cpu(mod_elem->value); 57636ad9bf1SSrinivas Kandagatla break; 57736ad9bf1SSrinivas Kandagatla default: 57836ad9bf1SSrinivas Kandagatla break; 57936ad9bf1SSrinivas Kandagatla } 58036ad9bf1SSrinivas Kandagatla tkn_count++; 58136ad9bf1SSrinivas Kandagatla mod_elem++; 58236ad9bf1SSrinivas Kandagatla } 58336ad9bf1SSrinivas Kandagatla 58436ad9bf1SSrinivas Kandagatla return 0; 58536ad9bf1SSrinivas Kandagatla } 58636ad9bf1SSrinivas Kandagatla 58736ad9bf1SSrinivas Kandagatla static int audioreach_widget_dma_module_load(struct audioreach_module *mod, 58836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 58936ad9bf1SSrinivas Kandagatla { 59036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 59136ad9bf1SSrinivas Kandagatla int tkn_count = 0; 59236ad9bf1SSrinivas Kandagatla 59336ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 59436ad9bf1SSrinivas Kandagatla 59536ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 59636ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 59736ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_IDX: 59836ad9bf1SSrinivas Kandagatla mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 59936ad9bf1SSrinivas Kandagatla break; 60036ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_DATA: 60136ad9bf1SSrinivas Kandagatla mod->data_format = le32_to_cpu(mod_elem->value); 60236ad9bf1SSrinivas Kandagatla break; 60336ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_TYPE: 60436ad9bf1SSrinivas Kandagatla mod->hw_interface_type = le32_to_cpu(mod_elem->value); 60536ad9bf1SSrinivas Kandagatla break; 60636ad9bf1SSrinivas Kandagatla default: 60736ad9bf1SSrinivas Kandagatla break; 60836ad9bf1SSrinivas Kandagatla } 60936ad9bf1SSrinivas Kandagatla tkn_count++; 61036ad9bf1SSrinivas Kandagatla mod_elem++; 61136ad9bf1SSrinivas Kandagatla } 61236ad9bf1SSrinivas Kandagatla 61336ad9bf1SSrinivas Kandagatla return 0; 61436ad9bf1SSrinivas Kandagatla } 61536ad9bf1SSrinivas Kandagatla 61636ad9bf1SSrinivas Kandagatla static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, 61736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array) 61836ad9bf1SSrinivas Kandagatla { 61936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *mod_elem; 62036ad9bf1SSrinivas Kandagatla int tkn_count = 0; 62136ad9bf1SSrinivas Kandagatla 62236ad9bf1SSrinivas Kandagatla mod_elem = mod_array->value; 62336ad9bf1SSrinivas Kandagatla 62436ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { 62536ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(mod_elem->token)) { 62636ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_IDX: 62736ad9bf1SSrinivas Kandagatla mod->hw_interface_idx = le32_to_cpu(mod_elem->value); 62836ad9bf1SSrinivas Kandagatla break; 62936ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_FMT_DATA: 63036ad9bf1SSrinivas Kandagatla mod->data_format = le32_to_cpu(mod_elem->value); 63136ad9bf1SSrinivas Kandagatla break; 63236ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_HW_IF_TYPE: 63336ad9bf1SSrinivas Kandagatla mod->hw_interface_type = le32_to_cpu(mod_elem->value); 63436ad9bf1SSrinivas Kandagatla break; 63536ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_SD_LINE_IDX: 63636ad9bf1SSrinivas Kandagatla mod->sd_line_idx = le32_to_cpu(mod_elem->value); 63736ad9bf1SSrinivas Kandagatla break; 63836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_MODULE_WS_SRC: 63936ad9bf1SSrinivas Kandagatla mod->ws_src = le32_to_cpu(mod_elem->value); 64036ad9bf1SSrinivas Kandagatla break; 64136ad9bf1SSrinivas Kandagatla default: 64236ad9bf1SSrinivas Kandagatla break; 64336ad9bf1SSrinivas Kandagatla } 64436ad9bf1SSrinivas Kandagatla tkn_count++; 64536ad9bf1SSrinivas Kandagatla mod_elem++; 64636ad9bf1SSrinivas Kandagatla } 64736ad9bf1SSrinivas Kandagatla 64836ad9bf1SSrinivas Kandagatla return 0; 64936ad9bf1SSrinivas Kandagatla } 65036ad9bf1SSrinivas Kandagatla 65136ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_buffer(struct snd_soc_component *component, 65236ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 65336ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 65436ad9bf1SSrinivas Kandagatla { 65536ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *mod_array; 65636ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 65736ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 65836ad9bf1SSrinivas Kandagatla int ret; 65936ad9bf1SSrinivas Kandagatla 66036ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 66136ad9bf1SSrinivas Kandagatla if (ret) 66236ad9bf1SSrinivas Kandagatla return ret; 66336ad9bf1SSrinivas Kandagatla 66436ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 66536ad9bf1SSrinivas Kandagatla mod = dobj->private; 66636ad9bf1SSrinivas Kandagatla 66736ad9bf1SSrinivas Kandagatla mod_array = audioreach_get_module_array(&tplg_w->priv); 66836ad9bf1SSrinivas Kandagatla 66936ad9bf1SSrinivas Kandagatla switch (mod->module_id) { 67036ad9bf1SSrinivas Kandagatla case MODULE_ID_CODEC_DMA_SINK: 67136ad9bf1SSrinivas Kandagatla case MODULE_ID_CODEC_DMA_SOURCE: 67236ad9bf1SSrinivas Kandagatla audioreach_widget_dma_module_load(mod, mod_array); 67336ad9bf1SSrinivas Kandagatla break; 67436ad9bf1SSrinivas Kandagatla case MODULE_ID_DATA_LOGGING: 67536ad9bf1SSrinivas Kandagatla audioreach_widget_log_module_load(mod, mod_array); 67636ad9bf1SSrinivas Kandagatla break; 67736ad9bf1SSrinivas Kandagatla case MODULE_ID_I2S_SINK: 67836ad9bf1SSrinivas Kandagatla case MODULE_ID_I2S_SOURCE: 67936ad9bf1SSrinivas Kandagatla audioreach_widget_i2s_module_load(mod, mod_array); 68036ad9bf1SSrinivas Kandagatla break; 68136ad9bf1SSrinivas Kandagatla default: 68236ad9bf1SSrinivas Kandagatla return -EINVAL; 68336ad9bf1SSrinivas Kandagatla } 68436ad9bf1SSrinivas Kandagatla 68536ad9bf1SSrinivas Kandagatla return 0; 68636ad9bf1SSrinivas Kandagatla } 68736ad9bf1SSrinivas Kandagatla 68836ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_mixer(struct snd_soc_component *component, 68936ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 69036ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 69136ad9bf1SSrinivas Kandagatla { 69236ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *w_elem; 69336ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *w_array; 69436ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol; 69536ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 69636ad9bf1SSrinivas Kandagatla int tkn_count = 0; 69736ad9bf1SSrinivas Kandagatla 69836ad9bf1SSrinivas Kandagatla w_array = &tplg_w->priv.array[0]; 69936ad9bf1SSrinivas Kandagatla 70036ad9bf1SSrinivas Kandagatla scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 70136ad9bf1SSrinivas Kandagatla if (!scontrol) 70236ad9bf1SSrinivas Kandagatla return -ENOMEM; 70336ad9bf1SSrinivas Kandagatla 70436ad9bf1SSrinivas Kandagatla scontrol->scomp = component; 70536ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 70636ad9bf1SSrinivas Kandagatla dobj->private = scontrol; 70736ad9bf1SSrinivas Kandagatla 70836ad9bf1SSrinivas Kandagatla w_elem = w_array->value; 70936ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) { 71036ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(w_elem->token)) { 71136ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 71236ad9bf1SSrinivas Kandagatla scontrol->sgid = le32_to_cpu(w_elem->value); 71336ad9bf1SSrinivas Kandagatla break; 71436ad9bf1SSrinivas Kandagatla default: /* ignore other tokens */ 71536ad9bf1SSrinivas Kandagatla break; 71636ad9bf1SSrinivas Kandagatla } 71736ad9bf1SSrinivas Kandagatla tkn_count++; 71836ad9bf1SSrinivas Kandagatla w_elem++; 71936ad9bf1SSrinivas Kandagatla } 72036ad9bf1SSrinivas Kandagatla 72136ad9bf1SSrinivas Kandagatla return 0; 72236ad9bf1SSrinivas Kandagatla } 72336ad9bf1SSrinivas Kandagatla 72436ad9bf1SSrinivas Kandagatla static int audioreach_pga_event(struct snd_soc_dapm_widget *w, 72536ad9bf1SSrinivas Kandagatla struct snd_kcontrol *kcontrol, int event) 72636ad9bf1SSrinivas Kandagatla 72736ad9bf1SSrinivas Kandagatla { 72836ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = w->dapm; 72936ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 73036ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = w->dobj.private; 73136ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(c->dev); 73236ad9bf1SSrinivas Kandagatla 73336ad9bf1SSrinivas Kandagatla switch (event) { 73436ad9bf1SSrinivas Kandagatla case SND_SOC_DAPM_POST_PMU: 73536ad9bf1SSrinivas Kandagatla /* apply gain after power up of widget */ 73636ad9bf1SSrinivas Kandagatla audioreach_gain_set_vol_ctrl(apm, mod, mod->gain); 73736ad9bf1SSrinivas Kandagatla break; 73836ad9bf1SSrinivas Kandagatla default: 73936ad9bf1SSrinivas Kandagatla break; 74036ad9bf1SSrinivas Kandagatla } 74136ad9bf1SSrinivas Kandagatla 74236ad9bf1SSrinivas Kandagatla return 0; 74336ad9bf1SSrinivas Kandagatla } 74436ad9bf1SSrinivas Kandagatla 74536ad9bf1SSrinivas Kandagatla static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = { 74636ad9bf1SSrinivas Kandagatla { AR_PGA_DAPM_EVENT, audioreach_pga_event }, 74736ad9bf1SSrinivas Kandagatla }; 74836ad9bf1SSrinivas Kandagatla 74936ad9bf1SSrinivas Kandagatla static int audioreach_widget_load_pga(struct snd_soc_component *component, 75036ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 75136ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 75236ad9bf1SSrinivas Kandagatla { 75336ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 75436ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 75536ad9bf1SSrinivas Kandagatla int ret; 75636ad9bf1SSrinivas Kandagatla 75736ad9bf1SSrinivas Kandagatla ret = audioreach_widget_load_module_common(component, index, w, tplg_w); 75836ad9bf1SSrinivas Kandagatla if (ret) 75936ad9bf1SSrinivas Kandagatla return ret; 76036ad9bf1SSrinivas Kandagatla 76136ad9bf1SSrinivas Kandagatla dobj = &w->dobj; 76236ad9bf1SSrinivas Kandagatla mod = dobj->private; 76336ad9bf1SSrinivas Kandagatla mod->gain = VOL_CTRL_DEFAULT_GAIN; 76436ad9bf1SSrinivas Kandagatla 76536ad9bf1SSrinivas Kandagatla ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops, 76636ad9bf1SSrinivas Kandagatla ARRAY_SIZE(audioreach_widget_ops), 76736ad9bf1SSrinivas Kandagatla le16_to_cpu(tplg_w->event_type)); 76836ad9bf1SSrinivas Kandagatla if (ret) { 76936ad9bf1SSrinivas Kandagatla dev_err(component->dev, "matching event handlers NOT found for %d\n", 77036ad9bf1SSrinivas Kandagatla le16_to_cpu(tplg_w->event_type)); 77136ad9bf1SSrinivas Kandagatla return -EINVAL; 77236ad9bf1SSrinivas Kandagatla } 77336ad9bf1SSrinivas Kandagatla 77436ad9bf1SSrinivas Kandagatla return 0; 77536ad9bf1SSrinivas Kandagatla } 77636ad9bf1SSrinivas Kandagatla 77736ad9bf1SSrinivas Kandagatla static int audioreach_widget_ready(struct snd_soc_component *component, 77836ad9bf1SSrinivas Kandagatla int index, struct snd_soc_dapm_widget *w, 77936ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_dapm_widget *tplg_w) 78036ad9bf1SSrinivas Kandagatla { 78136ad9bf1SSrinivas Kandagatla switch (w->id) { 78236ad9bf1SSrinivas Kandagatla case snd_soc_dapm_aif_in: 78336ad9bf1SSrinivas Kandagatla case snd_soc_dapm_aif_out: 78436ad9bf1SSrinivas Kandagatla audioreach_widget_load_buffer(component, index, w, tplg_w); 78536ad9bf1SSrinivas Kandagatla break; 78636ad9bf1SSrinivas Kandagatla case snd_soc_dapm_decoder: 78736ad9bf1SSrinivas Kandagatla case snd_soc_dapm_encoder: 78836ad9bf1SSrinivas Kandagatla case snd_soc_dapm_src: 78936ad9bf1SSrinivas Kandagatla audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w); 79036ad9bf1SSrinivas Kandagatla break; 79136ad9bf1SSrinivas Kandagatla case snd_soc_dapm_buffer: 79236ad9bf1SSrinivas Kandagatla audioreach_widget_load_buffer(component, index, w, tplg_w); 79336ad9bf1SSrinivas Kandagatla break; 79436ad9bf1SSrinivas Kandagatla case snd_soc_dapm_mixer: 79536ad9bf1SSrinivas Kandagatla return audioreach_widget_load_mixer(component, index, w, tplg_w); 79636ad9bf1SSrinivas Kandagatla case snd_soc_dapm_pga: 79736ad9bf1SSrinivas Kandagatla return audioreach_widget_load_pga(component, index, w, tplg_w); 79836ad9bf1SSrinivas Kandagatla case snd_soc_dapm_dai_link: 79936ad9bf1SSrinivas Kandagatla case snd_soc_dapm_scheduler: 80036ad9bf1SSrinivas Kandagatla case snd_soc_dapm_out_drv: 80136ad9bf1SSrinivas Kandagatla default: 80236ad9bf1SSrinivas Kandagatla dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id); 80336ad9bf1SSrinivas Kandagatla break; 80436ad9bf1SSrinivas Kandagatla } 80536ad9bf1SSrinivas Kandagatla 80636ad9bf1SSrinivas Kandagatla return 0; 80736ad9bf1SSrinivas Kandagatla } 80836ad9bf1SSrinivas Kandagatla 80936ad9bf1SSrinivas Kandagatla static int audioreach_widget_unload(struct snd_soc_component *scomp, 81036ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 81136ad9bf1SSrinivas Kandagatla { 81236ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj); 81336ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(scomp->dev); 81436ad9bf1SSrinivas Kandagatla struct audioreach_container *cont; 81536ad9bf1SSrinivas Kandagatla struct audioreach_module *mod; 81636ad9bf1SSrinivas Kandagatla 81736ad9bf1SSrinivas Kandagatla mod = dobj->private; 81836ad9bf1SSrinivas Kandagatla cont = mod->container; 81936ad9bf1SSrinivas Kandagatla 82036ad9bf1SSrinivas Kandagatla if (w->id == snd_soc_dapm_mixer) { 82136ad9bf1SSrinivas Kandagatla /* virtual widget */ 82236ad9bf1SSrinivas Kandagatla kfree(dobj->private); 82336ad9bf1SSrinivas Kandagatla return 0; 82436ad9bf1SSrinivas Kandagatla } 82536ad9bf1SSrinivas Kandagatla 82636ad9bf1SSrinivas Kandagatla mutex_lock(&apm->lock); 82736ad9bf1SSrinivas Kandagatla idr_remove(&apm->modules_idr, mod->instance_id); 82836ad9bf1SSrinivas Kandagatla cont->num_modules--; 82936ad9bf1SSrinivas Kandagatla 83036ad9bf1SSrinivas Kandagatla list_del(&mod->node); 83136ad9bf1SSrinivas Kandagatla kfree(mod); 83236ad9bf1SSrinivas Kandagatla /* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */ 83336ad9bf1SSrinivas Kandagatla if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */ 83436ad9bf1SSrinivas Kandagatla struct audioreach_sub_graph *sg = cont->sub_graph; 83536ad9bf1SSrinivas Kandagatla 83636ad9bf1SSrinivas Kandagatla idr_remove(&apm->containers_idr, cont->container_id); 83736ad9bf1SSrinivas Kandagatla list_del(&cont->node); 83836ad9bf1SSrinivas Kandagatla sg->num_containers--; 83936ad9bf1SSrinivas Kandagatla kfree(cont); 84036ad9bf1SSrinivas Kandagatla /* check if there are no more containers in the sub graph and remove it */ 84136ad9bf1SSrinivas Kandagatla if (list_empty(&sg->container_list)) { 84236ad9bf1SSrinivas Kandagatla struct audioreach_graph_info *info = sg->info; 84336ad9bf1SSrinivas Kandagatla 84436ad9bf1SSrinivas Kandagatla idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id); 84536ad9bf1SSrinivas Kandagatla list_del(&sg->node); 84636ad9bf1SSrinivas Kandagatla info->num_sub_graphs--; 84736ad9bf1SSrinivas Kandagatla kfree(sg); 84836ad9bf1SSrinivas Kandagatla /* Check if there are no more sub-graphs left then remove graph info */ 84936ad9bf1SSrinivas Kandagatla if (list_empty(&info->sg_list)) { 85036ad9bf1SSrinivas Kandagatla idr_remove(&apm->graph_info_idr, info->id); 85136ad9bf1SSrinivas Kandagatla kfree(info); 85236ad9bf1SSrinivas Kandagatla } 85336ad9bf1SSrinivas Kandagatla } 85436ad9bf1SSrinivas Kandagatla } 85536ad9bf1SSrinivas Kandagatla 85636ad9bf1SSrinivas Kandagatla mutex_unlock(&apm->lock); 85736ad9bf1SSrinivas Kandagatla 85836ad9bf1SSrinivas Kandagatla return 0; 85936ad9bf1SSrinivas Kandagatla } 86036ad9bf1SSrinivas Kandagatla 86136ad9bf1SSrinivas Kandagatla static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp, 86236ad9bf1SSrinivas Kandagatla const char *name) 86336ad9bf1SSrinivas Kandagatla { 86436ad9bf1SSrinivas Kandagatla struct q6apm *apm = dev_get_drvdata(comp->dev); 86536ad9bf1SSrinivas Kandagatla struct audioreach_module *module; 86636ad9bf1SSrinivas Kandagatla int id; 86736ad9bf1SSrinivas Kandagatla 86836ad9bf1SSrinivas Kandagatla idr_for_each_entry(&apm->modules_idr, module, id) { 86936ad9bf1SSrinivas Kandagatla if (!strcmp(name, module->widget->name)) 87036ad9bf1SSrinivas Kandagatla return module; 87136ad9bf1SSrinivas Kandagatla } 87236ad9bf1SSrinivas Kandagatla 87336ad9bf1SSrinivas Kandagatla return NULL; 87436ad9bf1SSrinivas Kandagatla } 87536ad9bf1SSrinivas Kandagatla 87636ad9bf1SSrinivas Kandagatla static int audioreach_route_load(struct snd_soc_component *scomp, int index, 87736ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_route *route) 87836ad9bf1SSrinivas Kandagatla { 87936ad9bf1SSrinivas Kandagatla struct audioreach_module *src, *sink; 88036ad9bf1SSrinivas Kandagatla 88136ad9bf1SSrinivas Kandagatla src = audioreach_find_widget(scomp, route->source); 88236ad9bf1SSrinivas Kandagatla sink = audioreach_find_widget(scomp, route->sink); 88336ad9bf1SSrinivas Kandagatla 88436ad9bf1SSrinivas Kandagatla if (src && sink) { 88536ad9bf1SSrinivas Kandagatla src->dst_mod_inst_id = sink->instance_id; 88636ad9bf1SSrinivas Kandagatla sink->src_mod_inst_id = src->instance_id; 88736ad9bf1SSrinivas Kandagatla } 88836ad9bf1SSrinivas Kandagatla 88936ad9bf1SSrinivas Kandagatla return 0; 89036ad9bf1SSrinivas Kandagatla } 89136ad9bf1SSrinivas Kandagatla 89236ad9bf1SSrinivas Kandagatla static int audioreach_route_unload(struct snd_soc_component *scomp, 89336ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 89436ad9bf1SSrinivas Kandagatla { 89536ad9bf1SSrinivas Kandagatla return 0; 89636ad9bf1SSrinivas Kandagatla } 89736ad9bf1SSrinivas Kandagatla 89836ad9bf1SSrinivas Kandagatla static int audioreach_tplg_complete(struct snd_soc_component *component) 89936ad9bf1SSrinivas Kandagatla { 90036ad9bf1SSrinivas Kandagatla /* TBD */ 90136ad9bf1SSrinivas Kandagatla return 0; 90236ad9bf1SSrinivas Kandagatla } 90336ad9bf1SSrinivas Kandagatla 90436ad9bf1SSrinivas Kandagatla /* DAI link - used for any driver specific init */ 90536ad9bf1SSrinivas Kandagatla static int audioreach_link_load(struct snd_soc_component *component, int index, 90636ad9bf1SSrinivas Kandagatla struct snd_soc_dai_link *link, 90736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_link_config *cfg) 90836ad9bf1SSrinivas Kandagatla { 90936ad9bf1SSrinivas Kandagatla link->nonatomic = true; 91036ad9bf1SSrinivas Kandagatla link->dynamic = true; 91136ad9bf1SSrinivas Kandagatla link->platforms->name = NULL; 91236ad9bf1SSrinivas Kandagatla link->platforms->of_node = of_get_compatible_child(component->dev->of_node, 91336ad9bf1SSrinivas Kandagatla "qcom,q6apm-dais"); 91436ad9bf1SSrinivas Kandagatla return 0; 91536ad9bf1SSrinivas Kandagatla } 91636ad9bf1SSrinivas Kandagatla 91736ad9bf1SSrinivas Kandagatla static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol, 91836ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 91936ad9bf1SSrinivas Kandagatla { 92036ad9bf1SSrinivas Kandagatla struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 92136ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 92236ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 92336ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 92436ad9bf1SSrinivas Kandagatla struct snd_ar_control *dapm_scontrol = dw->dobj.private; 92536ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = mc->dobj.private; 92636ad9bf1SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(c->dev); 92736ad9bf1SSrinivas Kandagatla bool connected; 92836ad9bf1SSrinivas Kandagatla 92936ad9bf1SSrinivas Kandagatla connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid); 93036ad9bf1SSrinivas Kandagatla if (connected) 93136ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = 1; 93236ad9bf1SSrinivas Kandagatla else 93336ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = 0; 93436ad9bf1SSrinivas Kandagatla 93536ad9bf1SSrinivas Kandagatla return 0; 93636ad9bf1SSrinivas Kandagatla } 93736ad9bf1SSrinivas Kandagatla 93836ad9bf1SSrinivas Kandagatla static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol, 93936ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 94036ad9bf1SSrinivas Kandagatla { 94136ad9bf1SSrinivas Kandagatla struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 94236ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); 94336ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 94436ad9bf1SSrinivas Kandagatla struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); 94536ad9bf1SSrinivas Kandagatla struct snd_ar_control *dapm_scontrol = dw->dobj.private; 94636ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = mc->dobj.private; 94736ad9bf1SSrinivas Kandagatla struct q6apm *data = dev_get_drvdata(c->dev); 94836ad9bf1SSrinivas Kandagatla 94936ad9bf1SSrinivas Kandagatla if (ucontrol->value.integer.value[0]) { 95036ad9bf1SSrinivas Kandagatla q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true); 95136ad9bf1SSrinivas Kandagatla snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL); 95236ad9bf1SSrinivas Kandagatla } else { 95336ad9bf1SSrinivas Kandagatla q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false); 95436ad9bf1SSrinivas Kandagatla snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL); 95536ad9bf1SSrinivas Kandagatla } 95636ad9bf1SSrinivas Kandagatla return 0; 95736ad9bf1SSrinivas Kandagatla } 95836ad9bf1SSrinivas Kandagatla 95936ad9bf1SSrinivas Kandagatla static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 96036ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 96136ad9bf1SSrinivas Kandagatla { 96236ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 96336ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = dw->dobj.private; 96436ad9bf1SSrinivas Kandagatla 96536ad9bf1SSrinivas Kandagatla ucontrol->value.integer.value[0] = mod->gain; 96636ad9bf1SSrinivas Kandagatla 96736ad9bf1SSrinivas Kandagatla return 0; 96836ad9bf1SSrinivas Kandagatla } 96936ad9bf1SSrinivas Kandagatla 97036ad9bf1SSrinivas Kandagatla static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, 97136ad9bf1SSrinivas Kandagatla struct snd_ctl_elem_value *ucontrol) 97236ad9bf1SSrinivas Kandagatla { 97336ad9bf1SSrinivas Kandagatla struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); 97436ad9bf1SSrinivas Kandagatla struct audioreach_module *mod = dw->dobj.private; 97536ad9bf1SSrinivas Kandagatla 97636ad9bf1SSrinivas Kandagatla mod->gain = ucontrol->value.integer.value[0]; 97736ad9bf1SSrinivas Kandagatla 97836ad9bf1SSrinivas Kandagatla return 1; 97936ad9bf1SSrinivas Kandagatla } 98036ad9bf1SSrinivas Kandagatla 98136ad9bf1SSrinivas Kandagatla static int audioreach_control_load_mix(struct snd_soc_component *scomp, 98236ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol, 98336ad9bf1SSrinivas Kandagatla struct snd_kcontrol_new *kc, 98436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_ctl_hdr *hdr) 98536ad9bf1SSrinivas Kandagatla { 98636ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_value_elem *c_elem; 98736ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_vendor_array *c_array; 98836ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_mixer_control *mc; 98936ad9bf1SSrinivas Kandagatla int tkn_count = 0; 99036ad9bf1SSrinivas Kandagatla 99136ad9bf1SSrinivas Kandagatla mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); 99236ad9bf1SSrinivas Kandagatla c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data; 99336ad9bf1SSrinivas Kandagatla 99436ad9bf1SSrinivas Kandagatla c_elem = c_array->value; 99536ad9bf1SSrinivas Kandagatla 99636ad9bf1SSrinivas Kandagatla while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) { 99736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(c_elem->token)) { 99836ad9bf1SSrinivas Kandagatla case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: 99936ad9bf1SSrinivas Kandagatla scontrol->sgid = le32_to_cpu(c_elem->value); 100036ad9bf1SSrinivas Kandagatla break; 100136ad9bf1SSrinivas Kandagatla default: 100236ad9bf1SSrinivas Kandagatla /* Ignore other tokens */ 100336ad9bf1SSrinivas Kandagatla break; 100436ad9bf1SSrinivas Kandagatla } 100536ad9bf1SSrinivas Kandagatla c_elem++; 100636ad9bf1SSrinivas Kandagatla tkn_count++; 100736ad9bf1SSrinivas Kandagatla } 100836ad9bf1SSrinivas Kandagatla 100936ad9bf1SSrinivas Kandagatla return 0; 101036ad9bf1SSrinivas Kandagatla } 101136ad9bf1SSrinivas Kandagatla 101236ad9bf1SSrinivas Kandagatla static int audioreach_control_load(struct snd_soc_component *scomp, int index, 101336ad9bf1SSrinivas Kandagatla struct snd_kcontrol_new *kc, 101436ad9bf1SSrinivas Kandagatla struct snd_soc_tplg_ctl_hdr *hdr) 101536ad9bf1SSrinivas Kandagatla { 101636ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol; 101736ad9bf1SSrinivas Kandagatla struct soc_mixer_control *sm; 101836ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj; 101936ad9bf1SSrinivas Kandagatla int ret = 0; 102036ad9bf1SSrinivas Kandagatla 102136ad9bf1SSrinivas Kandagatla scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); 102236ad9bf1SSrinivas Kandagatla if (!scontrol) 102336ad9bf1SSrinivas Kandagatla return -ENOMEM; 102436ad9bf1SSrinivas Kandagatla 102536ad9bf1SSrinivas Kandagatla scontrol->scomp = scomp; 102636ad9bf1SSrinivas Kandagatla 102736ad9bf1SSrinivas Kandagatla switch (le32_to_cpu(hdr->ops.get)) { 102836ad9bf1SSrinivas Kandagatla case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX: 102936ad9bf1SSrinivas Kandagatla sm = (struct soc_mixer_control *)kc->private_value; 103036ad9bf1SSrinivas Kandagatla dobj = &sm->dobj; 103136ad9bf1SSrinivas Kandagatla ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr); 103236ad9bf1SSrinivas Kandagatla break; 103336ad9bf1SSrinivas Kandagatla case SND_SOC_AR_TPLG_VOL_CTL: 103436ad9bf1SSrinivas Kandagatla sm = (struct soc_mixer_control *)kc->private_value; 103536ad9bf1SSrinivas Kandagatla dobj = &sm->dobj; 103636ad9bf1SSrinivas Kandagatla break; 103736ad9bf1SSrinivas Kandagatla default: 103836ad9bf1SSrinivas Kandagatla dev_warn(scomp->dev, "control type not supported %d:%d:%d\n", 103936ad9bf1SSrinivas Kandagatla hdr->ops.get, hdr->ops.put, hdr->ops.info); 104036ad9bf1SSrinivas Kandagatla kfree(scontrol); 104136ad9bf1SSrinivas Kandagatla return -EINVAL; 104236ad9bf1SSrinivas Kandagatla } 104336ad9bf1SSrinivas Kandagatla 104436ad9bf1SSrinivas Kandagatla dobj->private = scontrol; 104536ad9bf1SSrinivas Kandagatla return ret; 104636ad9bf1SSrinivas Kandagatla } 104736ad9bf1SSrinivas Kandagatla 104836ad9bf1SSrinivas Kandagatla static int audioreach_control_unload(struct snd_soc_component *scomp, 104936ad9bf1SSrinivas Kandagatla struct snd_soc_dobj *dobj) 105036ad9bf1SSrinivas Kandagatla { 105136ad9bf1SSrinivas Kandagatla struct snd_ar_control *scontrol = dobj->private; 105236ad9bf1SSrinivas Kandagatla 105336ad9bf1SSrinivas Kandagatla kfree(scontrol); 105436ad9bf1SSrinivas Kandagatla 105536ad9bf1SSrinivas Kandagatla return 0; 105636ad9bf1SSrinivas Kandagatla } 105736ad9bf1SSrinivas Kandagatla 105836ad9bf1SSrinivas Kandagatla static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = { 105936ad9bf1SSrinivas Kandagatla {SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer, 106036ad9bf1SSrinivas Kandagatla audioreach_put_audio_mixer, snd_soc_info_volsw}, 106136ad9bf1SSrinivas Kandagatla {SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer, 106236ad9bf1SSrinivas Kandagatla audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw}, 106336ad9bf1SSrinivas Kandagatla }; 106436ad9bf1SSrinivas Kandagatla 106536ad9bf1SSrinivas Kandagatla static struct snd_soc_tplg_ops audioreach_tplg_ops = { 106636ad9bf1SSrinivas Kandagatla .io_ops = audioreach_io_ops, 106736ad9bf1SSrinivas Kandagatla .io_ops_count = ARRAY_SIZE(audioreach_io_ops), 106836ad9bf1SSrinivas Kandagatla 106936ad9bf1SSrinivas Kandagatla .control_load = audioreach_control_load, 107036ad9bf1SSrinivas Kandagatla .control_unload = audioreach_control_unload, 107136ad9bf1SSrinivas Kandagatla 107236ad9bf1SSrinivas Kandagatla .widget_ready = audioreach_widget_ready, 107336ad9bf1SSrinivas Kandagatla .widget_unload = audioreach_widget_unload, 107436ad9bf1SSrinivas Kandagatla 107536ad9bf1SSrinivas Kandagatla .complete = audioreach_tplg_complete, 107636ad9bf1SSrinivas Kandagatla .link_load = audioreach_link_load, 107736ad9bf1SSrinivas Kandagatla 107836ad9bf1SSrinivas Kandagatla .dapm_route_load = audioreach_route_load, 107936ad9bf1SSrinivas Kandagatla .dapm_route_unload = audioreach_route_unload, 108036ad9bf1SSrinivas Kandagatla }; 108136ad9bf1SSrinivas Kandagatla 108236ad9bf1SSrinivas Kandagatla int audioreach_tplg_init(struct snd_soc_component *component) 108336ad9bf1SSrinivas Kandagatla { 108436ad9bf1SSrinivas Kandagatla struct snd_soc_card *card = component->card; 108536ad9bf1SSrinivas Kandagatla struct device *dev = component->dev; 108636ad9bf1SSrinivas Kandagatla const struct firmware *fw; 108736ad9bf1SSrinivas Kandagatla char *tplg_fw_name; 108836ad9bf1SSrinivas Kandagatla int ret; 108936ad9bf1SSrinivas Kandagatla 109036ad9bf1SSrinivas Kandagatla /* Inline with Qualcomm UCM configs and linux-firmware path */ 109136ad9bf1SSrinivas Kandagatla tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name); 109236ad9bf1SSrinivas Kandagatla if (!tplg_fw_name) 109336ad9bf1SSrinivas Kandagatla return -ENOMEM; 109436ad9bf1SSrinivas Kandagatla 109536ad9bf1SSrinivas Kandagatla ret = request_firmware(&fw, tplg_fw_name, dev); 109636ad9bf1SSrinivas Kandagatla if (ret < 0) { 109736ad9bf1SSrinivas Kandagatla dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); 109836ad9bf1SSrinivas Kandagatla goto err; 109936ad9bf1SSrinivas Kandagatla } 110036ad9bf1SSrinivas Kandagatla 110136ad9bf1SSrinivas Kandagatla ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw); 110236ad9bf1SSrinivas Kandagatla if (ret < 0) { 110336ad9bf1SSrinivas Kandagatla dev_err(dev, "tplg component load failed%d\n", ret); 110436ad9bf1SSrinivas Kandagatla ret = -EINVAL; 110536ad9bf1SSrinivas Kandagatla } 110636ad9bf1SSrinivas Kandagatla 110736ad9bf1SSrinivas Kandagatla release_firmware(fw); 110836ad9bf1SSrinivas Kandagatla err: 110936ad9bf1SSrinivas Kandagatla kfree(tplg_fw_name); 111036ad9bf1SSrinivas Kandagatla 111136ad9bf1SSrinivas Kandagatla return ret; 111236ad9bf1SSrinivas Kandagatla } 111336ad9bf1SSrinivas Kandagatla EXPORT_SYMBOL_GPL(audioreach_tplg_init); 1114