^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // Copyright (c) 2018, Linaro Limited.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright (c) 2018, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) int qcom_snd_parse_of(struct snd_soc_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) struct device_node *np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct device_node *codec = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct device_node *platform = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct device_node *cpu = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct device *dev = card->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) struct snd_soc_dai_link *link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) struct of_phandle_args args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct snd_soc_dai_link_component *dlc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) int ret, num_links;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) ret = snd_soc_of_parse_card_name(card, "model");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) if (ret == 0 && !card->name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Deprecated, only for compatibility with old device trees */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) ret = snd_soc_of_parse_card_name(card, "qcom,model");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) dev_err(dev, "Error parsing card name: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* DAPM routes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (of_property_read_bool(dev->of_node, "audio-routing")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Deprecated, only for compatibility with old device trees */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if (of_property_read_bool(dev->of_node, "qcom,audio-routing")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Populate links */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) num_links = of_get_child_count(dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Allocate the DAI link array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (!card->dai_link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) card->num_links = num_links;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) link = card->dai_link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) for_each_child_of_node(dev->of_node, np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (!dlc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) goto err_put_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) link->cpus = &dlc[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) link->platforms = &dlc[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) link->num_cpus = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) link->num_platforms = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ret = of_property_read_string(np, "link-name", &link->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) dev_err(card->dev, "error getting codec dai_link name\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) goto err_put_np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) cpu = of_get_child_by_name(np, "cpu");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) platform = of_get_child_by_name(np, "platform");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) codec = of_get_child_by_name(np, "codec");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (!cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) dev_err(dev, "%s: Can't find cpu DT node\n", link->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) ret = of_parse_phandle_with_args(cpu, "sound-dai",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "#sound-dai-cells", 0, &args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dev_err(card->dev, "%s: error getting cpu phandle\n", link->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) link->cpus->of_node = args.np;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) link->id = args.args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ret != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) dev_err(card->dev, "%s: error getting cpu dai name: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) link->name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (platform) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) link->platforms->of_node = of_parse_phandle(platform,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) "sound-dai",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (!link->platforms->of_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) dev_err(card->dev, "%s: platform dai not found\n", link->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) link->platforms->of_node = link->cpus->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (codec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (ret != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) dev_err(card->dev, "%s: codec dai not found: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) link->name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (platform) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /* DPCM backend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) link->no_pcm = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) link->ignore_pmdown_time = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* DPCM frontend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (!dlc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) link->codecs = dlc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) link->num_codecs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) link->codecs->dai_name = "snd-soc-dummy-dai";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) link->codecs->name = "snd-soc-dummy";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) link->dynamic = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (platform || !codec) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) /* DPCM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) snd_soc_dai_link_set_capabilities(link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) link->ignore_suspend = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) link->nonatomic = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) link->stream_name = link->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) link++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) of_node_put(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) of_node_put(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) of_node_put(platform);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) of_node_put(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) of_node_put(codec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) of_node_put(platform);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) err_put_np:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) EXPORT_SYMBOL(qcom_snd_parse_of);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) MODULE_LICENSE("GPL v2");