linux/sound/soc/qcom/sdw.c
Linus Torvalds 4d31167e84 soundwire updates for 6.15
- Support for SoundWire Bulk Register Access (BRA) protocol in core
    along with Intel driver support and ASoC bits required.
  - AMD driver updates and support for ACP 7.0 and 7.1 platforms
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmfqPDQACgkQfBQHDyUj
 g0fkMhAAo5kIXK3etgyxkeGuMxY9ufJB495qkwkjN4451AhlsUXkalrUd/8XUyhU
 sO/vBlc0ib8g+5PV+itHLunqWjYVC73IZA/BYZYEwgyPNZTY+jEchov7dK8Ijyx4
 S45NBZjUqxStiYmdMQ1xq4BgGPdQhc7mHd206m5L+9x8QtoOCoAT5gw0zYkjWLgY
 xw5xNPlEPeFISnrxdkm+LNn2d/OgTaq1rpWrD23rwTJijOatlJ/gJ1+ga05BV6ja
 ymDRJRHdTnyzkjV+SsUEY+O3XfaVgDo9AORzWMqe0TJwE/NKAhq+1DvcXKV3avVY
 AZMbFH3Gj7UL1oQF3r1hbpjzSKuTzB9n7h/iaJqg1XRH+sbnr/0jr/jYwgEucQ1z
 Pcv6XFb0cxyxdVf5ss6NFAsfGfeggJBrQ9lvoi4EWLPaA2whCFpVKNOU0m4UkEFF
 ZZN2hGDykTK84Q3jOHepKIr1/gYcBJo0iO5q8Urb/5BayioZmBmFgncEI6Hw6exU
 FujEumJMS21ZIV+LYDNOb7nJpPv/dcNSotT3M8u1W87I+dgB+8h6Y4lfmLrFIb2p
 5YkXH9WbRG49XGGVWRr7rRCIMpKdez0d9gnd7lNf0dGgTfpws+4hU9iDYQYatL/5
 z0XXfEajfPPy2tlRAkfO8xUu3k068EhZ/Q84y9inX76jC/kfoxU=
 =fe9N
 -----END PGP SIGNATURE-----

Merge tag 'soundwire-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire

Pull soundwire updates from Vinod Koul:

 - Support for SoundWire Bulk Register Access (BRA) protocol in core
   along with Intel driver support and ASoC bits required

 - AMD driver updates and support for ACP 7.0 and 7.1 platforms

* tag 'soundwire-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (28 commits)
  soundwire: take in count the bandwidth of a prepared stream
  ASoC: rt711-sdca: add DP0 support
  soundwire: debugfs: add interface for BPT/BRA transfers
  ASoC: SOF: Intel: hda-sdw-bpt: add CHAIN_DMA support
  soundwire: intel_ace2x: add BPT send_async/wait callbacks
  soundwire: intel: add BPT context definition
  ASoC: SOF: Intel: hda-sdw-bpt: add helpers for SoundWire BPT DMA
  soundwire: intel_auxdevice: add indirection for BPT send_async/wait
  soundwire: cadence: add BTP/BRA helpers to format data
  soundwire: bus: add bpt_stream pointer
  soundwire: bus: add send_async/wait APIs for BPT protocol
  soundwire: stream: reuse existing code for BPT stream
  soundwire: stream: special-case the bus compute_params() routine
  soundwire: stream: extend sdw_alloc_stream() to take 'type' parameter
  soundwire: extend sdw_stream_type to BPT
  soundwire: cadence: add BTP support for DP0
  Documentation: driver: add SoundWire BRA description
  soundwire: amd: change the log level for command response log
  soundwire: slave: fix an OF node reference leak in soundwire slave device
  soundwire: Use str_enable_disable-like helpers
  ...
2025-04-01 12:43:13 -07:00

192 lines
4.9 KiB
C

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2023, Linaro Limited.
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
#include <dt-bindings/sound/qcom,q6afe.h>
#include <linux/module.h>
#include <sound/soc.h>
#include "sdw.h"
/**
* qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card
* @substream: The PCM substream from audio, as passed to snd_soc_ops->startup()
*
* Helper for the SoC audio card (snd_soc_ops->startup()) to allocate and set
* Soundwire stream runtime to each codec DAI.
*
* The shutdown() callback should call sdw_release_stream() on the same
* sdw_stream_runtime.
*
* Return: 0 or errno
*/
int qcom_snd_sdw_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
u32 rx_ch[SDW_MAX_PORTS], tx_ch[SDW_MAX_PORTS];
struct sdw_stream_runtime *sruntime;
struct snd_soc_dai *codec_dai;
u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
int ret, i, j;
sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM);
if (!sruntime)
return -ENOMEM;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
ret = snd_soc_dai_set_stream(codec_dai, sruntime,
substream->stream);
if (ret < 0 && ret != -ENOTSUPP) {
dev_err(rtd->dev, "Failed to set sdw stream on %s\n", codec_dai->name);
goto err_set_stream;
} else if (ret == -ENOTSUPP) {
/* Ignore unsupported */
continue;
}
ret = snd_soc_dai_get_channel_map(codec_dai, &tx_ch_cnt, tx_ch,
&rx_ch_cnt, rx_ch);
if (ret != 0 && ret != -ENOTSUPP) {
dev_err(rtd->dev, "Failed to get codec chan map %s\n", codec_dai->name);
goto err_set_stream;
} else if (ret == -ENOTSUPP) {
/* Ignore unsupported */
continue;
}
}
switch (cpu_dai->id) {
case RX_CODEC_DMA_RX_0:
case TX_CODEC_DMA_TX_3:
if (tx_ch_cnt || rx_ch_cnt) {
for_each_rtd_codec_dais(rtd, j, codec_dai) {
ret = snd_soc_dai_set_channel_map(codec_dai,
tx_ch_cnt, tx_ch,
rx_ch_cnt, rx_ch);
if (ret != 0 && ret != -ENOTSUPP)
goto err_set_stream;
}
}
}
return 0;
err_set_stream:
sdw_release_stream(sruntime);
return ret;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_startup);
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime,
bool *stream_prepared)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
int ret;
if (!sruntime)
return 0;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
break;
default:
return 0;
}
if (*stream_prepared)
return 0;
ret = sdw_prepare_stream(sruntime);
if (ret)
return ret;
/**
* NOTE: there is a strict hw requirement about the ordering of port
* enables and actual WSA881x PA enable. PA enable should only happen
* after soundwire ports are enabled if not DC on the line is
* accumulated resulting in Click/Pop Noise
* PA enable/mute are handled as part of codec DAPM and digital mute.
*/
ret = sdw_enable_stream(sruntime);
if (ret) {
sdw_deprepare_stream(sruntime);
return ret;
}
*stream_prepared = true;
return ret;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct sdw_stream_runtime **psruntime)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sdw_stream_runtime *sruntime;
int i;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
for_each_rtd_codec_dais(rtd, i, codec_dai) {
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
if (sruntime != ERR_PTR(-ENOTSUPP))
*psruntime = sruntime;
}
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
struct sdw_stream_runtime *sruntime, bool *stream_prepared)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
case RX_CODEC_DMA_RX_0:
case RX_CODEC_DMA_RX_1:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
case TX_CODEC_DMA_TX_3:
if (sruntime && *stream_prepared) {
sdw_disable_stream(sruntime);
sdw_deprepare_stream(sruntime);
*stream_prepared = false;
}
break;
default:
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
MODULE_DESCRIPTION("Qualcomm ASoC SoundWire helper functions");
MODULE_LICENSE("GPL");