xref: /linux/sound/soc/sdw_utils/soc_sdw_maxim.c (revision 177bf8620cf4ed290ee170a6c5966adc0924b336)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // This file incorporates work covered by the following copyright notice:
3 // Copyright (c) 2020 Intel Corporation
4 // Copyright (c) 2024 Advanced Micro Devices, Inc.
5 //
6 // soc_sdw_maxim - Helpers to handle maxim codecs
7 // codec devices from generic machine driver
8 
9 #include <linux/device.h>
10 #include <linux/errno.h>
11 #include <sound/control.h>
12 #include <sound/soc.h>
13 #include <sound/soc-acpi.h>
14 #include <sound/soc-dapm.h>
15 #include <sound/soc_sdw_utils.h>
16 
17 static int maxim_part_id;
18 #define SOC_SDW_PART_ID_MAX98363 0x8363
19 #define SOC_SDW_PART_ID_MAX98373 0x8373
20 
21 static const struct snd_soc_dapm_route max_98373_dapm_routes[] = {
22 	{ "Left Spk", NULL, "Left BE_OUT" },
23 	{ "Right Spk", NULL, "Right BE_OUT" },
24 };
25 
asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime * rtd,struct snd_soc_dai * dai)26 int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
27 {
28 	struct snd_soc_card *card = rtd->card;
29 	int ret;
30 
31 	ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 2);
32 	if (ret)
33 		dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
34 
35 	return ret;
36 }
37 EXPORT_SYMBOL_NS(asoc_sdw_maxim_spk_rtd_init, "SND_SOC_SDW_UTILS");
38 
asoc_sdw_mx8373_enable_spk_pin(struct snd_pcm_substream * substream,bool enable)39 static int asoc_sdw_mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable)
40 {
41 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
42 	struct snd_soc_dai *codec_dai;
43 	struct snd_soc_dai *cpu_dai;
44 	int ret;
45 	int j;
46 
47 	/* set spk pin by playback only */
48 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
49 		return 0;
50 
51 	cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
52 	for_each_rtd_codec_dais(rtd, j, codec_dai) {
53 		struct snd_soc_dapm_context *dapm =
54 				snd_soc_component_get_dapm(cpu_dai->component);
55 		char pin_name[16];
56 
57 		snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
58 			 codec_dai->component->name_prefix);
59 
60 		if (enable)
61 			ret = snd_soc_dapm_enable_pin(dapm, pin_name);
62 		else
63 			ret = snd_soc_dapm_disable_pin(dapm, pin_name);
64 
65 		if (!ret)
66 			snd_soc_dapm_sync(dapm);
67 	}
68 
69 	return 0;
70 }
71 
asoc_sdw_mx8373_prepare(struct snd_pcm_substream * substream)72 static int asoc_sdw_mx8373_prepare(struct snd_pcm_substream *substream)
73 {
74 	int ret;
75 
76 	/* according to soc_pcm_prepare dai link prepare is called first */
77 	ret = asoc_sdw_prepare(substream);
78 	if (ret < 0)
79 		return ret;
80 
81 	return asoc_sdw_mx8373_enable_spk_pin(substream, true);
82 }
83 
asoc_sdw_mx8373_hw_free(struct snd_pcm_substream * substream)84 static int asoc_sdw_mx8373_hw_free(struct snd_pcm_substream *substream)
85 {
86 	int ret;
87 
88 	/* according to soc_pcm_hw_free dai link free is called first */
89 	ret = asoc_sdw_hw_free(substream);
90 	if (ret < 0)
91 		return ret;
92 
93 	return asoc_sdw_mx8373_enable_spk_pin(substream, false);
94 }
95 
96 static const struct snd_soc_ops max_98373_sdw_ops = {
97 	.startup = asoc_sdw_startup,
98 	.prepare = asoc_sdw_mx8373_prepare,
99 	.trigger = asoc_sdw_trigger,
100 	.hw_params = asoc_sdw_hw_params,
101 	.hw_free = asoc_sdw_mx8373_hw_free,
102 	.shutdown = asoc_sdw_shutdown,
103 };
104 
asoc_sdw_mx8373_sdw_late_probe(struct snd_soc_card * card)105 static int asoc_sdw_mx8373_sdw_late_probe(struct snd_soc_card *card)
106 {
107 	struct snd_soc_dapm_context *dapm = &card->dapm;
108 
109 	/* Disable Left and Right Spk pin after boot */
110 	snd_soc_dapm_disable_pin(dapm, "Left Spk");
111 	snd_soc_dapm_disable_pin(dapm, "Right Spk");
112 	return snd_soc_dapm_sync(dapm);
113 }
114 
asoc_sdw_maxim_init(struct snd_soc_card * card,struct snd_soc_dai_link * dai_links,struct asoc_sdw_codec_info * info,bool playback)115 int asoc_sdw_maxim_init(struct snd_soc_card *card,
116 			struct snd_soc_dai_link *dai_links,
117 			struct asoc_sdw_codec_info *info,
118 			bool playback)
119 {
120 	info->amp_num++;
121 
122 	maxim_part_id = info->part_id;
123 	switch (maxim_part_id) {
124 	case SOC_SDW_PART_ID_MAX98363:
125 		/* Default ops are set in function init_dai_link.
126 		 * called as part of function create_sdw_dailink
127 		 */
128 		break;
129 	case SOC_SDW_PART_ID_MAX98373:
130 		info->codec_card_late_probe = asoc_sdw_mx8373_sdw_late_probe;
131 		dai_links->ops = &max_98373_sdw_ops;
132 		break;
133 	default:
134 		dev_err(card->dev, "Invalid maxim_part_id %#x\n", maxim_part_id);
135 		return -EINVAL;
136 	}
137 	return 0;
138 }
139 EXPORT_SYMBOL_NS(asoc_sdw_maxim_init, "SND_SOC_SDW_UTILS");
140