[PATCH v3 1/4] ASoC: qcom: common: Add qcom_snd_tdm_hw_params function
Add qcom TDM setup function to support TDM ports for qcom platform.
Signed-off-by: Jianhua Lu lujianhua000@gmail.com --- Changes in v3: 1. new patch 2. split qcom_snd_tdm_hw_params function from [Patch v2 1/2] to here
sound/soc/qcom/common.c | 69 +++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/common.h | 2 ++ 2 files changed, 71 insertions(+)
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index 483bbf53a541..c0ab201416ef 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -5,6 +5,7 @@ #include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <sound/jack.h> +#include <sound/pcm_params.h> #include <linux/input-event-codes.h> #include "common.h"
@@ -13,6 +14,8 @@ static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), };
+static unsigned int tdm_slot_offset[8] = { 0, 4, 8, 12, 16, 20, 24, 28 }; + int qcom_snd_parse_of(struct snd_soc_card *card) { struct device_node *np; @@ -239,4 +242,70 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, return 0; } EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup); + +int qcom_snd_tdm_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); + int slots = ARRAY_SIZE(tdm_slot_offset); + int channels, slot_width, tx_mask, rx_mask; + int ret; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + slot_width = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + slot_width = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + slot_width = 32; + break; + default: + dev_err(rtd->dev, "%s: invalid param format 0x%x\n", __func__, + params_format(params)); + return -EINVAL; + } + + channels = params_channels(params); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + tx_mask = 0; + rx_mask = BIT(channels) - 1; + ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, slots, slot_width); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n", + __func__, ret); + return ret; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, channels, + tdm_slot_offset); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n", + __func__, ret); + return ret; + } + } else { + tx_mask = 0xf; + rx_mask = 0; + ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, slots, slot_width); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n", + __func__, ret); + return ret; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, channels, + tdm_slot_offset, 0, NULL); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n", + __func__, ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_snd_tdm_hw_params); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h index d7f80ee5ae26..b583110f556e 100644 --- a/sound/soc/qcom/common.h +++ b/sound/soc/qcom/common.h @@ -9,5 +9,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card); int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_jack *jack, bool *jack_setup); +int qcom_snd_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params);
#endif
Use qcom_snd_tdm_hw_params helper to setup TDM ports.
Signed-off-by: Jianhua Lu lujianhua000@gmail.com --- Changes in v3: 1. new patch
sound/soc/qcom/sdm845.c | 46 +++++++---------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-)
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 252a0f0819be..5052c1410723 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -53,8 +53,6 @@ static struct snd_soc_jack_pin sdm845_jack_pins[] = { }, };
-static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28}; - static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -99,10 +97,9 @@ static int sdm845_tdm_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 snd_soc_dai *codec_dai; int ret = 0, j; - int channels, slot_width; + int slot_width;
switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -114,39 +111,11 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream, return -EINVAL; }
- channels = params_channels(params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3, - 8, slot_width); - if (ret < 0) { - dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n", - __func__, ret); - goto end; - } - - ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, - channels, tdm_slot_offset); - if (ret < 0) { - dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n", - __func__, ret); - goto end; - } - } else { - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0, - 8, slot_width); - if (ret < 0) { - dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n", - __func__, ret); - goto end; - } - - ret = snd_soc_dai_set_channel_map(cpu_dai, channels, - tdm_slot_offset, 0, NULL); - if (ret < 0) { - dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n", - __func__, ret); - goto end; - } + ret = qcom_snd_tdm_hw_params(substream, params); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to setup TDM err:%d\n", + __func__, ret); + return ret; }
for_each_rtd_codec_dais(rtd, j, codec_dai) { @@ -176,8 +145,7 @@ static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream, } }
-end: - return ret; + return 0; }
static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
Setup TDM ports when dai id is matched to *_TDM_*.
Signed-off-by: Jianhua Lu lujianhua000@gmail.com --- Changes in v3: 1. split qcom_snd_tdm_hw_params function to common.c
Changes in v2: 1. remove EXPORT_SYMBOL_GPL 2. remove static modifier
sound/soc/qcom/sdw.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index 77dbe0c28b29..c07d878a1c18 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -5,6 +5,7 @@ #include <dt-bindings/sound/qcom,q6afe.h> #include <linux/module.h> #include <sound/soc.h> +#include "common.h" #include "sdw.h"
/** @@ -109,7 +110,7 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *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; + int ret, i;
switch (cpu_dai->id) { case WSA_CODEC_DMA_RX_0: @@ -125,6 +126,14 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream, *psruntime = sruntime; } break; + case PRIMARY_TDM_RX_0...QUINARY_TDM_TX_7: + ret = qcom_snd_tdm_hw_params(substream, params); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to setup TDM err:%d\n", + __func__, ret); + return ret; + } + break; }
return 0;
Add TERTIARY_TDM_RX_0 case to make speaker amplifiers working on Xiaomi Pad 5 Pro tablet.
Signed-off-by: Jianhua Lu lujianhua000@gmail.com --- No changes in v3.
No changes in v2.
sound/soc/qcom/sm8250.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index f298167c2a23..00c89c073e72 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -16,6 +16,7 @@
#define DRIVER_NAME "sm8250" #define MI2S_BCLK_RATE 1536000 +#define TDM_BCLK_RATE 12288000
struct sm8250_snd_data { bool stream_prepared[AFE_PORT_MAX]; @@ -53,6 +54,7 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret, j;
switch (cpu_dai->id) { case TERTIARY_MI2S_RX: @@ -63,6 +65,23 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_fmt(cpu_dai, fmt); snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; + case TERTIARY_TDM_RX_0: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_DSP_A; + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT, + TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + + for_each_rtd_codec_dais(rtd, j, codec_dai) { + ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + snd_soc_dai_set_sysclk(codec_dai, + 0, + TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + if (ret < 0) { + dev_err(rtd->dev, "TDM fmt err:%d\n", ret); + return ret; + } + } + break; default: break; }
On Wed, Dec 13, 2023 at 08:35:53PM +0800, Jianhua Lu wrote:
Add qcom TDM setup function to support TDM ports for qcom platform.
+int qcom_snd_tdm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
+{
...
ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, slots, slot_width);
if (ret < 0) {
The expectation is that TDM is set up by the machine driver, not from hw_params - if the TDM setup can be changed from within hw_params then it's hard to see how it's going to interact well with other TDM users on the bus. More usually hw_params() would be influenced by the setup done in set_tdm_slot().
On Thu, Dec 14, 2023 at 11:11:06AM +0000, Mark Brown wrote:
On Wed, Dec 13, 2023 at 08:35:53PM +0800, Jianhua Lu wrote:
Add qcom TDM setup function to support TDM ports for qcom platform.
+int qcom_snd_tdm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
+{
...
ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, rx_mask, slots, slot_width);
if (ret < 0) {
The expectation is that TDM is set up by the machine driver, not from hw_params - if the TDM setup can be changed from within hw_params then it's hard to see how it's going to interact well with other TDM users on the bus. More usually hw_params() would be influenced by the setup done in set_tdm_slot().
Currently, qcom TDM setup need to read hw_params, if we want to move it to machine driver, we must hardcode some params, but it will reduce reduce readability.
On Thu, Dec 14, 2023 at 11:51:50PM +0800, Jianhua Lu wrote:
On Thu, Dec 14, 2023 at 11:11:06AM +0000, Mark Brown wrote:
The expectation is that TDM is set up by the machine driver, not from hw_params - if the TDM setup can be changed from within hw_params then it's hard to see how it's going to interact well with other TDM users on the bus. More usually hw_params() would be influenced by the setup done in set_tdm_slot().
Currently, qcom TDM setup need to read hw_params, if we want to move it to machine driver, we must hardcode some params, but it will reduce reduce readability.
What makes you say that TDM setup needs to read hw_params?
On Thu, Dec 14, 2023 at 03:56:52PM +0000, Mark Brown wrote:
On Thu, Dec 14, 2023 at 11:51:50PM +0800, Jianhua Lu wrote:
On Thu, Dec 14, 2023 at 11:11:06AM +0000, Mark Brown wrote:
The expectation is that TDM is set up by the machine driver, not from hw_params - if the TDM setup can be changed from within hw_params then it's hard to see how it's going to interact well with other TDM users on the bus. More usually hw_params() would be influenced by the setup done in set_tdm_slot().
Currently, qcom TDM setup need to read hw_params, if we want to move it to machine driver, we must hardcode some params, but it will reduce reduce readability.
What makes you say that TDM setup needs to read hw_params?
qcom_snd_tdm_hw_params function read PCM_FORMAT to set slot_width value, read channels to set rx_mask value.
On Fri, Dec 15, 2023 at 12:55:08AM +0800, Jianhua Lu wrote:
On Thu, Dec 14, 2023 at 03:56:52PM +0000, Mark Brown wrote:
On Thu, Dec 14, 2023 at 11:51:50PM +0800, Jianhua Lu wrote:
Currently, qcom TDM setup need to read hw_params, if we want to move it to machine driver, we must hardcode some params, but it will reduce reduce readability.
What makes you say that TDM setup needs to read hw_params?
qcom_snd_tdm_hw_params function read PCM_FORMAT to set slot_width value, read channels to set rx_mask value.
A large part of the purpose of doing TDM configuration is to fix the slot width and assign which slots are in use by this interface - the TDM configuration is a constraint on what hardware paramters can be set and should always be followed regardless of what is being done with the audio stream. If you're just trying to configure the sample size for DSP modes then that shouldn't go through the TDM configuration API, that's just normal hw_params() so should be done directly. Possibly the hardware doesn't support manual TDM configuration?
participants (2)
-
Jianhua Lu
-
Mark Brown