165 lines · c
1// SPDX-License-Identifier: GPL-2.02// 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 card12 * @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 set15 * Soundwire stream runtime to each codec DAI.16 *17 * The shutdown() callback should call sdw_release_stream() on the same18 * sdw_stream_runtime.19 *20 * Return: 0 or errno21 */22int 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 46err_set_stream:47 sdw_release_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 = 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 port87 * enables and actual WSA881x PA enable. PA enable should only happen88 * after soundwire ports are enabled if not DC on the line is89 * accumulated resulting in Click/Pop Noise90 * 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}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 = 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}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 = 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}162EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);163MODULE_DESCRIPTION("Qualcomm ASoC SoundWire helper functions");164MODULE_LICENSE("GPL");165