xref: /openbmc/linux/sound/soc/mediatek/common/mtk-soundcard-driver.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
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