ALSA: hda - Fix LED GPIO setup for HP laptops with IDT codecs
Vitaliy Kulikov [Fri, 11 Dec 2009 06:51:54 +0000 (07:51 +0100)]
This patch fixes an error in processing of the HP BIOS configuration to enable
GPIO based mute LED indicator control. That error causes driver to enable
such control on all HP systems with the 92HD75 IDT codecs and results in
unnecessary toggling of the GPIO on mute control manipulation.

It also adds support of the future HP BIOS configuration extension for the
named control. New configuration string has a format HP_Mute_LED_P_G
where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
that corresponds to the NOT muted state of the master volume
and G is the index of the GPIO to use (0..9)

Lastly, it adds more systems to the support of the audio implementation
as found on HP B-series systems

Signed-off-by: Vitaliy Kulikov <Vitaliy.Kulikov@idt.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

sound/pci/hda/patch_sigmatel.c

index 6b0bc04..e666723 100644 (file)
@@ -209,6 +209,7 @@ struct sigmatel_spec {
        unsigned int gpio_data;
        unsigned int gpio_mute;
        unsigned int gpio_led;
+       unsigned int gpio_led_polarity;
 
        /* stream */
        unsigned int stream_delay;
@@ -4724,13 +4725,61 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
        }
 }
 
-static int hp_bseries_system(u32 subsystem_id)
+/*
+ * This method searches for the mute LED GPIO configuration
+ * provided as OEM string in SMBIOS. The format of that string
+ * is HP_Mute_LED_P_G or HP_Mute_LED_P
+ * where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
+ * that corresponds to the NOT muted state of the master volume
+ * and G is the index of the GPIO to use as the mute LED control (0..9)
+ * If _G portion is missing it is assigned based on the codec ID
+ *
+ * So, HP B-series like systems may have HP_Mute_LED_0 (current models)
+ * or  HP_Mute_LED_0_3 (future models) OEM SMBIOS strings
+ */
+static int find_mute_led_gpio(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       const struct dmi_device *dev = NULL;
+
+       if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
+               while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
+                                                               NULL, dev))) {
+                       if (sscanf(dev->name, "HP_Mute_LED_%d_%d",
+                             &spec->gpio_led_polarity,
+                             &spec->gpio_led) == 2) {
+                               spec->gpio_led = 1 << spec->gpio_led;
+                               return 1;
+                       }
+                       if (sscanf(dev->name, "HP_Mute_LED_%d",
+                             &spec->gpio_led_polarity) == 1) {
+                               switch (codec->vendor_id) {
+                               case 0x111d7608:
+                                       /* GPIO 0 */
+                                       spec->gpio_led = 0x01;
+                                       return 1;
+                               case 0x111d7600:
+                               case 0x111d7601:
+                               case 0x111d7602:
+                               case 0x111d7603:
+                                       /* GPIO 3 */
+                                       spec->gpio_led = 0x08;
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+static int hp_blike_system(u32 subsystem_id)
 {
        switch (subsystem_id) {
-       case 0x103c307e:
-       case 0x103c307f:
-       case 0x103c3080:
-       case 0x103c3081:
+       case 0x103c1520:
+       case 0x103c1521:
+       case 0x103c1523:
+       case 0x103c1524:
+       case 0x103c1525:
        case 0x103c1722:
        case 0x103c1723:
        case 0x103c1724:
@@ -4739,6 +4788,14 @@ static int hp_bseries_system(u32 subsystem_id)
        case 0x103c1727:
        case 0x103c1728:
        case 0x103c1729:
+       case 0x103c172a:
+       case 0x103c172b:
+       case 0x103c307e:
+       case 0x103c307f:
+       case 0x103c3080:
+       case 0x103c3081:
+       case 0x103c7007:
+       case 0x103c7008:
                return 1;
        }
        return 0;
@@ -4833,7 +4890,7 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
                else
                        spec->gpio_data |= spec->gpio_led; /* white */
 
-               if (hp_bseries_system(codec->subsystem_id)) {
+               if (!spec->gpio_led_polarity) {
                        /* LED state is inverted on these systems */
                        spec->gpio_data ^= spec->gpio_led;
                }
@@ -5526,7 +5583,7 @@ again:
                break;
        }
 
-       if (hp_bseries_system(codec->subsystem_id)) {
+       if (hp_blike_system(codec->subsystem_id)) {
                pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f);
                if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
                        get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER  ||
@@ -5544,26 +5601,10 @@ again:
                }
        }
 
-       if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
-               const struct dmi_device *dev = NULL;
-               while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
-                                             NULL, dev))) {
-                       if (strcmp(dev->name, "HP_Mute_LED_1")) {
-                               switch (codec->vendor_id) {
-                               case 0x111d7608:
-                                       spec->gpio_led = 0x01;
-                                       break;
-                               case 0x111d7600:
-                               case 0x111d7601:
-                               case 0x111d7602:
-                               case 0x111d7603:
-                                       spec->gpio_led = 0x08;
-                                       break;
-                               }
-                               break;
-                       }
-               }
-       }
+       if (find_mute_led_gpio(codec))
+               snd_printd("mute LED gpio %d polarity %d\n",
+                               spec->gpio_led,
+                               spec->gpio_led_polarity);
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (spec->gpio_led) {