summaryrefslogtreecommitdiff
path: root/sound/soc/sof/topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/topology.c')
-rw-r--r--sound/soc/sof/topology.c156
1 files changed, 92 insertions, 64 deletions
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index c88afa872a58..432ae343f960 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -394,6 +394,8 @@ static const struct sof_process_types sof_process[] = {
{"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT},
{"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB},
{"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR},
+ {"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX},
+ {"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX},
};
static enum sof_ipc_process_type find_process(const char *name)
@@ -442,14 +444,15 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
return -EINVAL;
/* init the volume get/put data */
- scontrol->size = sizeof(struct sof_ipc_ctrl_data) +
- sizeof(struct sof_ipc_ctrl_value_chan) *
- le32_to_cpu(mc->num_channels);
+ scontrol->size = struct_size(scontrol->control_data, chanv,
+ le32_to_cpu(mc->num_channels));
scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL);
if (!scontrol->control_data)
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 */
@@ -501,9 +504,8 @@ static int sof_control_load_enum(struct snd_soc_component *scomp,
return -EINVAL;
/* init the enum get/put data */
- scontrol->size = sizeof(struct sof_ipc_ctrl_data) +
- sizeof(struct sof_ipc_ctrl_value_chan) *
- le32_to_cpu(ec->num_channels);
+ scontrol->size = struct_size(scontrol->control_data, chanv,
+ le32_to_cpu(ec->num_channels));
scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL);
if (!scontrol->control_data)
return -ENOMEM;
@@ -777,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},
+
};
/*
@@ -1550,6 +1556,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);
@@ -1592,6 +1601,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)
@@ -2340,6 +2360,9 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size,
if (!dai->dai_config)
return -ENOMEM;
+ /* set cpu_dai_name */
+ dai->cpu_dai_name = link->cpus->dai_name;
+
found = 1;
}
}
@@ -2568,9 +2591,7 @@ err:
*/
static int sof_link_hda_process(struct snd_sof_dev *sdev,
struct snd_soc_dai_link *link,
- struct sof_ipc_dai_config *config,
- int tx_slot,
- int rx_slot)
+ struct sof_ipc_dai_config *config)
{
struct sof_ipc_reply reply;
u32 size = sizeof(*config);
@@ -2583,27 +2604,18 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev,
continue;
if (strcmp(link->name, sof_dai->name) == 0) {
- if (sof_dai->comp_dai.direction ==
- SNDRV_PCM_STREAM_PLAYBACK) {
- if (!link->dpcm_playback)
- return -EINVAL;
-
- config->hda.link_dma_ch = tx_slot;
- } else {
- if (!link->dpcm_capture)
- return -EINVAL;
-
- config->hda.link_dma_ch = rx_slot;
- }
-
config->dai_index = sof_dai->comp_dai.dai_index;
found = 1;
+ config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
/* save config in dai component */
sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL);
if (!sof_dai->dai_config)
return -ENOMEM;
+ sof_dai->cpu_dai_name = link->cpus->dai_name;
+
/* send message to DSP */
ret = sof_ipc_tx_message(sdev->ipc,
config->hdr.cmd, config, size,
@@ -2639,18 +2651,12 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
struct sof_ipc_dai_config *config)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
- struct snd_soc_dai_link_component dai_component;
struct snd_soc_tplg_private *private = &cfg->priv;
struct snd_soc_dai *dai;
u32 size = sizeof(*config);
- u32 tx_num = 0;
- u32 tx_slot = 0;
- u32 rx_num = 0;
- u32 rx_slot = 0;
int ret;
/* init IPC */
- memset(&dai_component, 0, sizeof(dai_component));
memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params));
config->hdr.size = size;
@@ -2664,30 +2670,14 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index,
return ret;
}
- dai_component.dai_name = link->cpu_dai_name;
- dai = snd_soc_find_dai(&dai_component);
+ dai = snd_soc_find_dai(link->cpus);
if (!dai) {
dev_err(sdev->dev, "error: failed to find dai %s in %s",
- dai_component.dai_name, __func__);
+ link->cpus->dai_name, __func__);
return -EINVAL;
}
- if (link->dpcm_playback)
- tx_num = 1;
-
- if (link->dpcm_capture)
- rx_num = 1;
-
- ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot,
- &rx_num, &rx_slot);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to get dma channel for HDA%d\n",
- config->dai_index);
-
- return ret;
- }
-
- ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot);
+ ret = sof_link_hda_process(sdev, link, config);
if (ret < 0)
dev_err(sdev->dev, "error: failed to process hda dai link %s",
link->name);
@@ -2708,7 +2698,11 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
int ret;
int i = 0;
- link->platform_name = dev_name(sdev->dev);
+ if (!link->platforms) {
+ dev_err(sdev->dev, "error: no platforms\n");
+ return -EINVAL;
+ }
+ link->platforms->name = dev_name(sdev->dev);
/*
* Set nonatomic property for FE dai links as their trigger action
@@ -2801,30 +2795,16 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
static int sof_link_hda_unload(struct snd_sof_dev *sdev,
struct snd_soc_dai_link *link)
{
- struct snd_soc_dai_link_component dai_component;
struct snd_soc_dai *dai;
int ret = 0;
- memset(&dai_component, 0, sizeof(dai_component));
- dai_component.dai_name = link->cpu_dai_name;
- dai = snd_soc_find_dai(&dai_component);
+ dai = snd_soc_find_dai(link->cpus);
if (!dai) {
dev_err(sdev->dev, "error: failed to find dai %s in %s",
- dai_component.dai_name, __func__);
+ link->cpus->dai_name, __func__);
return -EINVAL;
}
- /*
- * FIXME: this call to hw_free is mainly to release the link DMA ID.
- * This is abusing the API and handling SOC internals is not
- * recommended. This part will be reworked.
- */
- if (dai->driver->ops->hw_free)
- ret = dai->driver->ops->hw_free(NULL, dai);
- if (ret < 0)
- dev_err(sdev->dev, "error: failed to free hda resource for %s\n",
- link->name);
-
return ret;
}
@@ -2998,6 +2978,49 @@ err:
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)
{
@@ -3041,6 +3064,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 */