diff mbox

[1/2,SRU,Artful] ALSA: hda - Add HP ZBook 15u G3 Conexant CX20724 GPIO mute leds

Message ID 20170801032953.16287-1-kai.heng.feng@canonical.com
State New
Headers show

Commit Message

Kai-Heng Feng Aug. 1, 2017, 3:29 a.m. UTC
From: Jerónimo Borque <jeronimo@borque.com.ar>

BugLink: https://bugs.launchpad.net/bugs/1705586

The HP ZBook 15u G3 has a Conexant CX20724 with mute led on GPIO1 and
mic mute led on GPIO2.
Adding CXT_FIXUP_MUTE_LED_GPIO inspired on patch_realtek's one.

Signed-off-by: Jerónimo Borque <jeronimo@borque.com.ar>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
(cherry picked from commit 5cd5b1bdfb0137d0e814a51ff203d72c76b9f375)
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 sound/pci/hda/patch_conexant.c | 81 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

Comments

Stefan Bader Aug. 1, 2017, 8:23 a.m. UTC | #1
On 01.08.2017 05:29, Kai-Heng Feng wrote:
> From: Jerónimo Borque <jeronimo@borque.com.ar>
> 
> BugLink: https://bugs.launchpad.net/bugs/1705586
> 
> The HP ZBook 15u G3 has a Conexant CX20724 with mute led on GPIO1 and
> mic mute led on GPIO2.
> Adding CXT_FIXUP_MUTE_LED_GPIO inspired on patch_realtek's one.
> 
> Signed-off-by: Jerónimo Borque <jeronimo@borque.com.ar>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> (cherry picked from commit 5cd5b1bdfb0137d0e814a51ff203d72c76b9f375)
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---
>  sound/pci/hda/patch_conexant.c | 81 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 81 insertions(+)
> 
> diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
> index 69266b8ea2ad..e8253737c47a 100644
> --- a/sound/pci/hda/patch_conexant.c
> +++ b/sound/pci/hda/patch_conexant.c
> @@ -52,6 +52,12 @@ struct conexant_spec {
>  	bool dc_enable;
>  	unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
>  	struct nid_path *dc_mode_path;
> +
> +	int mute_led_polarity;
> +	unsigned int gpio_led;
> +	unsigned int gpio_mute_led_mask;
> +	unsigned int gpio_mic_led_mask;
> +
>  };
>  
>  
> @@ -264,6 +270,7 @@ enum {
>  	CXT_FIXUP_HP_DOCK,
>  	CXT_FIXUP_HP_SPECTRE,
>  	CXT_FIXUP_HP_GATE_MIC,
> +	CXT_FIXUP_MUTE_LED_GPIO,
>  };
>  
>  /* for hda_fixup_thinkpad_acpi() */
> @@ -646,6 +653,74 @@ static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
>  		snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
>  }
>  
> +/* update LED status via GPIO */
> +static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
> +				bool enabled)
> +{
> +	struct conexant_spec *spec = codec->spec;
> +	unsigned int oldval = spec->gpio_led;
> +
> +	if (spec->mute_led_polarity)
> +		enabled = !enabled;
> +
> +	if (enabled)
> +		spec->gpio_led &= ~mask;
> +	else
> +		spec->gpio_led |= mask;
> +	if (spec->gpio_led != oldval)
> +		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
> +				    spec->gpio_led);
> +}
> +
> +/* turn on/off mute LED via GPIO per vmaster hook */
> +static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
> +{
> +	struct hda_codec *codec = private_data;
> +	struct conexant_spec *spec = codec->spec;
> +
> +	cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
> +}
> +
> +/* turn on/off mic-mute LED via GPIO per capture hook */
> +static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
> +					 struct snd_kcontrol *kcontrol,
> +					 struct snd_ctl_elem_value *ucontrol)
> +{
> +	struct conexant_spec *spec = codec->spec;
> +
> +	if (ucontrol)
> +		cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
> +				    ucontrol->value.integer.value[0] ||
> +				    ucontrol->value.integer.value[1]);
> +}
> +
> +
> +static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
> +				const struct hda_fixup *fix, int action)
> +{
> +	struct conexant_spec *spec = codec->spec;
> +	static const struct hda_verb gpio_init[] = {
> +		{ 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
> +		{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
> +		{}
> +	};
> +	codec_info(codec, "action: %d gpio_led: %d\n", action, spec->gpio_led);
> +
> +	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
> +		spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
> +		spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook;
> +		spec->gpio_led = 0;
> +		spec->mute_led_polarity = 0;
> +		spec->gpio_mute_led_mask = 0x01;
> +		spec->gpio_mic_led_mask = 0x02;
> +	}
> +	snd_hda_add_verbs(codec, gpio_init);
> +	if (spec->gpio_led)
> +		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
> +				    spec->gpio_led);
> +}
> +
> +
>  /* ThinkPad X200 & co with cxt5051 */
>  static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
>  	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
> @@ -799,6 +874,10 @@ static const struct hda_fixup cxt_fixups[] = {
>  		.type = HDA_FIXUP_FUNC,
>  		.v.func = cxt_fixup_hp_gate_mic_jack,
>  	},
> +	[CXT_FIXUP_MUTE_LED_GPIO] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = cxt_fixup_mute_led_gpio,
> +	},
>  };
>  
>  static const struct snd_pci_quirk cxt5045_fixups[] = {
> @@ -851,6 +930,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
>  	SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
>  	SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
>  	SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
> +	SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
>  	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
>  	SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
>  	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
> @@ -882,6 +962,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
>  	{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
>  	{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
>  	{ .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
> +	{ .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
>  	{}
>  };
>  
> 
I believe this set was replaced by the follow up which had patch#1 split up for
A and Z.
diff mbox

Patch

diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 69266b8ea2ad..e8253737c47a 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -52,6 +52,12 @@  struct conexant_spec {
 	bool dc_enable;
 	unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
 	struct nid_path *dc_mode_path;
+
+	int mute_led_polarity;
+	unsigned int gpio_led;
+	unsigned int gpio_mute_led_mask;
+	unsigned int gpio_mic_led_mask;
+
 };
 
 
@@ -264,6 +270,7 @@  enum {
 	CXT_FIXUP_HP_DOCK,
 	CXT_FIXUP_HP_SPECTRE,
 	CXT_FIXUP_HP_GATE_MIC,
+	CXT_FIXUP_MUTE_LED_GPIO,
 };
 
 /* for hda_fixup_thinkpad_acpi() */
@@ -646,6 +653,74 @@  static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
 		snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
 }
 
+/* update LED status via GPIO */
+static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+				bool enabled)
+{
+	struct conexant_spec *spec = codec->spec;
+	unsigned int oldval = spec->gpio_led;
+
+	if (spec->mute_led_polarity)
+		enabled = !enabled;
+
+	if (enabled)
+		spec->gpio_led &= ~mask;
+	else
+		spec->gpio_led |= mask;
+	if (spec->gpio_led != oldval)
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_led);
+}
+
+/* turn on/off mute LED via GPIO per vmaster hook */
+static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
+{
+	struct hda_codec *codec = private_data;
+	struct conexant_spec *spec = codec->spec;
+
+	cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
+}
+
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
+					 struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct conexant_spec *spec = codec->spec;
+
+	if (ucontrol)
+		cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
+				    ucontrol->value.integer.value[0] ||
+				    ucontrol->value.integer.value[1]);
+}
+
+
+static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
+				const struct hda_fixup *fix, int action)
+{
+	struct conexant_spec *spec = codec->spec;
+	static const struct hda_verb gpio_init[] = {
+		{ 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
+		{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
+		{}
+	};
+	codec_info(codec, "action: %d gpio_led: %d\n", action, spec->gpio_led);
+
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+		spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
+		spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook;
+		spec->gpio_led = 0;
+		spec->mute_led_polarity = 0;
+		spec->gpio_mute_led_mask = 0x01;
+		spec->gpio_mic_led_mask = 0x02;
+	}
+	snd_hda_add_verbs(codec, gpio_init);
+	if (spec->gpio_led)
+		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+				    spec->gpio_led);
+}
+
+
 /* ThinkPad X200 & co with cxt5051 */
 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
 	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -799,6 +874,10 @@  static const struct hda_fixup cxt_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = cxt_fixup_hp_gate_mic_jack,
 	},
+	[CXT_FIXUP_MUTE_LED_GPIO] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cxt_fixup_mute_led_gpio,
+	},
 };
 
 static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -851,6 +930,7 @@  static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
 	SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
 	SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
+	SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
 	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
 	SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -882,6 +962,7 @@  static const struct hda_model_fixup cxt5066_fixup_models[] = {
 	{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
 	{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
 	{ .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
+	{ .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
 	{}
 };