From patchwork Wed Jul 15 02:37:44 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Packard X-Patchwork-Id: 6794231 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 4F82B9F380 for ; Wed, 15 Jul 2015 07:46:43 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 34CED205C4 for ; Wed, 15 Jul 2015 07:46:42 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id AB2B92052A for ; Wed, 15 Jul 2015 07:46:40 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id BC6932665A0; Wed, 15 Jul 2015 09:46:39 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 4F114265AF3; Wed, 15 Jul 2015 09:35:43 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 4667426572D; Wed, 15 Jul 2015 04:37:56 +0200 (CEST) Received: from elaine.keithp.com (home.keithp.com [63.227.221.253]) by alsa0.perex.cz (Postfix) with ESMTP id ED8B726571B for ; Wed, 15 Jul 2015 04:37:48 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by elaine.keithp.com (Postfix) with ESMTP id 8DB4D3F20062; Tue, 14 Jul 2015 19:37:46 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at keithp.com Received: from elaine.keithp.com ([127.0.0.1]) by localhost (elaine.keithp.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id ATW85eZcEQ_s; Tue, 14 Jul 2015 19:37:45 -0700 (PDT) Received: by elaine.keithp.com (Postfix, from userid 1033) id ACAD73F2085F; Tue, 14 Jul 2015 19:37:45 -0700 (PDT) Received: from hiro.keithp.com (localhost [127.0.0.1]) by elaine.keithp.com (Postfix) with ESMTP id 824073F20062; Tue, 14 Jul 2015 19:37:45 -0700 (PDT) Received: by hiro.keithp.com (Postfix, from userid 1001) id 559207410DE; Tue, 14 Jul 2015 19:37:45 -0700 (PDT) From: Keith Packard To: Takashi Iwai In-Reply-To: References: <1436892035-19589-1-git-send-email-keithp@keithp.com> <1436895871-2459-1-git-send-email-keithp@keithp.com> User-Agent: Notmuch/0.18.2 (http://notmuchmail.org) Emacs/24.4.1 (x86_64-pc-linux-gnu) Date: Tue, 14 Jul 2015 19:37:44 -0700 Message-ID: <86si8qw3gn.fsf@hiro.keithp.com> MIME-Version: 1.0 X-Mailman-Approved-At: Wed, 15 Jul 2015 09:35:32 +0200 Cc: alsa-devel@alsa-project.org, Kailang Yang , linux-kernel@vger.kernel.org, Hui Wang , David Henningsson Subject: Re: [alsa-devel] [PATCH] ALSA: hda/realtek: Enable HP amp and mute LED on HP Folio 9480m X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Takashi Iwai writes: > Thanks for the patch. But this looks suboptimal, unfortunately, since > it keeps the amp always on, and more badly, it would block the power > save of the widget root node. Thanks very much for your feedback; I wasn't sure precisely how this code worked and tried to make a change that was as close as I could manage to existing examples. > Can just using gpio_mute_led_mask=0x18 and gpio_led=0 (also drop > AC_VERB_SET_GPIO_DATA in gpio_init[]) work instead? If GPIO4 is the > the amp, we can associate it with the master mute control together > with the mute LED. The only concern would be the possible click > noise, but it doesn't happen on most machines. It's not quite that simple; the GPIO4 value is inverted from the mute LED value (the amp is powered up when GPIO4 is set). What I've done is to make the amp powered only when a headphone is plugged in, and then removed the code which was disabling power saving, which lets everything (including the amp) get turned back off when the device goes idle. Here's a second version of the patch. From 60e2c02d651b0ca6e4b72aa1cab21660400fe2eb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 14 Jul 2015 09:30:33 -0700 Subject: [PATCH] ALSA: hda/realtek: Enable HP amp and mute LED on HP Folio 9480m [v2] This laptop needs GPIO4 pulled high to enable the headphone amplifier, and has a mute LED on GPIO3. I modelled the patch on the existing GPIO4 code which pulls the line low for the same purpose; this time, the HP amp line is pulled high. v2: Disable the headphone amplifier when no headphone is connected. Don't disable power savings to preserve the LED state. Signed-off-by: Keith Packard --- sound/pci/hda/patch_realtek.c | 112 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6d01045..621c195 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -99,6 +99,7 @@ struct alc_spec { unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */ unsigned int gpio_mute_led_mask; unsigned int gpio_mic_led_mask; + unsigned int gpio_hp_amp_mask; hda_nid_t headset_mic_pin; hda_nid_t headphone_mic_pin; @@ -4435,6 +4436,111 @@ static void alc290_fixup_mono_speakers(struct hda_codec *codec, } } +/* Set headphone amp power via a GPIO depending on whether the + * headphones are plugged in or not + */ +static void alc280_set_hp_amp_power(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int oldval = spec->gpio_led; + + /* Headphone amp enable when headphone present */ + if (spec->gen.hp_jack_present) + spec->gpio_led |= spec->gpio_hp_amp_mask; + else + spec->gpio_led &= ~spec->gpio_hp_amp_mask; + + codec_dbg(codec, + "set_hp_amp_power present %d oldval %02x current %02x\n", + spec->gen.hp_jack_present, + oldval, spec->gpio_led); + + if (spec->gpio_led != oldval) + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); +} + +/* Detect headphone connection, then go update the headphone amp + * GPIO */ +static void alc280_update_headset_mode(struct hda_codec *codec) +{ + alc_update_headset_mode(codec); + alc280_set_hp_amp_power(codec); +} + +/* Hook to update headphone amp GPIO on config changes */ +static void +alc280_update_headset_mode_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + alc280_update_headset_mode(codec); +} + +/* Hook to update amp GPIO for automute */ +static void alc280_update_headset_jack_cb(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + alc_update_headset_jack_cb(codec, jack); + alc280_set_hp_amp_power(codec); +} + +/* Manage GPIOs for HP EliteBook Folio 9480m. + * + * GPIO4 is the headphone amplifier power control + * GPIO3 is the audio output mute indicator LED + */ + +static void alc280_fixup_hp_9480m(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 }, + {} + }; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + + /* Set the hooks to turn the headphone amp on/off + * as needed + */ + spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook; + spec->gen.cap_sync_hook = alc280_update_headset_mode_hook; + spec->gen.automute_hook = alc280_update_headset_mode; + spec->gen.hp_automute_hook = alc280_update_headset_jack_cb; + + /* The GPIOs are currently off */ + spec->gpio_led = 0; + + /* GPIO4 controls the headphone amp, + * high is on, low is off + */ + spec->gpio_hp_amp_mask = 0x10; + + /* GPIO3 is connected to the output mute LED, + * high is on, low is off + */ + spec->mute_led_polarity = 0; + spec->gpio_mute_led_mask = 0x08; + + /* Initialize GPIO configuration */ + snd_hda_add_verbs(codec, gpio_init); + break; + case HDA_FIXUP_ACT_INIT: + + /* Force configuration of headphone amp + * GPIO + */ + spec->current_headset_mode = 0; + alc280_update_headset_mode(codec); + break; + } +} + /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" @@ -4512,6 +4618,7 @@ enum { ALC286_FIXUP_HP_GPIO_LED, ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, ALC280_FIXUP_HP_DOCK_PINS, + ALC280_FIXUP_HP_9480M, ALC288_FIXUP_DELL_HEADSET_MODE, ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, ALC288_FIXUP_DELL_XPS_13_GPIO6, @@ -5012,6 +5119,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC280_FIXUP_HP_GPIO4 }, + [ALC280_FIXUP_HP_9480M] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc280_fixup_hp_9480m, + }, [ALC288_FIXUP_DELL_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_headset_mode_dell_alc288, @@ -5103,6 +5214,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M), SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), /* ALC290 */ -- 2.1.4