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 (conn->normal_link && 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 (snd_soc_dai_stream_active(cpu_dai, 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 *widget = snd_soc_dai_get_widget(cpu_dai, conn->stream_dir); 115 116 memset(&route, 0, sizeof(route)); 117 if (conn->stream_dir == SNDRV_PCM_STREAM_CAPTURE && widget) { 118 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 119 route.source = conn->sof_dma; 120 route.sink = p->sink->name; 121 snd_soc_dapm_add_routes(&card->dapm, &route, 1); 122 } 123 } else if (conn->stream_dir == SNDRV_PCM_STREAM_PLAYBACK && widget) { 124 snd_soc_dapm_widget_for_each_source_path(widget, p) { 125 route.source = p->source->name; 126 route.sink = conn->sof_dma; 127 snd_soc_dapm_add_routes(&card->dapm, &route, 1); 128 } 129 } else { 130 dev_err(cpu_dai->dev, "stream dir and widget not pair\n"); 131 } 132 } 133 134 sof_rtd->dai_link->be_hw_params_fixup = 135 sof_comp->driver->be_hw_params_fixup; 136 if (sof_priv->sof_dai_link_fixup) 137 normal_rtd->dai_link->be_hw_params_fixup = 138 sof_priv->sof_dai_link_fixup; 139 else 140 normal_rtd->dai_link->be_hw_params_fixup = mtk_sof_dai_link_fixup; 141 } 142 } 143 144 return 0; 145 } 146 EXPORT_SYMBOL_GPL(mtk_sof_card_late_probe); 147 148 int mtk_sof_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, 149 const char *propname, struct snd_soc_dai_link *pre_dai_links, 150 int pre_num_links) 151 { 152 struct device *dev = card->dev; 153 struct snd_soc_dai_link *parsed_dai_link; 154 const char *dai_name = NULL; 155 int i, j, ret, num_links, parsed_num_links = 0; 156 157 num_links = of_property_count_strings(np, "mediatek,dai-link"); 158 if (num_links < 0 || num_links > card->num_links) { 159 dev_dbg(dev, "number of dai-link is invalid\n"); 160 return -EINVAL; 161 } 162 163 parsed_dai_link = devm_kcalloc(dev, num_links, sizeof(*parsed_dai_link), GFP_KERNEL); 164 if (!parsed_dai_link) 165 return -ENOMEM; 166 167 for (i = 0; i < num_links; i++) { 168 ret = of_property_read_string_index(np, propname, i, &dai_name); 169 if (ret) { 170 dev_dbg(dev, "ASoC: Property '%s' index %d could not be read: %d\n", 171 propname, i, ret); 172 return ret; 173 } 174 dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name); 175 for (j = 0; j < pre_num_links; j++) { 176 if (!strcmp(dai_name, pre_dai_links[j].name)) { 177 memcpy(&parsed_dai_link[parsed_num_links++], &pre_dai_links[j], 178 sizeof(struct snd_soc_dai_link)); 179 break; 180 } 181 } 182 } 183 184 if (parsed_num_links != num_links) 185 return -EINVAL; 186 187 card->dai_link = parsed_dai_link; 188 card->num_links = parsed_num_links; 189 190 return 0; 191 } 192 EXPORT_SYMBOL_GPL(mtk_sof_dailink_parse_of); 193