1 // SPDX-License-Identifier: GPL-2.0
2 /* Helper functions for Dell Mic Mute LED control;
3 * to be included from codec driver
6 #if IS_ENABLED(CONFIG_DELL_LAPTOP)
7 #include <linux/dell-led.h>
12 MICMUTE_LED_FOLLOW_CAPTURE
,
13 MICMUTE_LED_FOLLOW_MUTE
,
16 static int dell_led_mode
= MICMUTE_LED_FOLLOW_MUTE
;
17 static int dell_capture
;
18 static int dell_led_value
;
19 static int (*dell_micmute_led_set_func
)(int);
20 static void (*dell_old_cap_hook
)(struct hda_codec
*,
21 struct snd_kcontrol
*,
22 struct snd_ctl_elem_value
*);
24 static void call_micmute_led_update(void)
28 switch (dell_led_mode
) {
35 case MICMUTE_LED_FOLLOW_CAPTURE
:
38 case MICMUTE_LED_FOLLOW_MUTE
:
44 if (val
== dell_led_value
)
47 dell_micmute_led_set_func(dell_led_value
);
50 static void update_dell_wmi_micmute_led(struct hda_codec
*codec
,
51 struct snd_kcontrol
*kcontrol
,
52 struct snd_ctl_elem_value
*ucontrol
)
54 if (dell_old_cap_hook
)
55 dell_old_cap_hook(codec
, kcontrol
, ucontrol
);
57 if (!ucontrol
|| !dell_micmute_led_set_func
)
59 if (strcmp("Capture Switch", ucontrol
->id
.name
) == 0 && ucontrol
->id
.index
== 0) {
60 /* TODO: How do I verify if it's a mono or stereo here? */
61 dell_capture
= (ucontrol
->value
.integer
.value
[0] ||
62 ucontrol
->value
.integer
.value
[1]);
63 call_micmute_led_update();
67 static int dell_mic_mute_led_mode_info(struct snd_kcontrol
*kcontrol
,
68 struct snd_ctl_elem_info
*uinfo
)
70 static const char * const texts
[] = {
71 "On", "Off", "Follow Capture", "Follow Mute",
74 return snd_ctl_enum_info(uinfo
, 1, ARRAY_SIZE(texts
), texts
);
77 static int dell_mic_mute_led_mode_get(struct snd_kcontrol
*kcontrol
,
78 struct snd_ctl_elem_value
*ucontrol
)
80 ucontrol
->value
.enumerated
.item
[0] = dell_led_mode
;
84 static int dell_mic_mute_led_mode_put(struct snd_kcontrol
*kcontrol
,
85 struct snd_ctl_elem_value
*ucontrol
)
89 mode
= ucontrol
->value
.enumerated
.item
[0];
90 if (mode
> MICMUTE_LED_FOLLOW_MUTE
)
91 mode
= MICMUTE_LED_FOLLOW_MUTE
;
92 if (mode
== dell_led_mode
)
95 call_micmute_led_update();
99 static const struct snd_kcontrol_new dell_mic_mute_mode_ctls
[] = {
101 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
102 .name
= "Mic Mute-LED Mode",
103 .info
= dell_mic_mute_led_mode_info
,
104 .get
= dell_mic_mute_led_mode_get
,
105 .put
= dell_mic_mute_led_mode_put
,
110 static void alc_fixup_dell_wmi(struct hda_codec
*codec
,
111 const struct hda_fixup
*fix
, int action
)
113 struct alc_spec
*spec
= codec
->spec
;
114 bool removefunc
= false;
116 if (action
== HDA_FIXUP_ACT_PROBE
) {
117 if (!dell_micmute_led_set_func
)
118 dell_micmute_led_set_func
= symbol_request(dell_micmute_led_set
);
119 if (!dell_micmute_led_set_func
) {
120 codec_warn(codec
, "Failed to find dell wmi symbol dell_micmute_led_set\n");
125 if (dell_micmute_led_set_func(false) >= 0) {
127 if (spec
->gen
.num_adc_nids
> 1 && !spec
->gen
.dyn_adc_switch
)
128 codec_dbg(codec
, "Skipping micmute LED control due to several ADCs");
130 dell_old_cap_hook
= spec
->gen
.cap_sync_hook
;
131 spec
->gen
.cap_sync_hook
= update_dell_wmi_micmute_led
;
133 add_mixer(spec
, dell_mic_mute_mode_ctls
);
139 if (dell_micmute_led_set_func
&& (action
== HDA_FIXUP_ACT_FREE
|| removefunc
)) {
140 symbol_put(dell_micmute_led_set
);
141 dell_micmute_led_set_func
= NULL
;
142 dell_old_cap_hook
= NULL
;
146 #else /* CONFIG_DELL_LAPTOP */
147 static void alc_fixup_dell_wmi(struct hda_codec
*codec
,
148 const struct hda_fixup
*fix
, int action
)
152 #endif /* CONFIG_DELL_LAPTOP */