1 /* Helper functions for Dell Mic Mute LED control;
2 * to be included from codec driver
5 #if IS_ENABLED(CONFIG_DELL_LAPTOP)
6 #include <linux/dell-led.h>
11 MICMUTE_LED_FOLLOW_CAPTURE
,
12 MICMUTE_LED_FOLLOW_MUTE
,
15 static int dell_led_mode
= MICMUTE_LED_FOLLOW_MUTE
;
16 static int dell_capture
;
17 static int dell_led_value
;
18 static int (*dell_micmute_led_set_func
)(int);
19 static void (*dell_old_cap_hook
)(struct hda_codec
*,
20 struct snd_kcontrol
*,
21 struct snd_ctl_elem_value
*);
23 static void call_micmute_led_update(void)
27 switch (dell_led_mode
) {
34 case MICMUTE_LED_FOLLOW_CAPTURE
:
37 case MICMUTE_LED_FOLLOW_MUTE
:
43 if (val
== dell_led_value
)
46 dell_micmute_led_set_func(dell_led_value
);
49 static void update_dell_wmi_micmute_led(struct hda_codec
*codec
,
50 struct snd_kcontrol
*kcontrol
,
51 struct snd_ctl_elem_value
*ucontrol
)
53 if (dell_old_cap_hook
)
54 dell_old_cap_hook(codec
, kcontrol
, ucontrol
);
56 if (!ucontrol
|| !dell_micmute_led_set_func
)
58 if (strcmp("Capture Switch", ucontrol
->id
.name
) == 0 && ucontrol
->id
.index
== 0) {
59 /* TODO: How do I verify if it's a mono or stereo here? */
60 dell_capture
= (ucontrol
->value
.integer
.value
[0] ||
61 ucontrol
->value
.integer
.value
[1]);
62 call_micmute_led_update();
66 static int dell_mic_mute_led_mode_info(struct snd_kcontrol
*kcontrol
,
67 struct snd_ctl_elem_info
*uinfo
)
69 static const char * const texts
[] = {
70 "On", "Off", "Follow Capture", "Follow Mute",
73 return snd_ctl_enum_info(uinfo
, 1, ARRAY_SIZE(texts
), texts
);
76 static int dell_mic_mute_led_mode_get(struct snd_kcontrol
*kcontrol
,
77 struct snd_ctl_elem_value
*ucontrol
)
79 ucontrol
->value
.enumerated
.item
[0] = dell_led_mode
;
83 static int dell_mic_mute_led_mode_put(struct snd_kcontrol
*kcontrol
,
84 struct snd_ctl_elem_value
*ucontrol
)
88 mode
= ucontrol
->value
.enumerated
.item
[0];
89 if (mode
> MICMUTE_LED_FOLLOW_MUTE
)
90 mode
= MICMUTE_LED_FOLLOW_MUTE
;
91 if (mode
== dell_led_mode
)
94 call_micmute_led_update();
98 static const struct snd_kcontrol_new dell_mic_mute_mode_ctls
[] = {
100 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
101 .name
= "Mic Mute-LED Mode",
102 .info
= dell_mic_mute_led_mode_info
,
103 .get
= dell_mic_mute_led_mode_get
,
104 .put
= dell_mic_mute_led_mode_put
,
109 static void alc_fixup_dell_wmi(struct hda_codec
*codec
,
110 const struct hda_fixup
*fix
, int action
)
112 struct alc_spec
*spec
= codec
->spec
;
113 bool removefunc
= false;
115 if (action
== HDA_FIXUP_ACT_PROBE
) {
116 if (!dell_micmute_led_set_func
)
117 dell_micmute_led_set_func
= symbol_request(dell_micmute_led_set
);
118 if (!dell_micmute_led_set_func
) {
119 codec_warn(codec
, "Failed to find dell wmi symbol dell_micmute_led_set\n");
124 if (dell_micmute_led_set_func(false) >= 0) {
126 if (spec
->gen
.num_adc_nids
> 1 && !spec
->gen
.dyn_adc_switch
)
127 codec_dbg(codec
, "Skipping micmute LED control due to several ADCs");
129 dell_old_cap_hook
= spec
->gen
.cap_sync_hook
;
130 spec
->gen
.cap_sync_hook
= update_dell_wmi_micmute_led
;
132 add_mixer(spec
, dell_mic_mute_mode_ctls
);
138 if (dell_micmute_led_set_func
&& (action
== HDA_FIXUP_ACT_FREE
|| removefunc
)) {
139 symbol_put(dell_micmute_led_set
);
140 dell_micmute_led_set_func
= NULL
;
141 dell_old_cap_hook
= NULL
;
145 #else /* CONFIG_DELL_LAPTOP */
146 static void alc_fixup_dell_wmi(struct hda_codec
*codec
,
147 const struct hda_fixup
*fix
, int action
)
151 #endif /* CONFIG_DELL_LAPTOP */