Skip to content

Commit a6f05dc

Browse files
author
Jyri Sarha
committed
ASoC: sof: ipc4-control: Global mixers and capture hw mute indicator
Implement global kcontrol concept and add capture hw mute indicator implementation in it. Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
1 parent 137ee12 commit a6f05dc

5 files changed

Lines changed: 150 additions & 3 deletions

File tree

sound/soc/sof/ipc4-control.c

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,130 @@ sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
649649
return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false);
650650
}
651651

652+
struct sof_ipc4_kcontrol_global_priv {
653+
struct snd_card *snd_card;
654+
struct snd_kcontrol *capture_hw_mute;
655+
};
656+
657+
static int sof_ipc4_capture_hw_mute_get(struct snd_kcontrol *kcontrol,
658+
struct snd_ctl_elem_value *ucontrol)
659+
{
660+
ucontrol->value.integer.value[0] = kcontrol->private_value;
661+
return 0;
662+
}
663+
664+
static const struct snd_kcontrol_new sof_ipc4_capture_hw_mute = {
665+
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
666+
.access = SNDRV_CTL_ELEM_ACCESS_READ,
667+
.name = "Global capture HW mute indicator",
668+
.info = snd_ctl_boolean_mono_info,
669+
.get = sof_ipc4_capture_hw_mute_get,
670+
};
671+
672+
static struct snd_card *sof_scomp_get_card(struct snd_soc_component *scomp)
673+
{
674+
struct device *dev = scomp->dev;
675+
676+
if (!scomp->card) {
677+
dev_err(dev, "%s: No snd_soc_card", __func__);
678+
return NULL;
679+
}
680+
681+
return scomp->card->snd_card;
682+
}
683+
684+
static int sof_ipc4_create_non_topology_controls(struct snd_sof_dev *sdev,
685+
struct snd_soc_component *scomp)
686+
{
687+
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
688+
struct snd_card *snd_card = sof_scomp_get_card(scomp);
689+
struct device *dev = sdev->dev;
690+
struct sof_ipc4_kcontrol_global_priv *priv;
691+
int ret;
692+
693+
if (!snd_card) {
694+
dev_err(dev, "%s: Card not found!", __func__);
695+
return -ENODEV;
696+
}
697+
698+
if (!ipc4_data->global_kcontrol_mask)
699+
return 0;
700+
701+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
702+
if (!priv)
703+
return -ENOMEM;
704+
705+
priv->snd_card = snd_card;
706+
707+
if (ipc4_data->global_kcontrol_mask &
708+
BIT(SOF_IPC4_KCONTROL_GLOBAL_CAPTURE_HW_MUTE)) {
709+
struct snd_kcontrol *kctl;
710+
711+
kctl = snd_ctl_new1(&sof_ipc4_capture_hw_mute, NULL);
712+
if (!kctl) {
713+
dev_err(dev, "%s: snd_ctl_new1(): failed", __func__);
714+
return -EINVAL;
715+
}
716+
717+
kctl->private_value = 0;
718+
719+
ret = snd_ctl_add(snd_card, kctl);
720+
if (ret < 0)
721+
dev_err(dev, "%s: snd_ctl_add(): failed", __func__);
722+
else
723+
priv->capture_hw_mute = kctl;
724+
}
725+
726+
ipc4_data->global_kcontrol_priv = priv;
727+
728+
return 0;
729+
}
730+
731+
static void snd_ipc4_global_capture_hw_mute_report(struct snd_sof_dev *sdev,
732+
bool status)
733+
{
734+
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
735+
struct sof_ipc4_kcontrol_global_priv *priv = ipc4_data->global_kcontrol_priv;
736+
struct device *dev = sdev->dev;
737+
struct snd_kcontrol *kctl;
738+
739+
if (!priv || !priv->capture_hw_mute)
740+
return;
741+
742+
kctl = priv->capture_hw_mute;
743+
744+
dev_dbg(dev, "%s: reporting %u, old %lu", __func__,
745+
status, kctl->private_value);
746+
747+
if (kctl->private_value == status)
748+
return;
749+
750+
kctl->private_value = status;
751+
snd_ctl_notify(priv->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
752+
}
753+
754+
static void snd_ipc4_handle_global_event(struct snd_sof_dev *sdev,
755+
struct sof_ipc4_control_msg_payload *msg_data)
756+
{
757+
struct device *dev = sdev->dev;
758+
759+
dev_dbg(dev, "%s: got msg id %u num_elems %u", __func__,
760+
msg_data->id, msg_data->num_elems);
761+
762+
switch (msg_data->id) {
763+
case SOF_IPC4_KCONTROL_GLOBAL_CAPTURE_HW_MUTE:
764+
if (msg_data->num_elems == 1 || msg_data->chanv[0].channel == 0)
765+
snd_ipc4_global_capture_hw_mute_report(sdev, msg_data->chanv[0].value);
766+
else
767+
dev_warn(dev, "%s: bad data for id %u chan 0 %u", __func__,
768+
msg_data->id, msg_data->chanv[0].channel);
769+
break;
770+
default:
771+
dev_warn(dev, "%s: unknown global control elem id %u", __func__,
772+
msg_data->id);
773+
}
774+
}
775+
652776
#define PARAM_ID_FROM_EXTENSION(_ext) (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) \
653777
>> SOF_IPC4_MOD_EXT_MSG_PARAM_ID_SHIFT)
654778

@@ -673,6 +797,7 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
673797
ndata->event_data_size);
674798
return;
675799
}
800+
msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data;
676801

677802
event_param_id = ndata->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK;
678803
switch (event_param_id) {
@@ -690,6 +815,14 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
690815
return;
691816
}
692817

818+
if (ndata->module_id == SOF_IPC4_MOD_INIT_BASEFW_MOD_ID &&
819+
ndata->instance_id == SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID) {
820+
dev_dbg(sdev->dev, "Received global notifier event_id %#x",
821+
event_param_id);
822+
snd_ipc4_handle_global_event(sdev, msg_data);
823+
return;
824+
}
825+
693826
/* Find the swidget based on ndata->module_id and ndata->instance_id */
694827
swidget = sof_ipc4_find_swidget_by_ids(sdev, ndata->module_id,
695828
ndata->instance_id);
@@ -700,7 +833,6 @@ static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
700833
}
701834

702835
/* Find the scontrol which is the source of the notification */
703-
msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data;
704836
list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
705837
if (scontrol->comp_id == swidget->comp_id) {
706838
u32 local_param_id;
@@ -855,4 +987,5 @@ const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
855987
.update = sof_ipc4_control_update,
856988
.widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
857989
.set_up_volume_table = sof_ipc4_set_up_volume_table,
990+
.create_non_topology_controls = sof_ipc4_create_non_topology_controls,
858991
};

sound/soc/sof/ipc4-loader.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,9 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
411411
case SOF_IPC4_FW_CONTEXT_SAVE:
412412
ipc4_data->fw_context_save = *tuple->value;
413413
break;
414+
case SOF_IPC4_FW_GLOBAL_KCONTROL_MASK:
415+
ipc4_data->global_kcontrol_mask = *tuple->value;
416+
break;
414417
default:
415418
break;
416419
}

sound/soc/sof/ipc4-priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ struct sof_ipc4_fw_data {
8686
int max_num_pipelines;
8787
u32 max_libs_count;
8888
bool fw_context_save;
89+
u32 global_kcontrol_mask;
90+
void *global_kcontrol_priv;
8991

9092
int (*load_library)(struct snd_sof_dev *sdev,
9193
struct sof_ipc4_fw_library *fw_lib, bool reload);

sound/soc/sof/sof-audio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ struct sof_ipc_tplg_control_ops {
166166
/* mandatory callback to set up volume table for volume kcontrols */
167167
int (*set_up_volume_table)(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS],
168168
int size);
169+
int (*create_non_topology_controls)(struct snd_sof_dev *sdev,
170+
struct snd_soc_component *scomp);
169171
};
170172

171173
/**

sound/soc/sof/topology.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,8 +2251,15 @@ static int sof_complete(struct snd_soc_component *scomp)
22512251
}
22522252

22532253
/* set up static pipelines */
2254-
if (tplg_ops && tplg_ops->set_up_all_pipelines)
2255-
return tplg_ops->set_up_all_pipelines(sdev, false);
2254+
if (tplg_ops && tplg_ops->set_up_all_pipelines) {
2255+
ret = tplg_ops->set_up_all_pipelines(sdev, false);
2256+
if (ret < 0)
2257+
return ret;
2258+
}
2259+
2260+
/* set up non topology mixers */
2261+
if (tplg_ops && tplg_ops->control && tplg_ops->control->create_non_topology_controls)
2262+
return tplg_ops->control->create_non_topology_controls(sdev, scomp);
22562263

22572264
return 0;
22582265
}

0 commit comments

Comments
 (0)