diff options
Diffstat (limited to 'sound/soc/intel/avs')
-rw-r--r-- | sound/soc/intel/avs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/intel/avs/boards/nau8825.c | 5 | ||||
-rw-r--r-- | sound/soc/intel/avs/boards/rt286.c | 2 | ||||
-rw-r--r-- | sound/soc/intel/avs/boards/rt298.c | 2 | ||||
-rw-r--r-- | sound/soc/intel/avs/control.c | 105 | ||||
-rw-r--r-- | sound/soc/intel/avs/control.h | 23 | ||||
-rw-r--r-- | sound/soc/intel/avs/messages.c | 29 | ||||
-rw-r--r-- | sound/soc/intel/avs/messages.h | 33 | ||||
-rw-r--r-- | sound/soc/intel/avs/path.c | 62 | ||||
-rw-r--r-- | sound/soc/intel/avs/pcm.c | 47 | ||||
-rw-r--r-- | sound/soc/intel/avs/probes.c | 25 | ||||
-rw-r--r-- | sound/soc/intel/avs/topology.c | 76 | ||||
-rw-r--r-- | sound/soc/intel/avs/topology.h | 3 | ||||
-rw-r--r-- | sound/soc/intel/avs/trace.c | 2 |
14 files changed, 363 insertions, 53 deletions
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index 1c6924a1ebca..460ee6599daf 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \ - topology.o path.o pcm.o board_selection.o + topology.o path.o pcm.o board_selection.o control.o snd-soc-avs-objs += cldma.o snd-soc-avs-objs += skl.o apl.o diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index 6731d8a49076..b31fa931ba8b 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -258,14 +258,15 @@ static int avs_card_resume_post(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); + int stream = SNDRV_PCM_STREAM_PLAYBACK; if (!codec_dai) { dev_err(card->dev, "Codec dai not found\n"); return -EINVAL; } - if (codec_dai->stream_active[SNDRV_PCM_STREAM_PLAYBACK] && - codec_dai->playback_widget->active) + if (snd_soc_dai_stream_active(codec_dai, stream) && + snd_soc_dai_get_widget(codec_dai, stream)->active) snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, 0, SND_SOC_CLOCK_IN); return snd_soc_component_set_jack(codec_dai->component, jack, NULL); diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 8447b37a2a41..3551a05bd599 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -98,7 +98,7 @@ static int avs_rt286_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pc static int avs_rt286_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *runtime = substream->private_data; + struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0); int ret; diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index bd25f0fde35e..2923f3805bbe 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -109,7 +109,7 @@ static int avs_rt298_be_fixup(struct snd_soc_pcm_runtime *runtime, struct snd_pc static int avs_rt298_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); unsigned int clk_freq; int ret; diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c new file mode 100644 index 000000000000..a8b14b784f8a --- /dev/null +++ b/sound/soc/intel/avs/control.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// +// Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <sound/soc.h> +#include "avs.h" +#include "control.h" +#include "messages.h" +#include "path.h" + +static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol) +{ + struct snd_soc_dapm_widget *w; + + w = snd_soc_dapm_kcontrol_widget(kcontrol); + + return to_avs_dev(w->dapm->component->dev); +} + +static struct avs_path_module *avs_get_kcontrol_module(struct avs_dev *adev, u32 id) +{ + struct avs_path *path; + struct avs_path_pipeline *ppl; + struct avs_path_module *mod; + + list_for_each_entry(path, &adev->path_list, node) + list_for_each_entry(ppl, &path->ppl_list, node) + list_for_each_entry(mod, &ppl->mod_list, node) + if (mod->template->ctl_id && mod->template->ctl_id == id) + return mod; + + return NULL; +} + +int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; + struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); + struct avs_volume_cfg *dspvols = NULL; + struct avs_path_module *active_module; + size_t num_dspvols; + int ret = 0; + + /* prevent access to modules while path is being constructed */ + mutex_lock(&adev->path_mutex); + + active_module = avs_get_kcontrol_module(adev, ctl_data->id); + if (active_module) { + ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id, + active_module->instance_id, &dspvols, + &num_dspvols); + if (!ret) + ucontrol->value.integer.value[0] = dspvols[0].target_volume; + + ret = AVS_IPC_RET(ret); + kfree(dspvols); + } else { + ucontrol->value.integer.value[0] = ctl_data->volume; + } + + mutex_unlock(&adev->path_mutex); + return ret; +} + +int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; + struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); + long *volume = &ctl_data->volume; + struct avs_path_module *active_module; + struct avs_volume_cfg dspvol = {0}; + long ctlvol = ucontrol->value.integer.value[0]; + int ret = 0, changed = 0; + + if (ctlvol < 0 || ctlvol > mc->max) + return -EINVAL; + + /* prevent access to modules while path is being constructed */ + mutex_lock(&adev->path_mutex); + + if (*volume != ctlvol) { + *volume = ctlvol; + changed = 1; + } + + active_module = avs_get_kcontrol_module(adev, ctl_data->id); + if (active_module) { + dspvol.channel_id = AVS_ALL_CHANNELS_MASK; + dspvol.target_volume = *volume; + + ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id, + active_module->instance_id, &dspvol); + ret = AVS_IPC_RET(ret); + } + + mutex_unlock(&adev->path_mutex); + + return ret ? ret : changed; +} diff --git a/sound/soc/intel/avs/control.h b/sound/soc/intel/avs/control.h new file mode 100644 index 000000000000..08631bde13c3 --- /dev/null +++ b/sound/soc/intel/avs/control.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * + * Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + * Cezary Rojewski <cezary.rojewski@intel.com> + */ + +#ifndef __SOUND_SOC_INTEL_AVS_CTRL_H +#define __SOUND_SOC_INTEL_AVS_CTRL_H + +#include <sound/control.h> + +struct avs_control_data { + u32 id; + + long volume; +}; + +int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + +#endif diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c index e11ae4246416..f887ab5b0311 100644 --- a/sound/soc/intel/avs/messages.c +++ b/sound/soc/intel/avs/messages.c @@ -702,6 +702,35 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, (u8 *)&cpr_fmt, sizeof(cpr_fmt)); } +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol) +{ + return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, (u8 *)vol, + sizeof(*vol)); +} + +int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg **vols, size_t *num_vols) +{ + size_t payload_size; + u8 *payload; + int ret; + + ret = avs_ipc_get_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, NULL, 0, + &payload, &payload_size); + if (ret) + return ret; + + /* Non-zero payload expected for PEAKVOL_VOLUME. */ + if (!payload_size) + return -EREMOTEIO; + + *vols = (struct avs_volume_cfg *)payload; + *num_vols = payload_size / sizeof(**vols); + + return 0; +} + #ifdef CONFIG_DEBUG_FS int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size) { diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 9dd835527e02..d3b60ae7d743 100644 --- a/sound/soc/intel/avs/messages.h +++ b/sound/soc/intel/avs/messages.h @@ -561,6 +561,12 @@ int avs_ipc_set_system_time(struct avs_dev *adev); #define AVS_COPIER_MOD_UUID \ GUID_INIT(0x9BA00C83, 0xCA12, 0x4A83, 0x94, 0x3C, 0x1F, 0xA2, 0xE8, 0x2F, 0x9D, 0xDA) +#define AVS_PEAKVOL_MOD_UUID \ + GUID_INIT(0x8A171323, 0x94A3, 0x4E1D, 0xAF, 0xE9, 0xFE, 0x5D, 0xBA, 0xa4, 0xC3, 0x93) + +#define AVS_GAIN_MOD_UUID \ + GUID_INIT(0x61BCA9A8, 0x18D0, 0x4A18, 0x8E, 0x7B, 0x26, 0x39, 0x21, 0x98, 0x04, 0xB7) + #define AVS_KPBUFF_MOD_UUID \ GUID_INIT(0xA8A0CB32, 0x4A77, 0x4DB1, 0x85, 0xC7, 0x53, 0xD7, 0xEE, 0x07, 0xBC, 0xE6) @@ -729,6 +735,19 @@ struct avs_copier_cfg { struct avs_copier_gtw_cfg gtw_cfg; } __packed; +struct avs_volume_cfg { + u32 channel_id; + u32 target_volume; + u32 curve_type; + u32 reserved; /* alignment */ + u64 curve_duration; +} __packed; + +struct avs_peakvol_cfg { + struct avs_modcfg_base base; + struct avs_volume_cfg vols[]; +} __packed; + struct avs_micsel_cfg { struct avs_modcfg_base base; struct avs_audio_format out_fmt; @@ -802,6 +821,20 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, const struct avs_audio_format *src_fmt, const struct avs_audio_format *sink_fmt); +enum avs_peakvol_runtime_param { + AVS_PEAKVOL_VOLUME = 0, +}; + +enum avs_audio_curve_type { + AVS_AUDIO_CURVE_NONE = 0, + AVS_AUDIO_CURVE_WINDOWS_FADE = 1, +}; + +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol); +int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg **vols, size_t *num_vols); + #define AVS_PROBE_INST_ID 0 enum avs_probe_runtime_param { diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index ce157a8d6552..05302ab705ae 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -10,6 +10,7 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include "avs.h" +#include "control.h" #include "path.h" #include "topology.h" @@ -264,6 +265,65 @@ static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) return ret; } +static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_tplg_path_template *path_tmpl; + struct snd_soc_dapm_widget *w; + int i; + + path_tmpl = t->owner->owner->owner; + w = path_tmpl->w; + + for (i = 0; i < w->num_kcontrols; i++) { + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + + mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value; + ctl_data = (struct avs_control_data *)mc->dobj.private; + if (ctl_data->id == t->ctl_id) + return ctl_data; + } + + return NULL; +} + +static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_control_data *ctl_data; + struct avs_peakvol_cfg *cfg; + int volume = S32_MAX; + size_t size; + int ret; + + ctl_data = avs_get_module_control(mod); + if (ctl_data) + volume = ctl_data->volume; + + /* As 2+ channels controls are unsupported, have a single block for all channels. */ + size = struct_size(cfg, vols, 1); + cfg = kzalloc(size, GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + cfg->base.cpc = t->cfg_base->cpc; + cfg->base.ibs = t->cfg_base->ibs; + cfg->base.obs = t->cfg_base->obs; + cfg->base.is_pages = t->cfg_base->is_pages; + cfg->base.audio_fmt = *t->in_fmt; + cfg->vols[0].target_volume = volume; + cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK; + cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE; + cfg->vols[0].curve_duration = 0; + + ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, + t->domain, cfg, size, &mod->instance_id); + + kfree(cfg); + return ret; +} + static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod) { struct avs_tplg_module *t = mod->template; @@ -465,6 +525,8 @@ static struct avs_module_create avs_module_create[] = { { &AVS_MIXOUT_MOD_UUID, avs_modbase_create }, { &AVS_KPBUFF_MOD_UUID, avs_modbase_create }, { &AVS_COPIER_MOD_UUID, avs_copier_create }, + { &AVS_PEAKVOL_MOD_UUID, avs_peakvol_create }, + { &AVS_GAIN_MOD_UUID, avs_peakvol_create }, { &AVS_MICSEL_MOD_UUID, avs_micsel_create }, { &AVS_MUX_MOD_UUID, avs_mux_create }, { &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create }, diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index f930c5e86a84..31c032a0f7e4 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -35,15 +35,13 @@ struct avs_dma_data { static struct avs_tplg_path_template * avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction) { - struct snd_soc_dapm_widget *dw; + struct snd_soc_dapm_widget *dw = snd_soc_dai_get_widget(dai, direction); struct snd_soc_dapm_path *dp; enum snd_soc_dapm_direction dir; if (direction == SNDRV_PCM_STREAM_CAPTURE) { - dw = dai->capture_widget; dir = is_fe ? SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN; } else { - dw = dai->playback_widget; dir = is_fe ? SND_SOC_DAPM_DIR_IN : SND_SOC_DAPM_DIR_OUT; } @@ -60,7 +58,7 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction) static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe, const struct snd_soc_dai_ops *ops) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct avs_dev *adev = to_avs_dev(dai->dev); struct avs_tplg_path_template *template; struct avs_dma_data *data; @@ -169,7 +167,7 @@ static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct avs_dev *adev = to_avs_dev(dai->dev); struct avs_dma_data *data; @@ -218,7 +216,7 @@ static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct avs_dma_data *data; int ret = 0; @@ -305,7 +303,7 @@ static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct avs_dma_data *data; - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; struct hdac_ext_link *link; struct hda_codec *codec; @@ -335,7 +333,7 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct hdac_ext_stream *link_stream = runtime->private_data; struct hdac_ext_link *link; @@ -374,7 +372,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; struct avs_dma_data *data; int ret = 0; @@ -489,7 +487,7 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct avs_dev *adev = to_avs_dev(dai->dev); struct avs_dma_data *data; @@ -628,7 +626,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct avs_dma_data *data; struct hdac_ext_stream *host_stream; struct hdac_bus *bus; @@ -647,7 +645,7 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: spin_lock_irqsave(&bus->reg_lock, flags); - snd_hdac_stream_start(hdac_stream(host_stream), true); + snd_hdac_stream_start(hdac_stream(host_stream)); spin_unlock_irqrestore(&bus->reg_lock, flags); /* Timeout on DRSM poll shall not stop the resume so ignore the result. */ @@ -836,7 +834,7 @@ static int avs_dai_resume_hw_params(struct snd_soc_dai *dai, struct avs_dma_data int ret; substream = data->substream; - rtd = snd_pcm_substream_chip(substream); + rtd = asoc_substream_to_rtd(substream); ret = dai->driver->ops->hw_params(substream, &rtd->dpcm[substream->stream].hw_params, dai); if (ret) @@ -929,9 +927,9 @@ static int avs_component_pm_op(struct snd_soc_component *component, bool be, int ret; for_each_component_dais(component, dai) { - data = dai->playback_dma_data; + data = snd_soc_dai_dma_data_get_playback(dai); if (data) { - rtd = snd_pcm_substream_chip(data->substream); + rtd = asoc_substream_to_rtd(data->substream); if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) { ret = op(dai, data); if (ret < 0) { @@ -942,9 +940,9 @@ static int avs_component_pm_op(struct snd_soc_component *component, bool be, } } - data = dai->capture_dma_data; + data = snd_soc_dai_dma_data_get_capture(dai); if (data) { - rtd = snd_pcm_substream_chip(data->substream); + rtd = asoc_substream_to_rtd(data->substream); if (rtd->dai_link->no_pcm == be && !rtd->dai_link->ignore_suspend) { ret = op(dai, data); if (ret < 0) { @@ -1048,7 +1046,7 @@ static const struct snd_pcm_hardware avs_pcm_hardware = { static int avs_component_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); /* only FE DAI links are handled here */ if (rtd->dai_link->no_pcm) @@ -1066,7 +1064,7 @@ static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream) static snd_pcm_uframes_t avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct avs_dma_data *data; struct hdac_ext_stream *host_stream; unsigned int pos; @@ -1291,11 +1289,14 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen sprintf(name, "%s-cpu", dev_name(&codec->core.dev)); for_each_component_dais_safe(component, dai, save) { + int stream; + if (!strstr(dai->driver->name, name)) continue; - snd_soc_dapm_free_widget(dai->playback_widget); - snd_soc_dapm_free_widget(dai->capture_widget); + for_each_pcm_streams(stream) + snd_soc_dapm_free_widget(snd_soc_dai_get_widget(dai, stream)); + snd_soc_unregister_dai(dai); } } @@ -1394,7 +1395,7 @@ static void avs_component_hda_remove(struct snd_soc_component *component) static int avs_component_hda_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; struct hda_codec *codec; @@ -1441,7 +1442,7 @@ static int avs_component_hda_open(struct snd_soc_component *component, static int avs_component_hda_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; /* only BE DAI links are handled here */ diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 29d63f2a9616..70a94201d6a5 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -190,7 +190,7 @@ static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: spin_lock_irqsave(&bus->reg_lock, cookie); - snd_hdac_stream_start(hdac_stream(host_stream), true); + snd_hdac_stream_start(hdac_stream(host_stream)); spin_unlock_irqrestore(&bus->reg_lock, cookie); break; @@ -277,31 +277,8 @@ static struct snd_soc_dai_driver probe_cpu_dais[] = { }, }; -static int avs_probe_component_probe(struct snd_soc_component *component) -{ - struct avs_soc_component *acomp = to_avs_soc_component(component); - struct avs_dev *adev = to_avs_dev(component->dev); - - mutex_lock(&adev->comp_list_mutex); - list_add_tail(&acomp->node, &adev->comp_list); - mutex_unlock(&adev->comp_list_mutex); - return 0; -} - -static void avs_probe_component_remove(struct snd_soc_component *component) -{ - struct avs_soc_component *acomp = to_avs_soc_component(component); - struct avs_dev *adev = to_avs_dev(component->dev); - - mutex_lock(&adev->comp_list_mutex); - list_del(&acomp->node); - mutex_unlock(&adev->comp_list_mutex); -} - static const struct snd_soc_component_driver avs_probe_component_driver = { .name = "avs-probe-compr", - .probe = avs_probe_component_probe, - .remove = avs_probe_component_remove, .compress_ops = &avs_probe_compress_ops, .module_get_upon_open = 1, /* increment refcount when a stream is opened */ }; diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index e845eaf0a1e7..cdb4ec500261 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -13,6 +13,7 @@ #include <sound/soc-topology.h> #include <uapi/sound/intel/avs/tokens.h> #include "avs.h" +#include "control.h" #include "topology.h" /* Get pointer to vendor array at the specified offset. */ @@ -1070,6 +1071,12 @@ static const struct avs_tplg_token_parser module_parsers[] = { .offset = offsetof(struct avs_tplg_module, cfg_ext), .parse = avs_parse_modcfg_ext_ptr, }, + { + .token = AVS_TKN_MOD_KCONTROL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_module, ctl_id), + .parse = avs_parse_byte_token, + }, }; static struct avs_tplg_module * @@ -1435,6 +1442,16 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, return 0; } +static int avs_widget_ready(struct snd_soc_component *comp, int index, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *dw) +{ + struct avs_tplg_path_template *template = w->priv; + + template->w = w; + return 0; +} + static int avs_dai_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) @@ -1586,9 +1603,68 @@ static int avs_manifest(struct snd_soc_component *comp, int index, return avs_tplg_parse_bindings(comp, tuples, remaining); } +#define AVS_CONTROL_OPS_VOLUME 257 + +static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = { + { + .id = AVS_CONTROL_OPS_VOLUME, + .get = avs_control_volume_get, + .put = avs_control_volume_put, + }, +}; + +static const struct avs_tplg_token_parser control_parsers[] = { + { + .token = AVS_TKN_KCONTROL_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_control_data, id), + .parse = avs_parse_word_token, + }, +}; + +static int +avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_new *ctmpl, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_soc_tplg_vendor_array *tuples; + struct snd_soc_tplg_mixer_control *tmc; + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + size_t block_size; + int ret; + + switch (le32_to_cpu(hdr->type)) { + case SND_SOC_TPLG_TYPE_MIXER: + tmc = container_of(hdr, typeof(*tmc), hdr); + tuples = tmc->priv.array; + block_size = le32_to_cpu(tmc->priv.size); + break; + default: + return -EINVAL; + } + + ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL); + if (!ctl_data) + return -ENOMEM; + + ret = parse_dictionary_entries(comp, tuples, block_size, ctl_data, 1, sizeof(*ctl_data), + AVS_TKN_KCONTROL_ID_U32, control_parsers, + ARRAY_SIZE(control_parsers)); + if (ret) + return ret; + + mc = (struct soc_mixer_control *)ctmpl->private_value; + mc->dobj.private = ctl_data; + return 0; +} + static struct snd_soc_tplg_ops avs_tplg_ops = { + .io_ops = avs_control_ops, + .io_ops_count = ARRAY_SIZE(avs_control_ops), + .control_load = avs_control_load, .dapm_route_load = avs_route_load, .widget_load = avs_widget_load, + .widget_ready = avs_widget_ready, .dai_load = avs_dai_load, .link_load = avs_link_load, .manifest = avs_manifest, diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 68e5f6312353..6e1c8e9b2496 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -138,6 +138,8 @@ struct avs_tplg_path_template_id { struct avs_tplg_path_template { u32 id; + struct snd_soc_dapm_widget *w; + struct list_head path_list; struct avs_tplg *owner; @@ -180,6 +182,7 @@ struct avs_tplg_module { u8 core_id; u8 domain; struct avs_tplg_modcfg_ext *cfg_ext; + u32 ctl_id; struct avs_tplg_pipeline *owner; /* Pipeline modules management. */ diff --git a/sound/soc/intel/avs/trace.c b/sound/soc/intel/avs/trace.c index fcb7cfc823d6..c63eea909b5e 100644 --- a/sound/soc/intel/avs/trace.c +++ b/sound/soc/intel/avs/trace.c @@ -24,7 +24,7 @@ void trace_avs_msg_payload(const void *data, size_t size) while (remaining > 0) { u32 chunk; - chunk = min(remaining, (size_t)MAX_CHUNK_SIZE); + chunk = min_t(size_t, remaining, MAX_CHUNK_SIZE); trace_avs_ipc_msg_payload(data, chunk, offset, size); remaining -= chunk; |