Commit 0c888bab authored by Bard Liao's avatar Bard Liao Committed by Mark Brown

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: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 7df43911
...@@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, ...@@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *sm = struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private; struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels; 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 */ /* read back each channel */
for (i = 0; i < channels; i++) for (i = 0; i < channels; i++)
...@@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, ...@@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
ipc_to_mixer(cdata->chanv[i].value, ipc_to_mixer(cdata->chanv[i].value,
scontrol->volume_table, sm->max + 1); 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; return 0;
} }
...@@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, ...@@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev; struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels; 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 */ /* update each channel */
for (i = 0; i < channels; i++) { for (i = 0; i < channels; i++) {
...@@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, ...@@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
} }
/* notify DSP of mixer updates */ /* notify DSP of mixer updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_VALUE, SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET, SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_VOLUME, SOF_CTRL_CMD_VOLUME,
true); 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);
return 0; return 0;
} }
...@@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, ...@@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *sm = struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private; struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels; 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 */ /* read back each channel */
for (i = 0; i < channels; i++) for (i = 0; i < channels; i++)
ucontrol->value.integer.value[i] = cdata->chanv[i].value; 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; return 0;
} }
...@@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, ...@@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev; struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels; 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 */ /* update each channel */
for (i = 0; i < channels; i++) { for (i = 0; i < channels; i++) {
...@@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, ...@@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
} }
/* notify DSP of mixer updates */ /* notify DSP of mixer updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_VALUE, SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET, SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_SWITCH, SOF_CTRL_CMD_SWITCH,
true); 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);
return 0; return 0;
} }
...@@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, ...@@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
struct soc_enum *se = struct soc_enum *se =
(struct soc_enum *)kcontrol->private_value; (struct soc_enum *)kcontrol->private_value;
struct snd_sof_control *scontrol = se->dobj.private; struct snd_sof_control *scontrol = se->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels; 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 */ /* read back each channel */
for (i = 0; i < channels; i++) for (i = 0; i < channels; i++)
ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; 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; return 0;
} }
...@@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, ...@@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev; struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels; 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 */ /* update each channel */
for (i = 0; i < channels; i++) { for (i = 0; i < channels; i++) {
...@@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, ...@@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
} }
/* notify DSP of enum updates */ /* notify DSP of enum updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_VALUE, SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET, SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_ENUM, SOF_CTRL_CMD_ENUM,
true); 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);
return 0; return 0;
} }
...@@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, ...@@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data; struct sof_abi_hdr *data = cdata->data;
size_t size; size_t size;
int ret, err; int ret = 0;
if (be->max > sizeof(ucontrol->value.bytes.data)) { if (be->max > sizeof(ucontrol->value.bytes.data)) {
dev_err_ratelimited(sdev->dev, dev_err_ratelimited(sdev->dev,
...@@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, ...@@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
return -EINVAL; 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); size = data->size + sizeof(*data);
if (size > be->max) { if (size > be->max) {
dev_err_ratelimited(sdev->dev, dev_err_ratelimited(sdev->dev,
...@@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, ...@@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
memcpy(ucontrol->value.bytes.data, data, size); memcpy(ucontrol->value.bytes.data, data, size);
out: 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; return ret;
} }
...@@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, ...@@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data; struct sof_abi_hdr *data = cdata->data;
size_t size = data->size + sizeof(*data); size_t size = data->size + sizeof(*data);
int ret, err;
if (be->max > sizeof(ucontrol->value.bytes.data)) { if (be->max > sizeof(ucontrol->value.bytes.data)) {
dev_err_ratelimited(sdev->dev, dev_err_ratelimited(sdev->dev,
...@@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, ...@@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
return -EINVAL; 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 */ /* copy from kcontrol */
memcpy(data, ucontrol->value.bytes.data, size); memcpy(data, ucontrol->value.bytes.data, size);
/* notify DSP of byte control updates */ /* notify DSP of byte control updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_DATA, SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET, SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd, scontrol->cmd,
true); true);
pm_runtime_mark_last_busy(sdev->dev); return 0;
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;
} }
int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
...@@ -406,8 +252,6 @@ 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; struct snd_ctl_tlv header;
const struct snd_ctl_tlv __user *tlvd = const struct snd_ctl_tlv __user *tlvd =
(const struct snd_ctl_tlv __user *)binary_data; (const struct snd_ctl_tlv __user *)binary_data;
int ret;
int err;
/* /*
* The beginning of bytes data contains a header from where * The beginning of bytes data contains a header from where
...@@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, ...@@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
return -EINVAL; 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 */ /* notify DSP of byte control updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_DATA, SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET, SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd, scontrol->cmd,
true); true);
pm_runtime_mark_last_busy(sdev->dev); return 0;
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);
return ret;
} }
int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
...@@ -492,17 +321,7 @@ 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 *tlvd =
(struct snd_ctl_tlv __user *)binary_data; (struct snd_ctl_tlv __user *)binary_data;
int data_size; int data_size;
int err; int ret = 0;
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;
}
/* /*
* Decrement the limit by ext bytes header size to * Decrement the limit by ext bytes header size to
...@@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, ...@@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
cdata->data->magic = SOF_ABI_MAGIC; cdata->data->magic = SOF_ABI_MAGIC;
cdata->data->abi = SOF_ABI_VERSION; 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 */ /* Prevent read of other kernel data or possibly corrupt response */
data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); 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, ...@@ -543,11 +355,5 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
ret = -EFAULT; ret = -EFAULT;
out: 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; return ret;
} }
...@@ -3016,6 +3016,49 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, ...@@ -3016,6 +3016,49 @@ static int sof_route_load(struct snd_soc_component *scomp, int index,
return ret; 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, int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget) struct snd_sof_widget *swidget)
{ {
...@@ -3059,6 +3102,11 @@ static void sof_complete(struct snd_soc_component *scomp) ...@@ -3059,6 +3102,11 @@ static void sof_complete(struct snd_soc_component *scomp)
break; 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 */ /* manifest - optional to inform component of manifest */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment