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 */
22int 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(stream_name: 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(dai: codec_dai, stream: sruntime,
36 direction: 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
46err_set_stream:
47 sdw_release_stream(stream: sruntime);
48
49 return ret;
50}
51EXPORT_SYMBOL_GPL(qcom_snd_sdw_startup);
52
53int 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(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(stream: sruntime);
94 if (ret) {
95 sdw_deprepare_stream(stream: sruntime);
96 return ret;
97 }
98 *stream_prepared = true;
99
100 return ret;
101}
102EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
103
104int 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(dai: codec_dai, direction: substream->stream);
124 if (sruntime != ERR_PTR(error: -ENOTSUPP))
125 *psruntime = sruntime;
126 }
127 break;
128 }
129
130 return 0;
131
132}
133EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
134
135int 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(stream: sruntime);
152 sdw_deprepare_stream(stream: sruntime);
153 *stream_prepared = false;
154 }
155 break;
156 default:
157 break;
158 }
159
160 return 0;
161}
162EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
163MODULE_LICENSE("GPL");
164

source code of linux/sound/soc/qcom/sdw.c