summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 8860dd529520..bf5e58ec1efe 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -555,6 +555,9 @@ struct azx {
#ifdef CONFIG_SND_HDA_DSP_LOADER
struct azx_dev saved_azx_dev;
#endif
+
+ /* secondary power domain for hdmi audio under vga device */
+ struct dev_pm_domain hdmi_pm_domain;
};
#define CREATE_TRACE_POINTS
@@ -1397,8 +1400,9 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
int i, ok;
#ifdef CONFIG_PM_RUNTIME
- if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
- return IRQ_NONE;
+ if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+ if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
+ return IRQ_NONE;
#endif
spin_lock(&chip->reg_lock);
@@ -1409,7 +1413,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
}
status = azx_readl(chip, INTSTS);
- if (status == 0) {
+ if (status == 0 || status == 0xffffffff) {
spin_unlock(&chip->reg_lock);
return IRQ_NONE;
}
@@ -2971,6 +2975,12 @@ static int azx_runtime_suspend(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
+ if (chip->disabled)
+ return 0;
+
+ if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+ return 0;
+
azx_stop_chip(chip);
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
@@ -2984,6 +2994,12 @@ static int azx_runtime_resume(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
+ if (chip->disabled)
+ return 0;
+
+ if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+ return 0;
+
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
hda_display_power(true);
azx_init_pci(chip);
@@ -2996,6 +3012,9 @@ static int azx_runtime_idle(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
+ if (chip->disabled)
+ return 0;
+
if (!power_save_controller ||
!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
return -EBUSY;
@@ -3078,13 +3097,19 @@ static void azx_vs_set_state(struct pci_dev *pci,
"%s: %s via VGA-switcheroo\n", pci_name(chip->pci),
disabled ? "Disabling" : "Enabling");
if (disabled) {
+ pm_runtime_put_sync_suspend(&pci->dev);
azx_suspend(&pci->dev);
+ /* when we get suspended by vga switcheroo we end up in D3cold,
+ * however we have no ACPI handle, so pci/acpi can't put us there,
+ * put ourselves there */
+ pci->current_state = PCI_D3cold;
chip->disabled = true;
if (snd_hda_lock_devices(chip->bus))
snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n",
pci_name(chip->pci));
} else {
snd_hda_unlock_devices(chip->bus);
+ pm_runtime_get_noresume(&pci->dev);
chip->disabled = false;
azx_resume(&pci->dev);
}
@@ -3139,6 +3164,9 @@ static int register_vga_switcheroo(struct azx *chip)
if (err < 0)
return err;
chip->vga_switcheroo_registered = 1;
+
+ /* register as an optimus hdmi audio power domain */
+ vga_switcheroo_init_domain_pm_optimus_hdmi_audio(&chip->pci->dev, &chip->hdmi_pm_domain);
return 0;
}
#else
@@ -3887,7 +3915,7 @@ static int azx_probe_continue(struct azx *chip)
power_down_all_codecs(chip);
azx_notifier_register(chip);
azx_add_card_list(chip);
- if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+ if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || chip->use_vga_switcheroo)
pm_runtime_put_noidle(&pci->dev);
return 0;