Merge branch 'for-linus' into for-next
[linux-2.6-microblaze.git] / sound / pci / hda / hda_intel.c
index 1e14d72..2af1e08 100644 (file)
@@ -46,6 +46,7 @@
 #include <sound/initval.h>
 #include <sound/hdaudio.h>
 #include <sound/hda_i915.h>
+#include <sound/intel-nhlt.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/firmware.h>
@@ -124,6 +125,7 @@ static char *patch[SNDRV_CARDS];
 static bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
                                        CONFIG_SND_HDA_INPUT_BEEP_MODE};
 #endif
+static bool dmic_detect = IS_ENABLED(CONFIG_SND_HDA_INTEL_DETECT_DMIC);
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -158,6 +160,8 @@ module_param_array(beep_mode, bool, NULL, 0444);
 MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
                            "(0=off, 1=on) (default=1).");
 #endif
+module_param(dmic_detect, bool, 0444);
+MODULE_PARM_DESC(dmic_detect, "DMIC detect on SKL+ platforms");
 
 #ifdef CONFIG_PM
 static int param_set_xint(const char *val, const struct kernel_param *kp);
@@ -266,6 +270,7 @@ enum {
        AZX_DRIVER_CTX,
        AZX_DRIVER_CTHDA,
        AZX_DRIVER_CMEDIA,
+       AZX_DRIVER_ZHAOXIN,
        AZX_DRIVER_GENERIC,
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
@@ -379,6 +384,7 @@ static char *driver_short_names[] = {
        [AZX_DRIVER_CTX] = "HDA Creative", 
        [AZX_DRIVER_CTHDA] = "HDA Creative",
        [AZX_DRIVER_CMEDIA] = "HDA C-Media",
+       [AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin",
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
@@ -1300,9 +1306,9 @@ static int azx_free(struct azx *chip)
        }
 
        if (bus->chip_init) {
+               azx_stop_chip(chip);
                azx_clear_irq_pending(chip);
                azx_stop_all_streams(chip);
-               azx_stop_chip(chip);
        }
 
        if (bus->irq >= 0)
@@ -2024,6 +2030,25 @@ static const struct hda_controller_ops pci_hda_ops = {
        .position_check = azx_position_check,
 };
 
+static int azx_check_dmic(struct pci_dev *pci, struct azx *chip)
+{
+       struct nhlt_acpi_table *nhlt;
+       int ret = 0;
+
+       if (chip->driver_type == AZX_DRIVER_SKL &&
+           pci->class != 0x040300) {
+               nhlt = intel_nhlt_init(&pci->dev);
+               if (nhlt) {
+                       if (intel_nhlt_get_dmic_geo(&pci->dev, nhlt)) {
+                               ret = -ENODEV;
+                               dev_info(&pci->dev, "Digital mics found on Skylake+ platform, aborting probe\n");
+                       }
+                       intel_nhlt_free(nhlt);
+               }
+       }
+       return ret;
+}
+
 static int azx_probe(struct pci_dev *pci,
                     const struct pci_device_id *pci_id)
 {
@@ -2054,6 +2079,17 @@ static int azx_probe(struct pci_dev *pci,
        card->private_data = chip;
        hda = container_of(chip, struct hda_intel, chip);
 
+       /*
+        * stop probe if digital microphones detected on Skylake+ platform
+        * with the DSP enabled. This is an opt-in behavior defined at build
+        * time or at run-time with a module parameter
+        */
+       if (dmic_detect) {
+               err = azx_check_dmic(pci, chip);
+               if (err < 0)
+                       goto out_free;
+       }
+
        pci_set_drvdata(pci, card);
 
        err = register_vga_switcheroo(chip);
@@ -2589,6 +2625,8 @@ static const struct pci_device_id azx_ids[] = {
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
+       /* Zhaoxin */
+       { PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);