summaryrefslogtreecommitdiff
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.c87
1 files changed, 70 insertions, 17 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index f39de9055097..8860dd529520 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -62,6 +62,7 @@
#include <linux/vga_switcheroo.h>
#include <linux/firmware.h>
#include "hda_codec.h"
+#include "hda_i915.h"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -541,6 +542,10 @@ struct azx {
/* for pending irqs */
struct work_struct irq_pending_work;
+#ifdef CONFIG_SND_HDA_I915
+ struct work_struct probe_work;
+#endif
+
/* reboot notifier (for mysterious hangup problem at power-down) */
struct notifier_block reboot_notifier;
@@ -594,6 +599,7 @@ enum {
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
+#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 power well support */
/* quirks for Intel PCH */
#define AZX_DCAPS_INTEL_PCH_NOPM \
@@ -2919,6 +2925,8 @@ static int azx_suspend(struct device *dev)
pci_disable_device(pci);
pci_save_state(pci);
pci_set_power_state(pci, PCI_D3hot);
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(false);
return 0;
}
@@ -2931,6 +2939,8 @@ static int azx_resume(struct device *dev)
if (chip->disabled)
return 0;
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(true);
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
@@ -2964,6 +2974,8 @@ static int azx_runtime_suspend(struct device *dev)
azx_stop_chip(chip);
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(false);
return 0;
}
@@ -2972,6 +2984,8 @@ static int azx_runtime_resume(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
+ hda_display_power(true);
azx_init_pci(chip);
azx_init_chip(chip, 1);
return 0;
@@ -3026,7 +3040,6 @@ static void azx_notifier_unregister(struct azx *chip)
unregister_reboot_notifier(&chip->reboot_notifier);
}
-static int azx_first_init(struct azx *chip);
static int azx_probe_continue(struct azx *chip);
#ifdef SUPPORT_VGA_SWITCHEROO
@@ -3053,8 +3066,7 @@ static void azx_vs_set_state(struct pci_dev *pci,
snd_printk(KERN_INFO SFX
"%s: Start delayed initialization\n",
pci_name(chip->pci));
- if (azx_first_init(chip) < 0 ||
- azx_probe_continue(chip) < 0) {
+ if (azx_probe_continue(chip) < 0) {
snd_printk(KERN_ERR SFX
"%s: initialization error\n",
pci_name(chip->pci));
@@ -3140,8 +3152,13 @@ static int register_vga_switcheroo(struct azx *chip)
*/
static int azx_free(struct azx *chip)
{
+ struct pci_dev *pci = chip->pci;
int i;
+ if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
+ && chip->running)
+ pm_runtime_get_noresume(&pci->dev);
+
azx_del_card_list(chip);
azx_notifier_unregister(chip);
@@ -3193,6 +3210,10 @@ static int azx_free(struct azx *chip)
if (chip->fw)
release_firmware(chip->fw);
#endif
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+ hda_display_power(false);
+ hda_i915_exit();
+ }
kfree(chip);
return 0;
@@ -3418,6 +3439,13 @@ static void azx_check_snoop_available(struct azx *chip)
}
}
+#ifdef CONFIG_SND_HDA_I915
+static void azx_probe_work(struct work_struct *work)
+{
+ azx_probe_continue(container_of(work, struct azx, probe_work));
+}
+#endif
+
/*
* constructor
*/
@@ -3493,7 +3521,13 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
+#ifdef CONFIG_SND_HDA_I915
+ /* continue probing in work context as may trigger request module */
+ INIT_WORK(&chip->probe_work, azx_probe_work);
+#endif
+
*rchip = chip;
+
return 0;
}
@@ -3750,11 +3784,6 @@ static int azx_probe(struct pci_dev *pci,
}
probe_now = !chip->disabled;
- if (probe_now) {
- err = azx_first_init(chip);
- if (err < 0)
- goto out_free;
- }
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (patch[dev] && *patch[dev]) {
@@ -3769,15 +3798,22 @@ static int azx_probe(struct pci_dev *pci,
}
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+ /* continue probing in work context, avoid request_module deadlock */
+ if (probe_now && (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) {
+#ifdef CONFIG_SND_HDA_I915
+ probe_now = false;
+ schedule_work(&chip->probe_work);
+#else
+ snd_printk(KERN_ERR SFX "Haswell must build in CONFIG_SND_HDA_I915\n");
+#endif
+ }
+
if (probe_now) {
err = azx_probe_continue(chip);
if (err < 0)
goto out_free;
}
- if (pci_dev_run_wake(pci))
- pm_runtime_put_noidle(&pci->dev);
-
dev++;
complete_all(&chip->probe_wait);
return 0;
@@ -3789,9 +3825,24 @@ out_free:
static int azx_probe_continue(struct azx *chip)
{
+ struct pci_dev *pci = chip->pci;
int dev = chip->dev_index;
int err;
+ /* Request power well for Haswell HDA controller and codec */
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+ err = hda_i915_init();
+ if (err < 0) {
+ snd_printk(KERN_ERR SFX "Error request power-well from i915\n");
+ goto out_free;
+ }
+ hda_display_power(true);
+ }
+
+ err = azx_first_init(chip);
+ if (err < 0)
+ goto out_free;
+
#ifdef CONFIG_SND_HDA_INPUT_BEEP
chip->beep_mode = beep_mode[dev];
#endif
@@ -3836,6 +3887,8 @@ 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)
+ pm_runtime_put_noidle(&pci->dev);
return 0;
@@ -3848,9 +3901,6 @@ static void azx_remove(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
- if (pci_dev_run_wake(pci))
- pm_runtime_get_noresume(&pci->dev);
-
if (card)
snd_card_free(card);
}
@@ -3882,11 +3932,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
+ AZX_DCAPS_I915_POWERWELL },
{ PCI_DEVICE(0x8086, 0x0c0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
+ AZX_DCAPS_I915_POWERWELL },
{ PCI_DEVICE(0x8086, 0x0d0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
+ AZX_DCAPS_I915_POWERWELL },
/* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },