Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: add multi Component support

Merge series from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>:

On below HW case, we would like to use it as "2 Cards",
but unfortunately it is impossible in intuitive way,
or possible but not intuitive way.
In reality, it is handled as "1 big Card" today.

+-- basic board --------+
|+--------+ |
|| CPU ch0| <--> CodecA |
|| ch1| <-+ |
|+--------+ | |
+-------------|---------+
+-- expansion board ----+
| | |
| +-> CodecB|
+-----------------------+

To handling it as intuitive "2 Cards", this patch-set
adds multi Component support.

To enable this patch-set, I included [01/15] patch into this patch-set
which is posted but not yet accepted.

+166 -28
+2 -3
include/sound/simple_card_utils.h
··· 192 192 193 193 int asoc_graph_card_probe(struct snd_soc_card *card); 194 194 int asoc_graph_is_ports0(struct device_node *port); 195 - int asoc_graph_parse_dai(struct device_node *ep, 196 - struct snd_soc_dai_link_component *dlc, 197 - int *is_single_link); 195 + int asoc_graph_parse_dai(struct device *dev, struct device_node *ep, 196 + struct snd_soc_dai_link_component *dlc, int *is_single_link); 198 197 199 198 #ifdef DEBUG 200 199 static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv,
+3
include/sound/soc-dai.h
··· 271 271 struct snd_compr_stream *cstream, 272 272 struct snd_compr_metadata *metadata); 273 273 274 + const char *snd_soc_dai_name_get(struct snd_soc_dai *dai); 275 + 274 276 struct snd_soc_dai_ops { 275 277 /* 276 278 * DAI clocking configuration, all optional. ··· 399 397 unsigned int id; 400 398 unsigned int base; 401 399 struct snd_soc_dobj dobj; 400 + struct of_phandle_args *dai_args; 402 401 403 402 /* DAI driver callbacks */ 404 403 int (*probe)(struct snd_soc_dai *dai);
+6
include/sound/soc.h
··· 651 651 const char *name; 652 652 struct device_node *of_node; 653 653 const char *dai_name; 654 + struct of_phandle_args *dai_args; 654 655 }; 655 656 656 657 struct snd_soc_dai_link_codec_ch_map { ··· 1336 1335 void snd_soc_remove_pcm_runtime(struct snd_soc_card *card, 1337 1336 struct snd_soc_pcm_runtime *rtd); 1338 1337 1338 + void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, 1339 + struct snd_soc_dai_link_component *cpus); 1340 + struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, 1341 + struct of_phandle_args *args); 1342 + struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args); 1339 1343 struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component, 1340 1344 struct snd_soc_dai_driver *dai_drv, 1341 1345 bool legacy_dai_naming);
+1 -1
sound/soc/generic/audio-graph-card.c
··· 126 126 127 127 graph_parse_mclk_fs(top, ep, dai_props); 128 128 129 - ret = asoc_graph_parse_dai(ep, dlc, cpu); 129 + ret = asoc_graph_parse_dai(dev, ep, dlc, cpu); 130 130 if (ret < 0) 131 131 return ret; 132 132
+1 -1
sound/soc/generic/audio-graph-card2.c
··· 407 407 408 408 graph_parse_mclk_fs(ep, dai_props); 409 409 410 - ret = asoc_graph_parse_dai(ep, dlc, &is_single_links); 410 + ret = asoc_graph_parse_dai(dev, ep, dlc, &is_single_links); 411 411 if (ret < 0) 412 412 return ret; 413 413
+19 -4
sound/soc/generic/simple-card-utils.c
··· 649 649 * simple-card.c :: simple_count_noml() 650 650 */ 651 651 if (!platforms->of_node) 652 - platforms->of_node = cpus->of_node; 652 + snd_soc_dlc_use_cpu_as_platform(platforms, cpus); 653 653 } 654 654 EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); 655 655 ··· 1066 1066 return id; 1067 1067 } 1068 1068 1069 - int asoc_graph_parse_dai(struct device_node *ep, 1070 - struct snd_soc_dai_link_component *dlc, 1071 - int *is_single_link) 1069 + int asoc_graph_parse_dai(struct device *dev, struct device_node *ep, 1070 + struct snd_soc_dai_link_component *dlc, int *is_single_link) 1072 1071 { 1073 1072 struct device_node *node; 1074 1073 struct of_phandle_args args = {}; 1074 + struct snd_soc_dai *dai; 1075 1075 int ret; 1076 1076 1077 1077 if (!ep) 1078 1078 return 0; 1079 1079 1080 1080 node = of_graph_get_port_parent(ep); 1081 + 1082 + /* 1083 + * Try to find from DAI node 1084 + */ 1085 + args.np = ep; 1086 + dai = snd_soc_get_dai_via_args(&args); 1087 + if (dai) { 1088 + dlc->dai_name = snd_soc_dai_name_get(dai); 1089 + dlc->dai_args = snd_soc_copy_dai_args(dev, &args); 1090 + if (!dlc->dai_args) 1091 + return -ENOMEM; 1092 + 1093 + goto parse_dai_end; 1094 + } 1081 1095 1082 1096 /* Get dai->name */ 1083 1097 args.np = node; ··· 1123 1109 return ret; 1124 1110 } 1125 1111 1112 + parse_dai_end: 1126 1113 if (is_single_link) 1127 1114 *is_single_link = of_graph_get_endpoint_count(node) == 1; 1128 1115
+18 -2
sound/soc/generic/simple-card.c
··· 52 52 return 0; 53 53 } 54 54 55 - static int asoc_simple_parse_dai(struct device_node *node, 55 + static int asoc_simple_parse_dai(struct device *dev, 56 + struct device_node *node, 56 57 struct snd_soc_dai_link_component *dlc, 57 58 int *is_single_link) 58 59 { 59 60 struct of_phandle_args args; 61 + struct snd_soc_dai *dai; 60 62 int ret; 61 63 62 64 if (!node) ··· 71 69 ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args); 72 70 if (ret) 73 71 return ret; 72 + 73 + /* 74 + * Try to find from DAI args 75 + */ 76 + dai = snd_soc_get_dai_via_args(&args); 77 + if (dai) { 78 + dlc->dai_name = snd_soc_dai_name_get(dai); 79 + dlc->dai_args = snd_soc_copy_dai_args(dev, &args); 80 + if (!dlc->dai_args) 81 + return -ENOMEM; 82 + 83 + goto parse_dai_end; 84 + } 74 85 75 86 /* 76 87 * FIXME ··· 108 93 if (ret < 0) 109 94 return ret; 110 95 96 + parse_dai_end: 111 97 if (is_single_link) 112 98 *is_single_link = !args.args_count; 113 99 ··· 172 156 173 157 simple_parse_mclk_fs(top, np, dai_props, prefix); 174 158 175 - ret = asoc_simple_parse_dai(np, dlc, cpu); 159 + ret = asoc_simple_parse_dai(dev, np, dlc, cpu); 176 160 if (ret) 177 161 return ret; 178 162
+116 -17
sound/soc/soc-core.c
··· 238 238 239 239 #endif 240 240 241 + static int snd_soc_is_match_dai_args(struct of_phandle_args *args1, 242 + struct of_phandle_args *args2) 243 + { 244 + if (!args1 || !args2) 245 + return 0; 246 + 247 + if (args1->np != args2->np) 248 + return 0; 249 + 250 + for (int i = 0; i < args1->args_count; i++) 251 + if (args1->args[i] != args2->args[i]) 252 + return 0; 253 + 254 + return 1; 255 + } 256 + 241 257 static inline int snd_soc_dlc_component_is_empty(struct snd_soc_dai_link_component *dlc) 242 258 { 243 - return !(dlc->name || dlc->of_node); 259 + return !(dlc->dai_args || dlc->name || dlc->of_node); 244 260 } 245 261 246 262 static inline int snd_soc_dlc_component_is_invalid(struct snd_soc_dai_link_component *dlc) ··· 266 250 267 251 static inline int snd_soc_dlc_dai_is_empty(struct snd_soc_dai_link_component *dlc) 268 252 { 269 - return !dlc->dai_name; 253 + return !(dlc->dai_args || dlc->dai_name); 270 254 } 255 + 256 + static int snd_soc_is_matching_dai(const struct snd_soc_dai_link_component *dlc, 257 + struct snd_soc_dai *dai) 258 + { 259 + if (!dlc) 260 + return 0; 261 + 262 + if (dlc->dai_args) 263 + return snd_soc_is_match_dai_args(dai->driver->dai_args, dlc->dai_args); 264 + 265 + if (!dlc->dai_name) 266 + return 1; 267 + 268 + /* see snd_soc_dai_name_get() */ 269 + 270 + if (strcmp(dlc->dai_name, dai->name) == 0) 271 + return 1; 272 + 273 + if (dai->driver->name && 274 + strcmp(dai->driver->name, dlc->dai_name) == 0) 275 + return 1; 276 + 277 + if (dai->component->name && 278 + strcmp(dlc->dai_name, dai->component->name) == 0) 279 + return 1; 280 + 281 + return 0; 282 + } 283 + 284 + const char *snd_soc_dai_name_get(struct snd_soc_dai *dai) 285 + { 286 + /* see snd_soc_is_matching_dai() */ 287 + if (dai->name) 288 + return dai->name; 289 + 290 + if (dai->driver->name) 291 + return dai->driver->name; 292 + 293 + if (dai->component->name) 294 + return dai->component->name; 295 + 296 + return NULL; 297 + } 298 + EXPORT_SYMBOL_GPL(snd_soc_dai_name_get); 271 299 272 300 static int snd_soc_rtd_add_component(struct snd_soc_pcm_runtime *rtd, 273 301 struct snd_soc_component *component) ··· 809 749 return of_node; 810 750 } 811 751 752 + struct of_phandle_args *snd_soc_copy_dai_args(struct device *dev, struct of_phandle_args *args) 753 + { 754 + struct of_phandle_args *ret = devm_kzalloc(dev, sizeof(*ret), GFP_KERNEL); 755 + 756 + if (!ret) 757 + return NULL; 758 + 759 + *ret = *args; 760 + 761 + return ret; 762 + } 763 + EXPORT_SYMBOL_GPL(snd_soc_copy_dai_args); 764 + 812 765 static int snd_soc_is_matching_component( 813 766 const struct snd_soc_dai_link_component *dlc, 814 767 struct snd_soc_component *component) ··· 830 757 831 758 if (!dlc) 832 759 return 0; 760 + 761 + if (dlc->dai_args) { 762 + struct snd_soc_dai *dai; 763 + 764 + for_each_component_dais(component, dai) 765 + if (snd_soc_is_matching_dai(dlc, dai)) 766 + return 1; 767 + return 0; 768 + } 833 769 834 770 component_of_node = soc_component_to_node(component); 835 771 ··· 892 810 lockdep_assert_held(&client_mutex); 893 811 894 812 /* Find CPU DAI from registered DAIs */ 895 - for_each_component(component) { 896 - if (!snd_soc_is_matching_component(dlc, component)) 897 - continue; 898 - for_each_component_dais(component, dai) { 899 - if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) 900 - && (!dai->driver->name 901 - || strcmp(dai->driver->name, dlc->dai_name))) 902 - continue; 903 - 904 - return dai; 905 - } 906 - } 813 + for_each_component(component) 814 + if (snd_soc_is_matching_component(dlc, component)) 815 + for_each_component_dais(component, dai) 816 + if (snd_soc_is_matching_dai(dlc, dai)) 817 + return dai; 907 818 908 819 return NULL; 909 820 } ··· 3018 2943 } 3019 2944 EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); 3020 2945 2946 + void snd_soc_dlc_use_cpu_as_platform(struct snd_soc_dai_link_component *platforms, 2947 + struct snd_soc_dai_link_component *cpus) 2948 + { 2949 + platforms->of_node = cpus->of_node; 2950 + platforms->dai_args = cpus->dai_args; 2951 + } 2952 + EXPORT_SYMBOL_GPL(snd_soc_dlc_use_cpu_as_platform); 2953 + 3021 2954 void snd_soc_of_parse_node_prefix(struct device_node *np, 3022 2955 struct snd_soc_codec_conf *codec_conf, 3023 2956 struct device_node *of_node, ··· 3399 3316 id--; 3400 3317 } 3401 3318 3402 - dlc->dai_name = dai->driver->name; 3403 - if (!dlc->dai_name) 3404 - dlc->dai_name = pos->name; 3319 + dlc->dai_name = snd_soc_dai_name_get(dai); 3405 3320 } else if (ret) { 3406 3321 /* 3407 3322 * if another error than ENOTSUPP is returned go on and ··· 3466 3385 return ret; 3467 3386 } 3468 3387 EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); 3388 + 3389 + struct snd_soc_dai *snd_soc_get_dai_via_args(struct of_phandle_args *dai_args) 3390 + { 3391 + struct snd_soc_dai *dai; 3392 + struct snd_soc_component *component; 3393 + 3394 + mutex_lock(&client_mutex); 3395 + for_each_component(component) { 3396 + for_each_component_dais(component, dai) 3397 + if (snd_soc_is_match_dai_args(dai->driver->dai_args, dai_args)) 3398 + goto found; 3399 + } 3400 + dai = NULL; 3401 + found: 3402 + mutex_unlock(&client_mutex); 3403 + return dai; 3404 + } 3405 + EXPORT_SYMBOL_GPL(snd_soc_get_dai_via_args); 3469 3406 3470 3407 static void __snd_soc_of_put_component(struct snd_soc_dai_link_component *component) 3471 3408 {