aboutsummaryrefslogtreecommitdiff
path: root/sound/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/patch_realtek.c66
1 files changed, 64 insertions, 2 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 80ba6c753c3..4f6dea23d8b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -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},