POS_FIX_POSBUF,
        POS_FIX_VIACOMBO,
        POS_FIX_COMBO,
+       POS_FIX_SKL,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "DMA pointer read method."
-                "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
+                "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
        return bound_pos + mod_dma_pos;
 }
 
+static unsigned int azx_skl_get_dpib_pos(struct azx *chip,
+                                        struct azx_dev *azx_dev)
+{
+       return _snd_hdac_chip_readl(azx_bus(chip),
+                                   AZX_REG_VS_SDXDPIB_XBASE +
+                                   (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                    azx_dev->core.index));
+}
+
+/* get the current DMA position with correction on SKL+ chips */
+static unsigned int azx_get_pos_skl(struct azx *chip, struct azx_dev *azx_dev)
+{
+       /* DPIB register gives a more accurate position for playback */
+       if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return azx_skl_get_dpib_pos(chip, azx_dev);
+
+       /* For capture, we need to read posbuf, but it requires a delay
+        * for the possible boundary overlap; the read of DPIB fetches the
+        * actual posbuf
+        */
+       udelay(20);
+       azx_skl_get_dpib_pos(chip, azx_dev);
+       return azx_get_pos_posbuf(chip, azx_dev);
+}
+
 #ifdef CONFIG_PM
 static DEFINE_MUTEX(card_list_lock);
 static LIST_HEAD(card_list);
        case POS_FIX_POSBUF:
        case POS_FIX_VIACOMBO:
        case POS_FIX_COMBO:
+       case POS_FIX_SKL:
                return fix;
        }
 
                dev_dbg(chip->card->dev, "Using LPIB position fix\n");
                return POS_FIX_LPIB;
        }
+       if (IS_SKL_PLUS(chip->pci)) {
+               dev_dbg(chip->card->dev, "Using SKL position fix\n");
+               return POS_FIX_SKL;
+       }
        return POS_FIX_AUTO;
 }
 
                [POS_FIX_POSBUF] = azx_get_pos_posbuf,
                [POS_FIX_VIACOMBO] = azx_via_get_position,
                [POS_FIX_COMBO] = azx_get_pos_lpib,
+               [POS_FIX_SKL] = azx_get_pos_skl,
        };
 
        chip->get_position[0] = chip->get_position[1] = callbacks[fix];
        if (fix == POS_FIX_COMBO)
                chip->get_position[1] = NULL;
 
-       if (fix == POS_FIX_POSBUF &&
+       if ((fix == POS_FIX_POSBUF || fix == POS_FIX_SKL) &&
            (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
                chip->get_delay[0] = chip->get_delay[1] =
                        azx_get_delay_from_lpib;