1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2023, Linaro Limited
4 #include <dt-bindings/sound/qcom,q6afe.h>
5 #include <linux/module.h>
6 #include <linux/platform_device.h>
7 #include <linux/soundwire/sdw.h>
9 #include <sound/jack.h>
10 #include <sound/soc.h>
11 #include <sound/soc-dapm.h>
14 #include "qdsp6/q6afe.h"
15 #include "qdsp6/q6dsp-common.h"
18 struct x1e80100_snd_data
{
19 bool stream_prepared
[AFE_PORT_MAX
];
20 struct snd_soc_card
*card
;
21 struct sdw_stream_runtime
*sruntime
[AFE_PORT_MAX
];
22 struct snd_soc_jack jack
;
23 struct snd_soc_jack dp_jack
[8];
27 static int x1e80100_snd_init(struct snd_soc_pcm_runtime
*rtd
)
29 struct x1e80100_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
30 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
31 struct snd_soc_jack
*dp_jack
= NULL
;
34 switch (cpu_dai
->id
) {
35 case DISPLAY_PORT_RX_0
:
37 dp_jack
= &data
->dp_jack
[dp_pcm_id
];
39 case DISPLAY_PORT_RX_1
... DISPLAY_PORT_RX_7
:
40 dp_pcm_id
= cpu_dai
->id
- DISPLAY_PORT_RX_1
+ 1;
41 dp_jack
= &data
->dp_jack
[dp_pcm_id
];
48 return qcom_snd_dp_jack_setup(rtd
, dp_jack
, dp_pcm_id
);
50 return qcom_snd_wcd_jack_setup(rtd
, &data
->jack
, &data
->jack_setup
);
53 static void x1e80100_snd_shutdown(struct snd_pcm_substream
*substream
)
55 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
56 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
57 struct x1e80100_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
58 struct sdw_stream_runtime
*sruntime
= data
->sruntime
[cpu_dai
->id
];
60 data
->sruntime
[cpu_dai
->id
] = NULL
;
61 sdw_release_stream(sruntime
);
64 static int x1e80100_be_hw_params_fixup(struct snd_soc_pcm_runtime
*rtd
,
65 struct snd_pcm_hw_params
*params
)
67 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
68 struct snd_interval
*rate
= hw_param_interval(params
,
69 SNDRV_PCM_HW_PARAM_RATE
);
70 struct snd_interval
*channels
= hw_param_interval(params
,
71 SNDRV_PCM_HW_PARAM_CHANNELS
);
73 rate
->min
= rate
->max
= 48000;
74 switch (cpu_dai
->id
) {
75 case TX_CODEC_DMA_TX_0
:
76 case TX_CODEC_DMA_TX_1
:
77 case TX_CODEC_DMA_TX_2
:
78 case TX_CODEC_DMA_TX_3
:
88 static int x1e80100_snd_hw_params(struct snd_pcm_substream
*substream
,
89 struct snd_pcm_hw_params
*params
)
91 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
92 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
93 struct x1e80100_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
95 return qcom_snd_sdw_hw_params(substream
, params
, &data
->sruntime
[cpu_dai
->id
]);
98 static int x1e80100_snd_hw_map_channels(unsigned int *ch_map
, int num
)
102 ch_map
[0] = PCM_CHANNEL_FC
;
105 ch_map
[0] = PCM_CHANNEL_FL
;
106 ch_map
[1] = PCM_CHANNEL_FR
;
109 ch_map
[0] = PCM_CHANNEL_FL
;
110 ch_map
[1] = PCM_CHANNEL_FR
;
111 ch_map
[2] = PCM_CHANNEL_FC
;
114 ch_map
[0] = PCM_CHANNEL_FL
;
115 ch_map
[1] = PCM_CHANNEL_LB
;
116 ch_map
[2] = PCM_CHANNEL_FR
;
117 ch_map
[3] = PCM_CHANNEL_RB
;
126 static int x1e80100_snd_prepare(struct snd_pcm_substream
*substream
)
128 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
129 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
130 struct x1e80100_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
131 struct sdw_stream_runtime
*sruntime
= data
->sruntime
[cpu_dai
->id
];
132 unsigned int channels
= substream
->runtime
->channels
;
133 unsigned int rx_slot
[4];
136 switch (cpu_dai
->id
) {
137 case WSA_CODEC_DMA_RX_0
:
138 case WSA_CODEC_DMA_RX_1
:
139 ret
= x1e80100_snd_hw_map_channels(rx_slot
, channels
);
143 ret
= snd_soc_dai_set_channel_map(cpu_dai
, 0, NULL
,
152 return qcom_snd_sdw_prepare(substream
, sruntime
,
153 &data
->stream_prepared
[cpu_dai
->id
]);
156 static int x1e80100_snd_hw_free(struct snd_pcm_substream
*substream
)
158 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
159 struct x1e80100_snd_data
*data
= snd_soc_card_get_drvdata(rtd
->card
);
160 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
161 struct sdw_stream_runtime
*sruntime
= data
->sruntime
[cpu_dai
->id
];
163 return qcom_snd_sdw_hw_free(substream
, sruntime
,
164 &data
->stream_prepared
[cpu_dai
->id
]);
167 static const struct snd_soc_ops x1e80100_be_ops
= {
168 .startup
= qcom_snd_sdw_startup
,
169 .shutdown
= x1e80100_snd_shutdown
,
170 .hw_params
= x1e80100_snd_hw_params
,
171 .hw_free
= x1e80100_snd_hw_free
,
172 .prepare
= x1e80100_snd_prepare
,
175 static void x1e80100_add_be_ops(struct snd_soc_card
*card
)
177 struct snd_soc_dai_link
*link
;
180 for_each_card_prelinks(card
, i
, link
) {
181 if (link
->no_pcm
== 1) {
182 link
->init
= x1e80100_snd_init
;
183 link
->be_hw_params_fixup
= x1e80100_be_hw_params_fixup
;
184 link
->ops
= &x1e80100_be_ops
;
189 static int x1e80100_platform_probe(struct platform_device
*pdev
)
191 struct snd_soc_card
*card
;
192 struct x1e80100_snd_data
*data
;
193 struct device
*dev
= &pdev
->dev
;
196 card
= devm_kzalloc(dev
, sizeof(*card
), GFP_KERNEL
);
199 /* Allocate the private data */
200 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
204 card
->owner
= THIS_MODULE
;
206 dev_set_drvdata(dev
, card
);
207 snd_soc_card_set_drvdata(card
, data
);
209 ret
= qcom_snd_parse_of(card
);
213 card
->driver_name
= "x1e80100";
214 x1e80100_add_be_ops(card
);
216 return devm_snd_soc_register_card(dev
, card
);
219 static const struct of_device_id snd_x1e80100_dt_match
[] = {
220 { .compatible
= "qcom,x1e80100-sndcard", },
223 MODULE_DEVICE_TABLE(of
, snd_x1e80100_dt_match
);
225 static struct platform_driver snd_x1e80100_driver
= {
226 .probe
= x1e80100_platform_probe
,
228 .name
= "snd-x1e80100",
229 .of_match_table
= snd_x1e80100_dt_match
,
232 module_platform_driver(snd_x1e80100_driver
);
233 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
234 MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
235 MODULE_DESCRIPTION("Qualcomm X1E80100 ASoC Machine Driver");
236 MODULE_LICENSE("GPL");