diff options
author | Pardha Saradhi K <pardha.saradhi.kesapragada@intel.com> | 2016-11-03 14:37:16 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-11-03 20:14:22 +0300 |
commit | a26a3f53e3d2bfeb666ca31b5f86c65a1816eb89 (patch) | |
tree | 16c2078a2f3aeed82afaf3bddd50e9a7122fc756 /sound/soc/intel/skylake/skl.c | |
parent | 41b7523f192bdf3804e3e18a61f91244e4a0cb25 (diff) | |
download | linux-a26a3f53e3d2bfeb666ca31b5f86c65a1816eb89.tar.xz |
ASoC: Intel: Skylake: Add support for programming D0i3C
To set the controller in D0i3 mode, the driver needs to set D0i3C
register after DSP is quiesced. Since the D0iX entry/exit is done by IPC,
add this as callback so that it can be invoked from IPC module.
Signed-off-by: Pardha Saradhi K <pardha.saradhi.kesapragada@intel.com>
Signed-off-by: Jayachandran B <jayachandran.b@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/intel/skylake/skl.c')
-rw-r--r-- | sound/soc/intel/skylake/skl.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 2989c164dafe..b9209af89915 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,6 +26,7 @@ #include <linux/pm_runtime.h> #include <linux/platform_device.h> #include <linux/firmware.h> +#include <linux/delay.h> #include <sound/pcm.h> #include "../common/sst-acpi.h" #include <sound/hda_register.h> @@ -109,6 +110,52 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset) return ret; } +void skl_update_d0i3c(struct device *dev, bool enable) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + u8 reg; + int timeout = 50; + + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + /* Do not write to D0I3C until command in progress bit is cleared */ + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); + return; + } + + if (enable) + reg = reg | AZX_REG_VS_D0I3C_I3; + else + reg = reg & (~AZX_REG_VS_D0I3C_I3); + + snd_hdac_chip_writeb(bus, VS_D0I3C, reg); + + timeout = 50; + /* Wait for cmd in progress to be cleared before exiting the function */ + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); + return; + } + + dev_dbg(bus->dev, "D0I3C register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); +} + /* called from IRQ */ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) { |