1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * mtk-dsp-sof-common.c -- MediaTek dsp sof common ctrl 4 * 5 * Copyright (c) 2022 MediaTek Inc. 6 * Author: Chunxu Li <chunxu.li@mediatek.com> 7 */ 8 9 #include "mtk-dsp-sof-common.h" 10 #include "mtk-soc-card.h" 11 12 /* fixup the BE DAI link to match any values from topology */ 13 int mtk_sof_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, 14 struct snd_pcm_hw_params *params) 15 { 16 struct snd_soc_card *card = rtd->card; 17 struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card); 18 struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; 19 int i, j, ret = 0; 20 21 for (i = 0; i < sof_priv->num_streams; i++) { 22 struct snd_soc_dai *cpu_dai; 23 struct snd_soc_pcm_runtime *runtime; 24 struct snd_soc_dai_link *sof_dai_link = NULL; 25 const struct sof_conn_stream *conn = &sof_priv->conn_streams[i]; 26 27 if (strcmp(rtd->dai_link->name, conn->normal_link)) 28 continue; 29 30 for_each_card_rtds(card, runtime) { 31 if (strcmp(runtime->dai_link->name, conn->sof_link)) 32 continue; 33 34 for_each_rtd_cpu_dais(runtime, j, cpu_dai) { 35 if (cpu_dai->stream_active[conn->stream_dir] > 0) { 36 sof_dai_link = runtime->dai_link; 37 break; 38 } 39 } 40 break; 41 } 42 43 if (sof_dai_link && sof_dai_link->be_hw_params_fixup) 44 ret = sof_dai_link->be_hw_params_fixup(runtime, params); 45 46 break; 47 } 48 49 return ret; 50 } 51 EXPORT_SYMBOL_GPL(mtk_sof_dai_link_fixup); 52 53 int mtk_sof_card_probe(struct snd_soc_card *card) 54 { 55 int i; 56 struct snd_soc_dai_link *dai_link; 57 58 /* Set stream_name to help sof bind widgets */ 59 for_each_card_prelinks(card, i, dai_link) { 60 if (dai_link->no_pcm && !dai_link->stream_name && dai_link->name) 61 dai_link->stream_name = dai_link->name; 62 } 63 64 return 0; 65 } 66 EXPORT_SYMBOL_GPL(mtk_sof_card_probe); 67 68 int mtk_sof_card_late_probe(struct snd_soc_card *card) 69 { 70 struct snd_soc_pcm_runtime *rtd; 71 struct snd_soc_component *sof_comp = NULL; 72 struct mtk_soc_card_data *soc_card_data = 73 snd_soc_card_get_drvdata(card); 74 struct mtk_sof_priv *sof_priv = soc_card_data->sof_priv; 75 int i; 76 77 /* 1. find sof component */ 78 for_each_card_rtds(card, rtd) { 79 sof_comp = snd_soc_rtdcom_lookup(rtd, "sof-audio-component"); 80 if (sof_comp) 81 break; 82 } 83 84 if (!sof_comp) { 85 dev_info(card->dev, "probe without sof-audio-component\n"); 86 return 0; 87 } 88 89 /* 2. add route path and fixup callback */ 90 for (i = 0; i < sof_priv->num_streams; i++) { 91 const struct sof_conn_stream *conn = &sof_priv->conn_streams[i]; 92 struct snd_soc_pcm_runtime *sof_rtd = NULL; 93 struct snd_soc_pcm_runtime *normal_rtd = NULL; 94 95 for_each_card_rtds(card, rtd) { 96 if (!strcmp(rtd->dai_link->name, conn->sof_link)) { 97 sof_rtd = rtd; 98 continue; 99 } 100 if (!strcmp(rtd->dai_link->name, conn->normal_link)) { 101 normal_rtd = rtd; 102 continue; 103 } 104 if (normal_rtd && sof_rtd) 105 break; 106 } 107 if (normal_rtd && sof_rtd) { 108 int j; 109 struct snd_soc_dai *cpu_dai; 110 111 for_each_rtd_cpu_dais(sof_rtd, j, cpu_dai) { 112 struct snd_soc_dapm_route route; 113 struct snd_soc_dapm_path *p = NULL; 114 struct snd_soc_dapm_widget *play_widget = 115 cpu_dai->playback_widget; 116 struct snd_soc_dapm_widget *cap_widget = 117 cpu_dai->capture_widget; 118 memset(&route, 0, sizeof(route)); 119 if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && 120 cap_widget) { 121 snd_soc_dapm_widget_for_each_sink_path(cap_widget, p) { 122 route.source = conn->sof_dma; 123 route.sink = p->sink->name; 124 snd_soc_dapm_add_routes(&card->dapm, &route, 1); 125 } 126 } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && 127 play_widget) { 128 snd_soc_dapm_widget_for_each_source_path(play_widget, p) { 129 route.source = p->source->name; 130 route.sink = conn->sof_dma; 131 snd_soc_dapm_add_routes(&card->dapm, &route, 1); 132 } 133 } else { 134 dev_err(cpu_dai->dev, "stream dir and widget not pair\n"); 135 } 136 } 137 138 sof_rtd->dai_link->be_hw_params_fixup = 139 sof_comp->driver->be_hw_params_fixup; 140 if (sof_priv->sof_dai_link_fixup) 141 normal_rtd->dai_link->be_hw_params_fixup = 142 sof_priv->sof_dai_link_fixup; 143 else 144 normal_rtd->dai_link->be_hw_params_fixup = mtk_sof_dai_link_fixup; 145 } 146 } 147 148 return 0; 149 } 150 EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe); 151 152 int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, 153 const char *propname, struct snd_soc_dai_link *pre_dai_links, 154 int pre_num_links) 155 { 156 struct device *dev = card->dev; 157 struct snd_soc_dai_link *parsed_dai_link; 158 const char *dai_name = NULL; 159 int i, j, ret, num_links, parsed_num_links = 0; 160 161 num_links = of_property_count_strings(np, "mediatek,dai-link"); 162 if (num_links < 0 || num_links > card->num_links) { 163 dev_dbg(dev, "number of dai-link is invalid\n"); 164 return -EINVAL; 165 } 166 167 parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL); 168 if (!parsed_dai_link) 169 return -ENOMEM; 170 171 for (i = 0; i < num_links; i++) { 172 ret = of_property_read_string_index(np, propname, i, &dai_name); 173 if (ret) { 174 dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n", 175 propname, i, ret); 176 return ret; 177 } 178 dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name); 179 for (j = 0; j < pre_num_links; j++) { 180 if (!strcmp(dai_name, pre_dai_links[j].name)) { 181 memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j], 182 sizeof(struct snd_soc_dai_link)); 183 break; 184 } 185 } 186 } 187 188 if (parsed_num_links != num_links) 189 return -EINVAL; 190 191 card->dai_link = parsed_dai_link; 192 card->num_links = parsed_num_links; 193 194 return 0; 195 } 196 EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of); 197