14302187dSTrevor Wu // SPDX-License-Identifier: GPL-2.0
24302187dSTrevor Wu /*
34302187dSTrevor Wu * mtk-soundcard-driver.c -- MediaTek soundcard driver common
44302187dSTrevor Wu *
54302187dSTrevor Wu * Copyright (c) 2022 MediaTek Inc.
64302187dSTrevor Wu * Author: Trevor Wu <trevor.wu@mediatek.com>
74302187dSTrevor Wu */
84302187dSTrevor Wu
94302187dSTrevor Wu #include <linux/module.h>
104302187dSTrevor Wu #include <linux/of.h>
114302187dSTrevor Wu #include <sound/soc.h>
124302187dSTrevor Wu
134302187dSTrevor Wu #include "mtk-soundcard-driver.h"
144302187dSTrevor Wu
set_card_codec_info(struct snd_soc_card * card,struct device_node * sub_node,struct snd_soc_dai_link * dai_link)154302187dSTrevor Wu static int set_card_codec_info(struct snd_soc_card *card,
164302187dSTrevor Wu struct device_node *sub_node,
174302187dSTrevor Wu struct snd_soc_dai_link *dai_link)
184302187dSTrevor Wu {
194302187dSTrevor Wu struct device *dev = card->dev;
204302187dSTrevor Wu struct device_node *codec_node;
214302187dSTrevor Wu int ret;
224302187dSTrevor Wu
234302187dSTrevor Wu codec_node = of_get_child_by_name(sub_node, "codec");
24c0e7390eSTrevor Wu if (!codec_node) {
25*87b8dca6SAngeloGioacchino Del Regno dev_dbg(dev, "%s no specified codec: setting dummy.\n", dai_link->name);
26*87b8dca6SAngeloGioacchino Del Regno
27*87b8dca6SAngeloGioacchino Del Regno dai_link->codecs = &snd_soc_dummy_dlc;
28*87b8dca6SAngeloGioacchino Del Regno dai_link->num_codecs = 1;
29*87b8dca6SAngeloGioacchino Del Regno dai_link->dynamic = 1;
30c0e7390eSTrevor Wu return 0;
31c0e7390eSTrevor Wu }
324302187dSTrevor Wu
334302187dSTrevor Wu /* set card codec info */
344302187dSTrevor Wu ret = snd_soc_of_get_dai_link_codecs(dev, codec_node, dai_link);
354302187dSTrevor Wu
364302187dSTrevor Wu of_node_put(codec_node);
374302187dSTrevor Wu
384302187dSTrevor Wu if (ret < 0)
394302187dSTrevor Wu return dev_err_probe(dev, ret, "%s: codec dai not found\n",
404302187dSTrevor Wu dai_link->name);
414302187dSTrevor Wu
424302187dSTrevor Wu return 0;
434302187dSTrevor Wu }
444302187dSTrevor Wu
set_dailink_daifmt(struct snd_soc_card * card,struct device_node * sub_node,struct snd_soc_dai_link * dai_link)45c0e7390eSTrevor Wu static int set_dailink_daifmt(struct snd_soc_card *card,
46c0e7390eSTrevor Wu struct device_node *sub_node,
47c0e7390eSTrevor Wu struct snd_soc_dai_link *dai_link)
48c0e7390eSTrevor Wu {
49c0e7390eSTrevor Wu unsigned int daifmt;
50c0e7390eSTrevor Wu const char *str;
51c0e7390eSTrevor Wu int ret;
52c0e7390eSTrevor Wu struct {
53c0e7390eSTrevor Wu char *name;
54c0e7390eSTrevor Wu unsigned int val;
55c0e7390eSTrevor Wu } of_clk_table[] = {
56c0e7390eSTrevor Wu { "cpu", SND_SOC_DAIFMT_CBC_CFC },
57c0e7390eSTrevor Wu { "codec", SND_SOC_DAIFMT_CBP_CFP },
58c0e7390eSTrevor Wu };
59c0e7390eSTrevor Wu
60c0e7390eSTrevor Wu daifmt = snd_soc_daifmt_parse_format(sub_node, NULL);
61c0e7390eSTrevor Wu if (daifmt) {
62c0e7390eSTrevor Wu dai_link->dai_fmt &= SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
63c0e7390eSTrevor Wu dai_link->dai_fmt |= daifmt;
64c0e7390eSTrevor Wu }
65c0e7390eSTrevor Wu
66c0e7390eSTrevor Wu /*
67c0e7390eSTrevor Wu * check "mediatek,clk-provider = xxx"
68c0e7390eSTrevor Wu * SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK area
69c0e7390eSTrevor Wu */
70c0e7390eSTrevor Wu ret = of_property_read_string(sub_node, "mediatek,clk-provider", &str);
71c0e7390eSTrevor Wu if (ret == 0) {
72c0e7390eSTrevor Wu int i;
73c0e7390eSTrevor Wu
74c0e7390eSTrevor Wu for (i = 0; i < ARRAY_SIZE(of_clk_table); i++) {
75c0e7390eSTrevor Wu if (strcmp(str, of_clk_table[i].name) == 0) {
76c0e7390eSTrevor Wu dai_link->dai_fmt &= ~SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK;
77c0e7390eSTrevor Wu dai_link->dai_fmt |= of_clk_table[i].val;
78c0e7390eSTrevor Wu break;
79c0e7390eSTrevor Wu }
80c0e7390eSTrevor Wu }
81c0e7390eSTrevor Wu }
82c0e7390eSTrevor Wu
83c0e7390eSTrevor Wu return 0;
84c0e7390eSTrevor Wu }
85c0e7390eSTrevor Wu
parse_dai_link_info(struct snd_soc_card * card)864302187dSTrevor Wu int parse_dai_link_info(struct snd_soc_card *card)
874302187dSTrevor Wu {
884302187dSTrevor Wu struct device *dev = card->dev;
894302187dSTrevor Wu struct device_node *sub_node;
904302187dSTrevor Wu struct snd_soc_dai_link *dai_link;
914302187dSTrevor Wu const char *dai_link_name;
924302187dSTrevor Wu int ret, i;
934302187dSTrevor Wu
944302187dSTrevor Wu /* Loop over all the dai link sub nodes */
954302187dSTrevor Wu for_each_available_child_of_node(dev->of_node, sub_node) {
964302187dSTrevor Wu if (of_property_read_string(sub_node, "link-name",
97beed115cSAashish Sharma &dai_link_name)) {
98beed115cSAashish Sharma of_node_put(sub_node);
994302187dSTrevor Wu return -EINVAL;
100beed115cSAashish Sharma }
1014302187dSTrevor Wu
1024302187dSTrevor Wu for_each_card_prelinks(card, i, dai_link) {
1034302187dSTrevor Wu if (!strcmp(dai_link_name, dai_link->name))
1044302187dSTrevor Wu break;
1054302187dSTrevor Wu }
1064302187dSTrevor Wu
107beed115cSAashish Sharma if (i >= card->num_links) {
108beed115cSAashish Sharma of_node_put(sub_node);
1094302187dSTrevor Wu return -EINVAL;
110beed115cSAashish Sharma }
1114302187dSTrevor Wu
1124302187dSTrevor Wu ret = set_card_codec_info(card, sub_node, dai_link);
113beed115cSAashish Sharma if (ret < 0) {
114beed115cSAashish Sharma of_node_put(sub_node);
1154302187dSTrevor Wu return ret;
1164302187dSTrevor Wu }
117c0e7390eSTrevor Wu
118c0e7390eSTrevor Wu ret = set_dailink_daifmt(card, sub_node, dai_link);
119c0e7390eSTrevor Wu if (ret < 0) {
120c0e7390eSTrevor Wu of_node_put(sub_node);
121c0e7390eSTrevor Wu return ret;
122c0e7390eSTrevor Wu }
123beed115cSAashish Sharma }
1244302187dSTrevor Wu
1254302187dSTrevor Wu return 0;
1264302187dSTrevor Wu }
1274302187dSTrevor Wu EXPORT_SYMBOL_GPL(parse_dai_link_info);
1284302187dSTrevor Wu
clean_card_reference(struct snd_soc_card * card)1294302187dSTrevor Wu void clean_card_reference(struct snd_soc_card *card)
1304302187dSTrevor Wu {
1314302187dSTrevor Wu struct snd_soc_dai_link *dai_link;
1324302187dSTrevor Wu int i;
1334302187dSTrevor Wu
1344302187dSTrevor Wu /* release codec reference gotten by set_card_codec_info */
1354302187dSTrevor Wu for_each_card_prelinks(card, i, dai_link)
1364302187dSTrevor Wu snd_soc_of_put_dai_link_codecs(dai_link);
1374302187dSTrevor Wu }
1384302187dSTrevor Wu EXPORT_SYMBOL_GPL(clean_card_reference);
139