[alsa-devel] [PATCH 0/4] ASoC: SOF: control/topology improvements
3 patches to improve volume handling and DMIC unmute, plus a long-overdue one to avoid waking-up the DSP when reading from a kcontrol cached value.
Bard Liao (1): ASoC: SOF: dont wake dsp up in kcontrol IO
Seppo Ingalsuo (1): ASoC: SOF: Add DMIC token for unmute gain ramp time
Zhu Yingjiang (2): ASoC: SOF: topology: add min/max step for volume_table ASoC: SOF: topology: pass volume min/max linear value to FW
include/sound/sof/dai-intel.h | 3 +- include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/control.c | 270 +++++--------------------------- sound/soc/sof/sof-priv.h | 2 + sound/soc/sof/topology.c | 68 ++++++++ 6 files changed, 112 insertions(+), 234 deletions(-)
From: Zhu Yingjiang yingjiang.zhu@linux.intel.com
add two units min_volume_step and max_volume_step to the snd_sof_control struct, for the min and max step of the volume_table.
Signed-off-by: Zhu Yingjiang yingjiang.zhu@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- sound/soc/sof/sof-priv.h | 2 ++ sound/soc/sof/topology.c | 2 ++ 2 files changed, 4 insertions(+)
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 563623bcaad6..d2dbca7d57d1 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -297,6 +297,8 @@ struct snd_sof_pcm { struct snd_sof_control { struct snd_sof_dev *sdev; int comp_id; + int min_volume_step; /* min volume step for volume_table */ + int max_volume_step; /* max volume step for volume_table */ int num_channels; u32 readback_offset; /* offset to mmaped data if used */ struct sof_ipc_ctrl_data *control_data; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a13233ae6d0e..1c661dec8dd4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -451,6 +451,8 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, return -ENOMEM;
scontrol->comp_id = sdev->next_comp_id; + scontrol->min_volume_step = le32_to_cpu(mc->min); + scontrol->max_volume_step = le32_to_cpu(mc->max); scontrol->num_channels = le32_to_cpu(mc->num_channels);
/* set cmd for mixer control */
The patch
ASoC: SOF: topology: add min/max step for volume_table
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.3
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From aa66fd80e0813fab0146e001b8bef8c4ffe0ba3a Mon Sep 17 00:00:00 2001
From: Zhu Yingjiang yingjiang.zhu@linux.intel.com Date: Wed, 12 Jun 2019 12:01:45 -0500 Subject: [PATCH] ASoC: SOF: topology: add min/max step for volume_table
add two units min_volume_step and max_volume_step to the snd_sof_control struct, for the min and max step of the volume_table.
Signed-off-by: Zhu Yingjiang yingjiang.zhu@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sof/sof-priv.h | 2 ++ sound/soc/sof/topology.c | 2 ++ 2 files changed, 4 insertions(+)
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 17f3d2a5a701..8760a4694d8f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -297,6 +297,8 @@ struct snd_sof_pcm { struct snd_sof_control { struct snd_sof_dev *sdev; int comp_id; + int min_volume_step; /* min volume step for volume_table */ + int max_volume_step; /* max volume step for volume_table */ int num_channels; u32 readback_offset; /* offset to mmaped data if used */ struct sof_ipc_ctrl_data *control_data; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a13233ae6d0e..1c661dec8dd4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -451,6 +451,8 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, return -ENOMEM;
scontrol->comp_id = sdev->next_comp_id; + scontrol->min_volume_step = le32_to_cpu(mc->min); + scontrol->max_volume_step = le32_to_cpu(mc->max); scontrol->num_channels = le32_to_cpu(mc->num_channels);
/* set cmd for mixer control */
From: Zhu Yingjiang yingjiang.zhu@linux.intel.com
The driver currently passes the volume ramp type and length topology tokens to firmware, but the min and max volume are not set. This patch provides a correction to convert the information from the topology file and pass the linear volume min/max value to the firmware to improve transitions.
Signed-off-by: Zhu Yingjiang yingjiang.zhu@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- sound/soc/sof/topology.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1c661dec8dd4..bbad8053b1bc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1552,6 +1552,9 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_volume *volume; + struct snd_sof_control *scontrol; + int min_step; + int max_step; int ret;
volume = kzalloc(sizeof(*volume), GFP_KERNEL); @@ -1594,6 +1597,17 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
swidget->private = volume;
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id) { + min_step = scontrol->min_volume_step; + max_step = scontrol->max_volume_step; + volume->min_value = scontrol->volume_table[min_step]; + volume->max_value = scontrol->volume_table[max_step]; + volume->channels = scontrol->num_channels; + break; + } + } + ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume, sizeof(*volume), r, sizeof(*r)); if (ret >= 0)
The patch
ASoC: SOF: topology: pass volume min/max linear value to FW
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.3
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 65a18a46b274e64012fcf19d79ac62c8fb2a12e9 Mon Sep 17 00:00:00 2001
From: Zhu Yingjiang yingjiang.zhu@linux.intel.com Date: Wed, 12 Jun 2019 12:01:46 -0500 Subject: [PATCH] ASoC: SOF: topology: pass volume min/max linear value to FW
The driver currently passes the volume ramp type and length topology tokens to firmware, but the min and max volume are not set. This patch provides a correction to convert the information from the topology file and pass the linear volume min/max value to the firmware to improve transitions.
Signed-off-by: Zhu Yingjiang yingjiang.zhu@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sof/topology.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1c661dec8dd4..bbad8053b1bc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1552,6 +1552,9 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_volume *volume; + struct snd_sof_control *scontrol; + int min_step; + int max_step; int ret;
volume = kzalloc(sizeof(*volume), GFP_KERNEL); @@ -1594,6 +1597,17 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
swidget->private = volume;
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id) { + min_step = scontrol->min_volume_step; + max_step = scontrol->max_volume_step; + volume->min_value = scontrol->volume_table[min_step]; + volume->max_value = scontrol->volume_table[max_step]; + volume->channels = scontrol->num_channels; + break; + } + } + ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume, sizeof(*volume), r, sizeof(*r)); if (ret >= 0)
From: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
The settling time of DMIC DC level is both platform and used microphone model specific. The unmute gain ramp is used to conceal most of the large DC level seen in beginning of capture. This patch adds into the DMIC DAI IPC struct a new field called unmute_ramp_time and a new token SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME. The value is the ramp length in milliseconds (ms).
The ABI minor version is incremented for this backwards compatible change.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- include/sound/sof/dai-intel.h | 3 ++- include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/topology.c | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 4bd83f7adddf..4bb8ee138ba7 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -167,9 +167,10 @@ struct sof_ipc_dai_dmic_params {
uint32_t wake_up_time; /**< Time from clock start to data (us) */ uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */ + uint32_t unmute_ramp_time; /**< Length of logarithmic gain ramp (ms) */
/* reserved for future use */ - uint32_t reserved[6]; + uint32_t reserved[5];
/**< variable number of pdm controller config */ struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 92eee681bc62..4a9c24434f42 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 7 +#define SOF_ABI_MINOR 8 #define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 53ea94bf1c08..dc1b27daaac6 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -85,6 +85,7 @@ #define SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE 605 #define SOF_TKN_INTEL_DMIC_SAMPLE_RATE 608 #define SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH 609 +#define SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS 610
/* DMIC PDM */ #define SOF_TKN_INTEL_DMIC_PDM_CTRL_ID 700 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index bbad8053b1bc..8e00f829bfdb 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -779,6 +779,10 @@ static const struct sof_topology_token dmic_tokens[] = { {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, offsetof(struct sof_ipc_dai_dmic_params, fifo_bits), 0}, + {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time), 0}, + };
/*
The patch
ASoC: SOF: Add DMIC token for unmute gain ramp time
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.3
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 7df43911e92aa2137ae77ae60efaa9d6656df3fe Mon Sep 17 00:00:00 2001
From: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com Date: Wed, 12 Jun 2019 12:01:47 -0500 Subject: [PATCH] ASoC: SOF: Add DMIC token for unmute gain ramp time
The settling time of DMIC DC level is both platform and used microphone model specific. The unmute gain ramp is used to conceal most of the large DC level seen in beginning of capture. This patch adds into the DMIC DAI IPC struct a new field called unmute_ramp_time and a new token SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME. The value is the ramp length in milliseconds (ms).
The ABI minor version is incremented for this backwards compatible change.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- include/sound/sof/dai-intel.h | 3 ++- include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/topology.c | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 4bd83f7adddf..4bb8ee138ba7 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -167,9 +167,10 @@ struct sof_ipc_dai_dmic_params {
uint32_t wake_up_time; /**< Time from clock start to data (us) */ uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */ + uint32_t unmute_ramp_time; /**< Length of logarithmic gain ramp (ms) */
/* reserved for future use */ - uint32_t reserved[6]; + uint32_t reserved[5];
/**< variable number of pdm controller config */ struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 92eee681bc62..4a9c24434f42 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 7 +#define SOF_ABI_MINOR 8 #define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 53ea94bf1c08..dc1b27daaac6 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -85,6 +85,7 @@ #define SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE 605 #define SOF_TKN_INTEL_DMIC_SAMPLE_RATE 608 #define SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH 609 +#define SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS 610
/* DMIC PDM */ #define SOF_TKN_INTEL_DMIC_PDM_CTRL_ID 700 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index bbad8053b1bc..8e00f829bfdb 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -779,6 +779,10 @@ static const struct sof_topology_token dmic_tokens[] = { {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, offsetof(struct sof_ipc_dai_dmic_params, fifo_bits), 0}, + {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time), 0}, + };
/*
From: Bard Liao yung-chuan.liao@linux.intel.com
Always get kcontrol value from cache, set kcontrol value to DSP when DSP is active. Kcontrol values will be restored when DSP boot up. We will set the default value of kcontrol in sof_complete to make sure the value is align with firmware.
Signed-off-by: Bard Liao yung-chuan.liao@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- sound/soc/sof/control.c | 270 ++++++--------------------------------- sound/soc/sof/topology.c | 48 +++++++ 2 files changed, 86 insertions(+), 232 deletions(-)
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 84e2cbfbbcbb..a4983f90ff5b 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: volume get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the mixer data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME, - false);
/* read back each channel */ for (i = 0; i < channels; i++) @@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, ipc_to_mixer(cdata->chanv[i].value, scontrol->volume_table, sm->max + 1);
- pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: volume get failed to idle %d\n", - err); return 0; }
@@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: volume put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - }
/* update each channel */ for (i = 0; i < channels; i++) { @@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, }
/* notify DSP of mixer updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: volume put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME, + true); + return 0; }
@@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: switch get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the mixer data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH, - false);
/* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.integer.value[i] = cdata->chanv[i].value;
- pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: switch get failed to idle %d\n", - err); return 0; }
@@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: switch put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - }
/* update each channel */ for (i = 0; i < channels; i++) { @@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, }
/* notify DSP of mixer updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: switch put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH, + true); + return 0; }
@@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: enum get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the enum data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM, - false);
/* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
- pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: enum get failed to idle %d\n", - err); return 0; }
@@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: enum put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - }
/* update each channel */ for (i = 0; i < channels; i++) { @@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, }
/* notify DSP of enum updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: enum put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM, + true); + return 0; }
@@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size; - int ret, err; + int ret = 0;
if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(sdev->dev, @@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, return -EINVAL; }
- ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the binary data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, - scontrol->cmd, - false); - size = data->size + sizeof(*data); if (size > be->max) { dev_err_ratelimited(sdev->dev, @@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, memcpy(ucontrol->value.bytes.data, data, size);
out: - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes get failed to idle %d\n", - err); return ret; }
@@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size = data->size + sizeof(*data); - int ret, err;
if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(sdev->dev, @@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, return -EINVAL; }
- ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* copy from kcontrol */ memcpy(data, ucontrol->value.bytes.data, size);
/* notify DSP of byte control updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes put failed to idle %d\n", - err); - return ret; + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); + + return 0; }
int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, @@ -406,8 +252,6 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv header; const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data; - int ret; - int err;
/* * The beginning of bytes data contains a header from where @@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EINVAL; }
- ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes_ext put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* notify DSP of byte control updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes_ext put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true);
- return ret; + return 0; }
int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, @@ -492,17 +321,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; int data_size; - int err; - int ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes_ext get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } + int ret = 0;
/* * Decrement the limit by ext bytes header size to @@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION;
- /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, - scontrol->cmd, - false); - /* Prevent read of other kernel data or possibly corrupt response */ data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
@@ -543,11 +355,5 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, ret = -EFAULT;
out: - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes_ext get failed to idle %d\n", - err); return ret; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 8e00f829bfdb..aaf459af89d0 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3016,6 +3016,49 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, return ret; }
+/* Function to set the initial value of SOF kcontrols. + * The value will be stored in scontrol->control_data + */ +static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev) +{ + struct snd_sof_control *scontrol = NULL; + int ipc_cmd, ctrl_type; + int ret = 0; + + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + + /* notify DSP of kcontrol values */ + switch (scontrol->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + ipc_cmd = SOF_IPC_COMP_GET_VALUE; + ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET; + break; + case SOF_CTRL_CMD_BINARY: + ipc_cmd = SOF_IPC_COMP_GET_DATA; + ctrl_type = SOF_CTRL_TYPE_DATA_GET; + break; + default: + dev_err(sdev->dev, + "error: Invalid scontrol->cmd: %d\n", + scontrol->cmd); + return -EINVAL; + } + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + false); + if (ret < 0) { + dev_warn(sdev->dev, + "error: kcontrol value get for widget: %d\n", + scontrol->comp_id); + } + } + + return ret; +} + int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { @@ -3059,6 +3102,11 @@ static void sof_complete(struct snd_soc_component *scomp) break; } } + /* + * cache initial values of SOF kcontrols by reading DSP value over + * IPC. It may be overwritten by alsa-mixer after booting up + */ + snd_sof_cache_kcontrol_val(sdev); }
/* manifest - optional to inform component of manifest */
The patch
ASoC: SOF: dont wake dsp up in kcontrol IO
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.3
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 0c888baba8e041c92c5c1882f25b8df5c29bff9f Mon Sep 17 00:00:00 2001
From: Bard Liao yung-chuan.liao@linux.intel.com Date: Wed, 12 Jun 2019 12:01:48 -0500 Subject: [PATCH] ASoC: SOF: dont wake dsp up in kcontrol IO
Always get kcontrol value from cache, set kcontrol value to DSP when DSP is active. Kcontrol values will be restored when DSP boot up. We will set the default value of kcontrol in sof_complete to make sure the value is align with firmware.
Signed-off-by: Bard Liao yung-chuan.liao@linux.intel.com Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sof/control.c | 270 ++++++--------------------------------- sound/soc/sof/topology.c | 48 +++++++ 2 files changed, 86 insertions(+), 232 deletions(-)
diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 84e2cbfbbcbb..a4983f90ff5b 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: volume get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the mixer data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME, - false);
/* read back each channel */ for (i = 0; i < channels; i++) @@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, ipc_to_mixer(cdata->chanv[i].value, scontrol->volume_table, sm->max + 1);
- pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: volume get failed to idle %d\n", - err); return 0; }
@@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: volume put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - }
/* update each channel */ for (i = 0; i < channels; i++) { @@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, }
/* notify DSP of mixer updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: volume put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME, + true); + return 0; }
@@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: switch get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the mixer data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH, - false);
/* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.integer.value[i] = cdata->chanv[i].value;
- pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: switch get failed to idle %d\n", - err); return 0; }
@@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: switch put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - }
/* update each channel */ for (i = 0; i < channels; i++) { @@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, }
/* notify DSP of mixer updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: switch put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH, + true); + return 0; }
@@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: enum get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the enum data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM, - false);
/* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
- pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: enum get failed to idle %d\n", - err); return 0; }
@@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: enum put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - }
/* update each channel */ for (i = 0; i < channels; i++) { @@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, }
/* notify DSP of enum updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: enum put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM, + true); + return 0; }
@@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size; - int ret, err; + int ret = 0;
if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(sdev->dev, @@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, return -EINVAL; }
- ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the binary data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, - scontrol->cmd, - false); - size = data->size + sizeof(*data); if (size > be->max) { dev_err_ratelimited(sdev->dev, @@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, memcpy(ucontrol->value.bytes.data, data, size);
out: - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes get failed to idle %d\n", - err); return ret; }
@@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size = data->size + sizeof(*data); - int ret, err;
if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(sdev->dev, @@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, return -EINVAL; }
- ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* copy from kcontrol */ memcpy(data, ucontrol->value.bytes.data, size);
/* notify DSP of byte control updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes put failed to idle %d\n", - err); - return ret; + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); + + return 0; }
int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, @@ -406,8 +252,6 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv header; const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data; - int ret; - int err;
/* * The beginning of bytes data contains a header from where @@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EINVAL; }
- ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes_ext put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* notify DSP of byte control updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes_ext put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true);
- return ret; + return 0; }
int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, @@ -492,17 +321,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; int data_size; - int err; - int ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes_ext get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } + int ret = 0;
/* * Decrement the limit by ext bytes header size to @@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION;
- /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, - scontrol->cmd, - false); - /* Prevent read of other kernel data or possibly corrupt response */ data_size = cdata->data->size + sizeof(const struct sof_abi_hdr);
@@ -543,11 +355,5 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, ret = -EFAULT;
out: - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes_ext get failed to idle %d\n", - err); return ret; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 8e00f829bfdb..aaf459af89d0 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3016,6 +3016,49 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, return ret; }
+/* Function to set the initial value of SOF kcontrols. + * The value will be stored in scontrol->control_data + */ +static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev) +{ + struct snd_sof_control *scontrol = NULL; + int ipc_cmd, ctrl_type; + int ret = 0; + + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + + /* notify DSP of kcontrol values */ + switch (scontrol->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + ipc_cmd = SOF_IPC_COMP_GET_VALUE; + ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET; + break; + case SOF_CTRL_CMD_BINARY: + ipc_cmd = SOF_IPC_COMP_GET_DATA; + ctrl_type = SOF_CTRL_TYPE_DATA_GET; + break; + default: + dev_err(sdev->dev, + "error: Invalid scontrol->cmd: %d\n", + scontrol->cmd); + return -EINVAL; + } + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + false); + if (ret < 0) { + dev_warn(sdev->dev, + "error: kcontrol value get for widget: %d\n", + scontrol->comp_id); + } + } + + return ret; +} + int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { @@ -3059,6 +3102,11 @@ static void sof_complete(struct snd_soc_component *scomp) break; } } + /* + * cache initial values of SOF kcontrols by reading DSP value over + * IPC. It may be overwritten by alsa-mixer after booting up + */ + snd_sof_cache_kcontrol_val(sdev); }
/* manifest - optional to inform component of manifest */
participants (2)
-
Mark Brown
-
Pierre-Louis Bossart