Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 195 additions & 5 deletions audioreach-driver/audioreach_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
struct qcs6490_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;
Expand Down Expand Up @@ -62,6 +63,182 @@ static struct snd_soc_jack_pin qcs6490_headset_jack_pins[] = {
},
};

static int qcs6490_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;
}

static int qcs6490_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;
}

static int qcs6490_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;
}

static int qcs6490_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;
}

static void qcs6490_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 qcs6490_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 qcs6490_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *dp_jack, int dp_pcm_id)
Expand Down Expand Up @@ -388,7 +565,7 @@ static int qcs6490_snd_init(struct snd_soc_pcm_runtime *rtd)
}

static int qcs6490_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
struct snd_pcm_hw_params *params)
{
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_interval *rate = hw_param_interval(params,
Expand All @@ -414,27 +591,40 @@ static int qcs6490_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}

static int qcs6490_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 qcs6490_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);

return qcs6490_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
}

static int qcs6490_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 qcs6490_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, &data->stream_prepared[cpu_dai->id]);
return qcs6490_snd_sdw_prepare(substream, sruntime, &data->stream_prepared[cpu_dai->id]);
}

static int qcs6490_snd_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct qcs6490_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, &data->stream_prepared[cpu_dai->id]);
return qcs6490_snd_sdw_hw_free(substream, sruntime, &data->stream_prepared[cpu_dai->id]);
}

static const struct snd_soc_ops qcs6490_be_ops = {
.startup = qcom_snd_sdw_startup,
.shutdown = qcom_snd_sdw_shutdown,
.startup = qcs6490_snd_sdw_startup,
.shutdown = qcs6490_snd_shutdown,
.hw_params = qcs6490_snd_hw_params,
.hw_free = qcs6490_snd_hw_free,
.prepare = qcs6490_snd_prepare,
};
Expand Down
Loading