xref: /linux/sound/soc/qcom/sdw.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018-2023, Linaro Limited.
3 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 
5 #include <dt-bindings/sound/qcom,q6afe.h>
6 #include <linux/module.h>
7 #include <sound/soc.h>
8 #include "sdw.h"
9 
10 /**
11  * qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card
12  * @substream: The PCM substream from audio, as passed to snd_soc_ops->startup()
13  *
14  * Helper for the SoC audio card (snd_soc_ops->startup()) to allocate and set
15  * Soundwire stream runtime to each codec DAI.
16  *
17  * The shutdown() callback should call sdw_release_stream() on the same
18  * sdw_stream_runtime.
19  *
20  * Return: 0 or errno
21  */
22 int qcom_snd_sdw_startup(struct snd_pcm_substream *substream)
23 {
24 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
25 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
26 	struct sdw_stream_runtime *sruntime;
27 	struct snd_soc_dai *codec_dai;
28 	int ret, i;
29 
30 	sruntime = sdw_alloc_stream(cpu_dai->name);
31 	if (!sruntime)
32 		return -ENOMEM;
33 
34 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
35 		ret = snd_soc_dai_set_stream(codec_dai, sruntime,
36 					     substream->stream);
37 		if (ret < 0 && ret != -ENOTSUPP) {
38 			dev_err(rtd->dev, "Failed to set sdw stream on %s\n",
39 				codec_dai->name);
40 			goto err_set_stream;
41 		}
42 	}
43 
44 	return 0;
45 
46 err_set_stream:
47 	sdw_release_stream(sruntime);
48 
49 	return ret;
50 }
51 EXPORT_SYMBOL_GPL(qcom_snd_sdw_startup);
52 
53 int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
54 			 struct sdw_stream_runtime *sruntime,
55 			 bool *stream_prepared)
56 {
57 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
58 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
59 	int ret;
60 
61 	if (!sruntime)
62 		return 0;
63 
64 	switch (cpu_dai->id) {
65 	case WSA_CODEC_DMA_RX_0:
66 	case WSA_CODEC_DMA_RX_1:
67 	case RX_CODEC_DMA_RX_0:
68 	case RX_CODEC_DMA_RX_1:
69 	case TX_CODEC_DMA_TX_0:
70 	case TX_CODEC_DMA_TX_1:
71 	case TX_CODEC_DMA_TX_2:
72 	case TX_CODEC_DMA_TX_3:
73 		break;
74 	default:
75 		return 0;
76 	}
77 
78 	if (*stream_prepared)
79 		return 0;
80 
81 	ret = sdw_prepare_stream(sruntime);
82 	if (ret)
83 		return ret;
84 
85 	/**
86 	 * NOTE: there is a strict hw requirement about the ordering of port
87 	 * enables and actual WSA881x PA enable. PA enable should only happen
88 	 * after soundwire ports are enabled if not DC on the line is
89 	 * accumulated resulting in Click/Pop Noise
90 	 * PA enable/mute are handled as part of codec DAPM and digital mute.
91 	 */
92 
93 	ret = sdw_enable_stream(sruntime);
94 	if (ret) {
95 		sdw_deprepare_stream(sruntime);
96 		return ret;
97 	}
98 	*stream_prepared  = true;
99 
100 	return ret;
101 }
102 EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
103 
104 int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
105 			   struct snd_pcm_hw_params *params,
106 			   struct sdw_stream_runtime **psruntime)
107 {
108 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
109 	struct snd_soc_dai *codec_dai;
110 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
111 	struct sdw_stream_runtime *sruntime;
112 	int i;
113 
114 	switch (cpu_dai->id) {
115 	case WSA_CODEC_DMA_RX_0:
116 	case RX_CODEC_DMA_RX_0:
117 	case RX_CODEC_DMA_RX_1:
118 	case TX_CODEC_DMA_TX_0:
119 	case TX_CODEC_DMA_TX_1:
120 	case TX_CODEC_DMA_TX_2:
121 	case TX_CODEC_DMA_TX_3:
122 		for_each_rtd_codec_dais(rtd, i, codec_dai) {
123 			sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
124 			if (sruntime != ERR_PTR(-ENOTSUPP))
125 				*psruntime = sruntime;
126 		}
127 		break;
128 	}
129 
130 	return 0;
131 
132 }
133 EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
134 
135 int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
136 			 struct sdw_stream_runtime *sruntime, bool *stream_prepared)
137 {
138 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
139 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
140 
141 	switch (cpu_dai->id) {
142 	case WSA_CODEC_DMA_RX_0:
143 	case WSA_CODEC_DMA_RX_1:
144 	case RX_CODEC_DMA_RX_0:
145 	case RX_CODEC_DMA_RX_1:
146 	case TX_CODEC_DMA_TX_0:
147 	case TX_CODEC_DMA_TX_1:
148 	case TX_CODEC_DMA_TX_2:
149 	case TX_CODEC_DMA_TX_3:
150 		if (sruntime && *stream_prepared) {
151 			sdw_disable_stream(sruntime);
152 			sdw_deprepare_stream(sruntime);
153 			*stream_prepared = false;
154 		}
155 		break;
156 	default:
157 		break;
158 	}
159 
160 	return 0;
161 }
162 EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
163 MODULE_DESCRIPTION("Qualcomm ASoC SoundWire helper functions");
164 MODULE_LICENSE("GPL");
165