[ALSA] HDA/ALC260: 4/7 - add GPIO switches to test model
authorJonathan Woithe <jwoithe@physics.adelaide.edu.au>
Tue, 28 Feb 2006 10:43:27 +0000 (11:43 +0100)
committerJaroslav Kysela <perex@suse.cz>
Wed, 22 Mar 2006 09:32:49 +0000 (10:32 +0100)
Modules: HDA Codec driver

This patch adds 'test' model mixer switches for the GPIO controls found on
the ALC260.  It has been found that some laptops (eg: Acer) can use these to
enable particular controls, so it would be useful to have access to these
via the 'test' model.  It will make testing new models easy, especially if
certain outputs cannot be made to work any other way.

This patch *should* work, but because the GPIO pins don't do anything in
my laptop I cannot personally verify that all this works as expected.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_realtek.c

index 80ba6c7..4f6dea2 100644 (file)
@@ -342,6 +342,58 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
          .put = alc_pin_mode_put, \
          .private_value = nid | (dir<<16) }
 
+/* A switch control for ALC260 GPIO pins.  Multiple GPIOs can be ganged
+ * together using a mask with more than one bit set.  This control is
+ * currently used only by the ALC260 test model.  At this stage they are not
+ * needed for any "production" models.
+ */
+#ifdef CONFIG_SND_DEBUG
+static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}                                
+static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long *valp = ucontrol->value.integer.value;
+       unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
+
+       *valp = (val & mask) != 0;
+       return 0;
+}
+static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       signed int change;
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value & 0xffff;
+       unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+       long val = *ucontrol->value.integer.value;
+       unsigned int gpio_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
+
+       /* Set/unset the masked GPIO bit(s) as needed */
+       change = (val==0?0:mask) != (gpio_data & mask);
+       if (val==0)
+               gpio_data &= ~mask;
+       else
+               gpio_data |= mask;
+       snd_hda_codec_write(codec,nid,0,AC_VERB_SET_GPIO_DATA,gpio_data);
+
+       return change;
+}
+#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+         .info = alc_gpio_data_info, \
+         .get = alc_gpio_data_get, \
+         .put = alc_gpio_data_put, \
+         .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
+
 /*
  * set up from the preset table
  */
@@ -2874,11 +2926,21 @@ static struct snd_kcontrol_new alc260_test_mixer[] = {
        HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
        HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
        HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
+
+       /* Controls for GPIO pins, assuming they are configured as outputs */
+       ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+       ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+
        { } /* end */
 };
 static struct hda_verb alc260_test_init_verbs[] = {
-       /* Disable all GPIOs */
-       {0x01, AC_VERB_SET_GPIO_MASK, 0},
+       /* Enable all GPIOs as outputs with an initial value of 0 */
+       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+       {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
        /* Enable retasking pins as output, initially without power amp */
        {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},