GNU Linux-libre 6.9.1-gnu
[releases.git] / sound / soc / qcom / sdw.c
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 = substream->private_data;
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 = substream->private_data;
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 = substream->private_data;
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 = substream->private_data;
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_LICENSE("GPL");