mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
ASoC: qcom: sdw: fix memory leak
Merge series from Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>: For some reason we endedup allocating sdw_stream_runtime for every cpu dai, this has two issues. 1. we never set snd_soc_dai_set_stream for non soundwire dai, which means there is no way that we can free this, resulting in memory leak 2. startup and shutdown callbacks can be called without hw_params callback called. This combination results in memory leak because machine driver sruntime array pointer is only set in hw_params callback. All the machine drivers have these memory leaks, so cleanup the mess and make them use common helpers from sdw.c This patch series fix the issue, and while we are at it, it also remove some redundant code from machine drivers.
This commit is contained in:
@@ -281,6 +281,10 @@ static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
|
||||
rt_sdca_index_write(rt721->mbq_regmap, RT721_BOOST_CTRL,
|
||||
RT721_BST_4CH_TOP_GATING_CTRL1, 0x002a);
|
||||
regmap_write(rt721->regmap, 0x2f58, 0x07);
|
||||
|
||||
regmap_write(rt721->regmap, 0x2f51, 0x00);
|
||||
rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
|
||||
RT721_MISC_CTL, 0x0004);
|
||||
}
|
||||
|
||||
static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
|
||||
|
||||
@@ -137,6 +137,7 @@ struct rt721_sdca_dmic_kctrl_priv {
|
||||
#define RT721_HDA_LEGACY_UAJ_CTL 0x02
|
||||
#define RT721_HDA_LEGACY_CTL1 0x05
|
||||
#define RT721_HDA_LEGACY_RESET_CTL 0x06
|
||||
#define RT721_MISC_CTL 0x07
|
||||
#define RT721_XU_REL_CTRL 0x0c
|
||||
#define RT721_GE_REL_CTRL1 0x0d
|
||||
#define RT721_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e
|
||||
|
||||
@@ -131,7 +131,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = {
|
||||
.fifos = 8,
|
||||
.fifo_depth = 32,
|
||||
.dataline = 0xf,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_BE,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_LE,
|
||||
.use_edma = true,
|
||||
.use_verid = true,
|
||||
.volume_sx = false,
|
||||
@@ -823,7 +823,7 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
|
||||
break;
|
||||
}
|
||||
|
||||
if (format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
|
||||
if (format == SNDRV_PCM_FORMAT_DSD_U32_LE) {
|
||||
micfil->dec_bypass = true;
|
||||
/*
|
||||
* According to equation 29 in RM:
|
||||
|
||||
@@ -353,7 +353,6 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
|
||||
break;
|
||||
case SND_SOC_DAIFMT_PDM:
|
||||
val_cr2 |= FSL_SAI_CR2_BCP;
|
||||
val_cr4 &= ~FSL_SAI_CR4_MF;
|
||||
sai->is_pdm_mode = true;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
@@ -638,7 +637,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
|
||||
val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
|
||||
|
||||
if (sai->is_lsb_first || sai->is_pdm_mode)
|
||||
if (sai->is_lsb_first)
|
||||
val_cr5 |= FSL_SAI_CR5_FBT(0);
|
||||
else
|
||||
val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
|
||||
@@ -653,12 +652,12 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
val_cr4 |= FSL_SAI_CR4_CHMOD;
|
||||
|
||||
/*
|
||||
* For SAI provider mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
|
||||
* generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
|
||||
* RCR5(TCR5) for playback(capture), or there will be sync error.
|
||||
* When Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will provide bclk and
|
||||
* frame clock for Tx(Rx). We should set RCR4(TCR4), RCR5(TCR5)
|
||||
* for playback(capture), or there will be sync error.
|
||||
*/
|
||||
|
||||
if (!sai->is_consumer_mode[tx] && fsl_sai_dir_is_synced(sai, adir)) {
|
||||
if (fsl_sai_dir_is_synced(sai, adir)) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs),
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
|
||||
FSL_SAI_CR4_CHMOD_MASK,
|
||||
|
||||
@@ -651,6 +651,7 @@ static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_
|
||||
|
||||
data = snd_soc_dai_get_dma_data(dai, substream);
|
||||
|
||||
disable_work_sync(&data->period_elapsed_work);
|
||||
snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST);
|
||||
avs_dai_shutdown(substream, dai);
|
||||
}
|
||||
@@ -754,6 +755,8 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so
|
||||
data = snd_soc_dai_get_dma_data(dai, substream);
|
||||
host_stream = data->host_stream;
|
||||
|
||||
if (runtime->state == SNDRV_PCM_STATE_XRUN)
|
||||
hdac_stream(host_stream)->prepared = false;
|
||||
if (hdac_stream(host_stream)->prepared)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include "debug.h"
|
||||
#include "messages.h"
|
||||
|
||||
static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
|
||||
size_t buffer_size)
|
||||
static int avs_dsp_init_probe(struct avs_dev *adev, struct snd_compr_params *params, int bps,
|
||||
union avs_connector_node_id node_id, size_t buffer_size)
|
||||
{
|
||||
struct avs_probe_cfg cfg = {{0}};
|
||||
struct avs_module_entry mentry;
|
||||
@@ -27,12 +27,16 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Probe module uses no cycles, audio data format and input and output
|
||||
* frame sizes are unused. It is also not owned by any pipeline.
|
||||
* Probe module uses no cycles, input and output frame sizes are unused.
|
||||
* It is also not owned by any pipeline.
|
||||
*/
|
||||
cfg.base.ibs = 1;
|
||||
/* BSS module descriptor is always segment of index=2. */
|
||||
cfg.base.is_pages = mentry.segments[2].flags.length;
|
||||
cfg.base.audio_fmt.sampling_freq = params->codec.sample_rate;
|
||||
cfg.base.audio_fmt.bit_depth = bps;
|
||||
cfg.base.audio_fmt.num_channels = params->codec.ch_out;
|
||||
cfg.base.audio_fmt.valid_bit_depth = bps;
|
||||
cfg.gtw_cfg.node_id = node_id;
|
||||
cfg.gtw_cfg.dma_buffer_size = buffer_size;
|
||||
|
||||
@@ -128,8 +132,6 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
|
||||
struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
|
||||
struct snd_compr_runtime *rtd = cstream->runtime;
|
||||
struct avs_dev *adev = to_avs_dev(dai->dev);
|
||||
/* compr params do not store bit depth, default to S32_LE. */
|
||||
snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE;
|
||||
unsigned int format_val;
|
||||
int bps, ret;
|
||||
|
||||
@@ -142,7 +144,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
|
||||
ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
bps = snd_pcm_format_physical_width(format);
|
||||
bps = snd_pcm_format_physical_width(params->codec.format);
|
||||
if (bps < 0)
|
||||
return bps;
|
||||
format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate);
|
||||
@@ -166,7 +168,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
|
||||
node_id.vindex = hdac_stream(host_stream)->stream_tag - 1;
|
||||
node_id.dma_type = AVS_DMA_HDA_HOST_INPUT;
|
||||
|
||||
ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes);
|
||||
ret = avs_dsp_init_probe(adev, params, bps, node_id, rtd->dma_bytes);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "probe init failed: %d\n", ret);
|
||||
avs_dsp_enable_d0ix(adev);
|
||||
|
||||
@@ -3174,7 +3174,6 @@ err_pm_put:
|
||||
|
||||
static void mt8195_afe_pcm_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
mt8195_afe_runtime_suspend(&pdev->dev);
|
||||
}
|
||||
|
||||
@@ -2238,7 +2238,6 @@ static void mt8365_afe_pcm_dev_remove(struct platform_device *pdev)
|
||||
|
||||
mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_AFE);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
mt8365_afe_runtime_suspend(&pdev->dev);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
struct sc7280_snd_data {
|
||||
struct snd_soc_card card;
|
||||
struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS];
|
||||
u32 pri_mi2s_clk_count;
|
||||
struct snd_soc_jack hs_jack;
|
||||
struct snd_soc_jack hdmi_jack;
|
||||
@@ -207,32 +206,12 @@ static int sc7280_snd_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *codec_dai;
|
||||
const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
int i;
|
||||
|
||||
if (!rtd->dai_link->no_pcm) {
|
||||
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
|
||||
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, 48000, 48000);
|
||||
}
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case LPASS_CDC_DMA_TX3:
|
||||
case LPASS_CDC_DMA_RX0:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case SECONDARY_MI2S_RX:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
case VA_CODEC_DMA_TX_0:
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
|
||||
if (sruntime != ERR_PTR(-ENOTSUPP))
|
||||
pdata->sruntime[cpu_dai->id] = sruntime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -241,30 +220,8 @@ static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
int ret;
|
||||
|
||||
if (!sruntime)
|
||||
return 0;
|
||||
|
||||
if (data->stream_prepared[cpu_dai->id]) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
data->stream_prepared[cpu_dai->id] = false;
|
||||
}
|
||||
|
||||
ret = sdw_prepare_stream(sruntime);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sdw_enable_stream(sruntime);
|
||||
if (ret) {
|
||||
sdw_deprepare_stream(sruntime);
|
||||
return ret;
|
||||
}
|
||||
data->stream_prepared[cpu_dai->id] = true;
|
||||
|
||||
return ret;
|
||||
return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int sc7280_snd_prepare(struct snd_pcm_substream *substream)
|
||||
@@ -291,24 +248,8 @@ static int sc7280_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case LPASS_CDC_DMA_RX0:
|
||||
case LPASS_CDC_DMA_TX3:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
case VA_CODEC_DMA_TX_0:
|
||||
if (sruntime && data->stream_prepared[cpu_dai->id]) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
data->stream_prepared[cpu_dai->id] = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
@@ -317,7 +258,6 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case MI2S_PRIMARY:
|
||||
@@ -336,8 +276,7 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
break;
|
||||
}
|
||||
|
||||
data->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
qcom_snd_sdw_shutdown(substream);
|
||||
}
|
||||
|
||||
static int sc7280_snd_startup(struct snd_pcm_substream *substream)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
struct sc8280xp_snd_data {
|
||||
bool stream_prepared[AFE_PORT_MAX];
|
||||
struct snd_soc_card *card;
|
||||
struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
|
||||
struct snd_soc_jack jack;
|
||||
struct snd_soc_jack dp_jack[8];
|
||||
bool jack_setup;
|
||||
@@ -68,17 +67,6 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
|
||||
}
|
||||
|
||||
static void sc8280xp_snd_shutdown(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);
|
||||
struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id];
|
||||
|
||||
pdata->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
}
|
||||
|
||||
static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
@@ -108,25 +96,13 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
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);
|
||||
struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int sc8280xp_snd_prepare(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);
|
||||
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
return qcom_snd_sdw_prepare(substream, sruntime,
|
||||
&data->stream_prepared[cpu_dai->id]);
|
||||
return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
@@ -134,16 +110,13 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
return qcom_snd_sdw_hw_free(substream, sruntime,
|
||||
&data->stream_prepared[cpu_dai->id]);
|
||||
return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops sc8280xp_be_ops = {
|
||||
.startup = qcom_snd_sdw_startup,
|
||||
.shutdown = sc8280xp_snd_shutdown,
|
||||
.hw_params = sc8280xp_snd_hw_params,
|
||||
.shutdown = qcom_snd_sdw_shutdown,
|
||||
.hw_free = sc8280xp_snd_hw_free,
|
||||
.prepare = sc8280xp_snd_prepare,
|
||||
};
|
||||
|
||||
@@ -40,7 +40,6 @@ struct sdm845_snd_data {
|
||||
uint32_t pri_mi2s_clk_count;
|
||||
uint32_t sec_mi2s_clk_count;
|
||||
uint32_t quat_tdm_clk_count;
|
||||
struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin sdm845_jack_pins[] = {
|
||||
@@ -62,18 +61,11 @@ static int sdm845_slim_snd_hw_params(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);
|
||||
struct snd_soc_dai *codec_dai;
|
||||
struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
|
||||
u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
|
||||
int ret = 0, i;
|
||||
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
sruntime = snd_soc_dai_get_stream(codec_dai,
|
||||
substream->stream);
|
||||
if (sruntime != ERR_PTR(-ENOTSUPP))
|
||||
pdata->sruntime[cpu_dai->id] = sruntime;
|
||||
|
||||
ret = snd_soc_dai_get_channel_map(codec_dai,
|
||||
&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
|
||||
|
||||
@@ -430,7 +422,6 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case PRIMARY_MI2S_RX:
|
||||
@@ -471,8 +462,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
break;
|
||||
}
|
||||
|
||||
data->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
qcom_snd_sdw_shutdown(substream);
|
||||
}
|
||||
|
||||
static int sdm845_snd_prepare(struct snd_pcm_substream *substream)
|
||||
@@ -480,38 +470,8 @@ static int sdm845_snd_prepare(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
int ret;
|
||||
|
||||
if (!sruntime)
|
||||
return 0;
|
||||
|
||||
if (data->stream_prepared[cpu_dai->id]) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
data->stream_prepared[cpu_dai->id] = false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
data->stream_prepared[cpu_dai->id] = true;
|
||||
|
||||
return ret;
|
||||
return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int sdm845_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
@@ -519,15 +479,8 @@ static int sdm845_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
if (sruntime && data->stream_prepared[cpu_dai->id]) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
data->stream_prepared[cpu_dai->id] = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops sdm845_be_ops = {
|
||||
|
||||
@@ -2,11 +2,53 @@
|
||||
// Copyright (c) 2018-2023, Linaro Limited.
|
||||
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <dt-bindings/sound/qcom,lpass.h>
|
||||
#include <dt-bindings/sound/qcom,q6afe.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
#include "sdw.h"
|
||||
|
||||
static bool qcom_snd_is_sdw_dai(int id)
|
||||
{
|
||||
switch (id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_TX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case WSA_CODEC_DMA_TX_1:
|
||||
case WSA_CODEC_DMA_TX_2:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case RX_CODEC_DMA_RX_2:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case RX_CODEC_DMA_RX_3:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
case RX_CODEC_DMA_RX_4:
|
||||
case TX_CODEC_DMA_TX_4:
|
||||
case RX_CODEC_DMA_RX_5:
|
||||
case TX_CODEC_DMA_TX_5:
|
||||
case RX_CODEC_DMA_RX_6:
|
||||
case RX_CODEC_DMA_RX_7:
|
||||
case SLIMBUS_0_RX...SLIMBUS_6_TX:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* DSP Bypass usecase, cpu dai index overlaps with DSP dai ids,
|
||||
* DO NOT MERGE into top switch case */
|
||||
switch (id) {
|
||||
case LPASS_CDC_DMA_TX3:
|
||||
case LPASS_CDC_DMA_RX0:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
@@ -29,6 +71,9 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream)
|
||||
u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
|
||||
int ret, i, j;
|
||||
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
return 0;
|
||||
|
||||
sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM);
|
||||
if (!sruntime)
|
||||
return -ENOMEM;
|
||||
@@ -79,29 +124,20 @@ err_set_stream:
|
||||
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);
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
int ret;
|
||||
|
||||
if (!sruntime)
|
||||
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
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:
|
||||
sruntime = qcom_snd_sdw_get_stream(substream);
|
||||
if (!sruntime)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*stream_prepared)
|
||||
return 0;
|
||||
@@ -129,9 +165,7 @@ int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
}
|
||||
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 sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *codec_dai;
|
||||
@@ -139,50 +173,40 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
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;
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
return NULL;
|
||||
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
|
||||
if (sruntime != ERR_PTR(-ENOTSUPP))
|
||||
return sruntime;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_get_stream);
|
||||
|
||||
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime, bool *stream_prepared)
|
||||
void qcom_snd_sdw_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream);
|
||||
|
||||
sdw_release_stream(sruntime);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_shutdown);
|
||||
|
||||
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream, 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);
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
|
||||
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;
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
return 0;
|
||||
|
||||
sruntime = qcom_snd_sdw_get_stream(substream);
|
||||
if (sruntime && *stream_prepared) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
*stream_prepared = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -7,13 +7,10 @@
|
||||
#include <linux/soundwire/sdw.h>
|
||||
|
||||
int qcom_snd_sdw_startup(struct snd_pcm_substream *substream);
|
||||
void qcom_snd_sdw_shutdown(struct snd_pcm_substream *substream);
|
||||
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *runtime,
|
||||
bool *stream_prepared);
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime);
|
||||
struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *stream);
|
||||
int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime,
|
||||
bool *stream_prepared);
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
struct sm8250_snd_data {
|
||||
bool stream_prepared[AFE_PORT_MAX];
|
||||
struct snd_soc_card *card;
|
||||
struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
|
||||
struct snd_soc_jack jack;
|
||||
struct snd_soc_jack usb_offload_jack;
|
||||
bool usb_offload_jack_setup;
|
||||
@@ -112,36 +111,13 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream)
|
||||
return qcom_snd_sdw_startup(substream);
|
||||
}
|
||||
|
||||
static void sm8250_snd_shutdown(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);
|
||||
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
data->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
}
|
||||
|
||||
static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
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);
|
||||
struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int sm8250_snd_prepare(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);
|
||||
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
return qcom_snd_sdw_prepare(substream, sruntime,
|
||||
&data->stream_prepared[cpu_dai->id]);
|
||||
return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
@@ -149,16 +125,13 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
return qcom_snd_sdw_hw_free(substream, sruntime,
|
||||
&data->stream_prepared[cpu_dai->id]);
|
||||
return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops sm8250_be_ops = {
|
||||
.startup = sm8250_snd_startup,
|
||||
.shutdown = sm8250_snd_shutdown,
|
||||
.hw_params = sm8250_snd_hw_params,
|
||||
.shutdown = qcom_snd_sdw_shutdown,
|
||||
.hw_free = sm8250_snd_hw_free,
|
||||
.prepare = sm8250_snd_prepare,
|
||||
};
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
struct x1e80100_snd_data {
|
||||
bool stream_prepared[AFE_PORT_MAX];
|
||||
struct snd_soc_card *card;
|
||||
struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
|
||||
struct snd_soc_jack jack;
|
||||
struct snd_soc_jack dp_jack[8];
|
||||
bool jack_setup;
|
||||
@@ -50,17 +49,6 @@ static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd)
|
||||
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
|
||||
}
|
||||
|
||||
static void x1e80100_snd_shutdown(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);
|
||||
struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
data->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
}
|
||||
|
||||
static int x1e80100_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
@@ -85,16 +73,6 @@ static int x1e80100_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int x1e80100_snd_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
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);
|
||||
struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
|
||||
return qcom_snd_sdw_hw_params(substream, params, &data->sruntime[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int x1e80100_snd_hw_map_channels(unsigned int *ch_map, int num)
|
||||
{
|
||||
switch (num) {
|
||||
@@ -128,7 +106,6 @@ static int x1e80100_snd_prepare(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);
|
||||
struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
unsigned int channels = substream->runtime->channels;
|
||||
unsigned int rx_slot[4];
|
||||
int ret;
|
||||
@@ -149,8 +126,7 @@ static int x1e80100_snd_prepare(struct snd_pcm_substream *substream)
|
||||
break;
|
||||
}
|
||||
|
||||
return qcom_snd_sdw_prepare(substream, sruntime,
|
||||
&data->stream_prepared[cpu_dai->id]);
|
||||
return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static int x1e80100_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
@@ -158,16 +134,13 @@ static int x1e80100_snd_hw_free(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
|
||||
return qcom_snd_sdw_hw_free(substream, sruntime,
|
||||
&data->stream_prepared[cpu_dai->id]);
|
||||
return qcom_snd_sdw_hw_free(substream, &data->stream_prepared[cpu_dai->id]);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops x1e80100_be_ops = {
|
||||
.startup = qcom_snd_sdw_startup,
|
||||
.shutdown = x1e80100_snd_shutdown,
|
||||
.hw_params = x1e80100_snd_hw_params,
|
||||
.shutdown = qcom_snd_sdw_shutdown,
|
||||
.hw_free = x1e80100_snd_hw_free,
|
||||
.prepare = x1e80100_snd_prepare,
|
||||
};
|
||||
|
||||
@@ -691,7 +691,6 @@ struct asoc_sdw_codec_info codec_info_list[] = {
|
||||
{
|
||||
.direction = {true, false},
|
||||
.dai_name = "cs42l43-dp6",
|
||||
.component_name = "cs42l43",
|
||||
.dai_type = SOC_SDW_DAI_TYPE_AMP,
|
||||
.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
|
||||
.init = asoc_sdw_cs42l43_spk_init,
|
||||
|
||||
Reference in New Issue
Block a user