[alsa-devel] [PATCH 1/3] snd-meastro3: Add amp_gpio quirk for Compaq EVO N600C
Without this quirk sound stops working after suspend resume. With this quirk, one still needs to manually unmute the master volume control after a suspend / / resume cycle. That is fixed in another patch in this set.
Note that this patch was submitted to the alsa bug tracker a long time ago: https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4319
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/pci/maestro3.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 75283fb..491a2fc 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -884,6 +884,7 @@ static struct pci_device_id snd_m3_ids[] = { MODULE_DEVICE_TABLE(pci, snd_m3_ids);
static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { + SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c), SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03),
While working on a fix for the volume being muted on the allegro in my Compaq EVO N600C after suspend, I've learned a few things about the hardware volume control worth documenting. The actual fix for the suspend / resume issue is in the next patch in this set.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/pci/maestro3.c | 22 ++++++++++++++++++---- 1 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 491a2fc..c6593cf 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1597,6 +1597,10 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s) } }
+/* The m3's hardware volume works by incrementing / decrementing 2 counters + (without wrap around) in response to volume button presses and then + generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 + of a byte wide register. The meaning of bits 0 and 4 is unknown. */ static void snd_m3_update_hw_volume(unsigned long private_data) { struct snd_m3 *chip = (struct snd_m3 *) private_data; @@ -1608,7 +1612,15 @@ static void snd_m3_update_hw_volume(unsigned long private_data) values. */ x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
- /* Reset the volume control registers. */ + /* Reset the volume counters to 4. Tests on the allegro integrated + into a Compaq N600C laptop, have revealed that: + 1) Writing any value will result in the 2 counters being reset to + 4 so writing 0x88 is not strictly necessary + 2) Writing to any of the 4 involved registers will reset all 4 + of them (and reading them always returns the same value for all + of them) + It could be that a maestro deviates from this, so leave the code + as is. */ outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); @@ -1623,7 +1635,9 @@ static void snd_m3_update_hw_volume(unsigned long private_data) val = chip->ac97->regs[AC97_MASTER_VOL]; switch (x) { case 0x88: - /* mute */ + /* The counters have not changed, yet we've received a HV + interrupt. According to tests run by various people this + happens when pressing the mute button. */ val ^= 0x8000; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); @@ -1632,7 +1646,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) &chip->master_switch->id); break; case 0xaa: - /* volume up */ + /* counters increased by 1 -> volume up */ if ((val & 0x7f) > 0) val--; if ((val & 0x7f00) > 0) @@ -1644,7 +1658,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data) &chip->master_volume->id); break; case 0x66: - /* volume down */ + /* counters decreased by 1 -> volume down */ if ((val & 0x7f) < 0x1f) val++; if ((val & 0x7f00) < 0x1f00)
Ignore spurious HV interrupts during suspend / resume, this avoids mistaking them for a mute button press. This is not very pretty but it seems the only way to fix the master volume control gets muted after suspend issue I'm seeing. Note that the es1968 driver is doing exactly the same.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- sound/pci/maestro3.c | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index c6593cf..0ed634a 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -849,6 +849,7 @@ struct snd_m3 { struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; struct tasklet_struct hwvol_tq; + unsigned int in_suspend;
#ifdef CONFIG_PM u16 *suspend_mem; @@ -1626,6 +1627,11 @@ static void snd_m3_update_hw_volume(unsigned long private_data) outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER);
+ /* Ignore spurious HV interrupts during suspend / resume, this avoids + mistaking them for a mute button press. */ + if (chip->in_suspend) + return; + if (!chip->master_switch || !chip->master_volume) return;
@@ -2439,6 +2445,7 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state) if (chip->suspend_mem == NULL) return 0;
+ chip->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2512,6 +2519,7 @@ static int m3_resume(struct pci_dev *pci) snd_m3_hv_init(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0); + chip->in_suspend = 0; return 0; } #endif /* CONFIG_PM */
participants (1)
-
Hans de Goede