xref: /openbmc/linux/sound/soc/intel/skylake/skl.c (revision a2db8743)
18e8e69d6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d8c2dab8SJeeja KP /*
3d8c2dab8SJeeja KP  *  skl.c - Implementation of ASoC Intel SKL HD Audio driver
4d8c2dab8SJeeja KP  *
5d8c2dab8SJeeja KP  *  Copyright (C) 2014-2015 Intel Corp
6d8c2dab8SJeeja KP  *  Author: Jeeja KP <jeeja.kp@intel.com>
7d8c2dab8SJeeja KP  *
8d8c2dab8SJeeja KP  *  Derived mostly from Intel HDA driver with following copyrights:
9d8c2dab8SJeeja KP  *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
10d8c2dab8SJeeja KP  *                     PeiSen Hou <pshou@realtek.com.tw>
11d8c2dab8SJeeja KP  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12d8c2dab8SJeeja KP  *
13d8c2dab8SJeeja KP  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14d8c2dab8SJeeja KP  */
15d8c2dab8SJeeja KP 
16d8c2dab8SJeeja KP #include <linux/module.h>
17d8c2dab8SJeeja KP #include <linux/pci.h>
18d8c2dab8SJeeja KP #include <linux/pm_runtime.h>
19d8c2dab8SJeeja KP #include <linux/platform_device.h>
20d8018361SVinod Koul #include <linux/firmware.h>
21a26a3f53SPardha Saradhi K #include <linux/delay.h>
22d8c2dab8SJeeja KP #include <sound/pcm.h>
237feb2f78SPierre-Louis Bossart #include <sound/soc-acpi.h>
24cbaa7f0bSPierre-Louis Bossart #include <sound/soc-acpi-intel-match.h>
256980c057SVinod Koul #include <sound/hda_register.h>
266980c057SVinod Koul #include <sound/hdaudio.h>
276980c057SVinod Koul #include <sound/hda_i915.h>
2800deadb5SRakesh Ughreja #include <sound/hda_codec.h>
291169cbf6SPierre-Louis Bossart #include <sound/intel-nhlt.h>
3082d9d54aSJaroslav Kysela #include <sound/intel-dsp-config.h>
31d8c2dab8SJeeja KP #include "skl.h"
320c8ba9d2SJayachandran B #include "skl-sst-dsp.h"
330c8ba9d2SJayachandran B #include "skl-sst-ipc.h"
341169cbf6SPierre-Louis Bossart 
358c4e7c2eSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
366bae5ea9SRakesh Ughreja #include "../../../soc/codecs/hdac_hda.h"
378c4e7c2eSPierre-Louis Bossart #endif
38d82b51c8SPierre-Louis Bossart static int skl_pci_binding;
39d82b51c8SPierre-Louis Bossart module_param_named(pci_binding, skl_pci_binding, int, 0444);
40d82b51c8SPierre-Louis Bossart MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc");
41d8c2dab8SJeeja KP 
42d8c2dab8SJeeja KP /*
43d8c2dab8SJeeja KP  * initialize the PCI registers
44d8c2dab8SJeeja KP  */
skl_update_pci_byte(struct pci_dev * pci,unsigned int reg,unsigned char mask,unsigned char val)45d8c2dab8SJeeja KP static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg,
46d8c2dab8SJeeja KP 			    unsigned char mask, unsigned char val)
47d8c2dab8SJeeja KP {
48d8c2dab8SJeeja KP 	unsigned char data;
49d8c2dab8SJeeja KP 
50d8c2dab8SJeeja KP 	pci_read_config_byte(pci, reg, &data);
51d8c2dab8SJeeja KP 	data &= ~mask;
52d8c2dab8SJeeja KP 	data |= (val & mask);
53d8c2dab8SJeeja KP 	pci_write_config_byte(pci, reg, data);
54d8c2dab8SJeeja KP }
55d8c2dab8SJeeja KP 
skl_init_pci(struct skl_dev * skl)56bcc2a2dcSCezary Rojewski static void skl_init_pci(struct skl_dev *skl)
57d8c2dab8SJeeja KP {
5876f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
59d8c2dab8SJeeja KP 
60d8c2dab8SJeeja KP 	/*
61d8c2dab8SJeeja KP 	 * Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
62d8c2dab8SJeeja KP 	 * TCSEL == Traffic Class Select Register, which sets PCI express QOS
63d8c2dab8SJeeja KP 	 * Ensuring these bits are 0 clears playback static on some HD Audio
64d8c2dab8SJeeja KP 	 * codecs.
65d8c2dab8SJeeja KP 	 * The PCI register TCSEL is defined in the Intel manuals.
66d8c2dab8SJeeja KP 	 */
6776f56faeSRakesh Ughreja 	dev_dbg(bus->dev, "Clearing TCSEL\n");
68d8c2dab8SJeeja KP 	skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
69d8c2dab8SJeeja KP }
70d8c2dab8SJeeja KP 
update_pci_dword(struct pci_dev * pci,unsigned int reg,u32 mask,u32 val)710c8ba9d2SJayachandran B static void update_pci_dword(struct pci_dev *pci,
720c8ba9d2SJayachandran B 			unsigned int reg, u32 mask, u32 val)
730c8ba9d2SJayachandran B {
740c8ba9d2SJayachandran B 	u32 data = 0;
750c8ba9d2SJayachandran B 
760c8ba9d2SJayachandran B 	pci_read_config_dword(pci, reg, &data);
770c8ba9d2SJayachandran B 	data &= ~mask;
780c8ba9d2SJayachandran B 	data |= (val & mask);
790c8ba9d2SJayachandran B 	pci_write_config_dword(pci, reg, data);
800c8ba9d2SJayachandran B }
810c8ba9d2SJayachandran B 
820c8ba9d2SJayachandran B /*
830c8ba9d2SJayachandran B  * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits
840c8ba9d2SJayachandran B  *
850c8ba9d2SJayachandran B  * @dev: device pointer
860c8ba9d2SJayachandran B  * @enable: enable/disable flag
870c8ba9d2SJayachandran B  */
skl_enable_miscbdcge(struct device * dev,bool enable)880c8ba9d2SJayachandran B static void skl_enable_miscbdcge(struct device *dev, bool enable)
890c8ba9d2SJayachandran B {
900c8ba9d2SJayachandran B 	struct pci_dev *pci = to_pci_dev(dev);
910c8ba9d2SJayachandran B 	u32 val;
920c8ba9d2SJayachandran B 
930c8ba9d2SJayachandran B 	val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0;
940c8ba9d2SJayachandran B 
950c8ba9d2SJayachandran B 	update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val);
960c8ba9d2SJayachandran B }
970c8ba9d2SJayachandran B 
98fc9fdd61SSanyog Kale /**
99fc9fdd61SSanyog Kale  * skl_clock_power_gating: Enable/Disable clock and power gating
100fc9fdd61SSanyog Kale  *
101fc9fdd61SSanyog Kale  * @dev: Device pointer
102fc9fdd61SSanyog Kale  * @enable: Enable/Disable flag
103fc9fdd61SSanyog Kale  */
skl_clock_power_gating(struct device * dev,bool enable)104fc9fdd61SSanyog Kale static void skl_clock_power_gating(struct device *dev, bool enable)
105fc9fdd61SSanyog Kale {
106fc9fdd61SSanyog Kale 	struct pci_dev *pci = to_pci_dev(dev);
10776f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
108fc9fdd61SSanyog Kale 	u32 val;
109fc9fdd61SSanyog Kale 
110fc9fdd61SSanyog Kale 	/* Update PDCGE bit of CGCTL register */
111fc9fdd61SSanyog Kale 	val = enable ? AZX_CGCTL_ADSPDCGE : 0;
112fc9fdd61SSanyog Kale 	update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_ADSPDCGE, val);
113fc9fdd61SSanyog Kale 
114fc9fdd61SSanyog Kale 	/* Update L1SEN bit of EM2 register */
115fc9fdd61SSanyog Kale 	val = enable ? AZX_REG_VS_EM2_L1SEN : 0;
116fc9fdd61SSanyog Kale 	snd_hdac_chip_updatel(bus, VS_EM2, AZX_REG_VS_EM2_L1SEN, val);
117fc9fdd61SSanyog Kale 
118fc9fdd61SSanyog Kale 	/* Update ADSPPGD bit of PGCTL register */
119fc9fdd61SSanyog Kale 	val = enable ? 0 : AZX_PGCTL_ADSPPGD;
120fc9fdd61SSanyog Kale 	update_pci_dword(pci, AZX_PCIREG_PGCTL, AZX_PGCTL_ADSPPGD, val);
121fc9fdd61SSanyog Kale }
122fc9fdd61SSanyog Kale 
1230c8ba9d2SJayachandran B /*
1240c8ba9d2SJayachandran B  * While performing reset, controller may not come back properly causing
1250c8ba9d2SJayachandran B  * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset
1260c8ba9d2SJayachandran B  * (init chip) and then again set CGCTL.MISCBDCGE to 1
1270c8ba9d2SJayachandran B  */
skl_init_chip(struct hdac_bus * bus,bool full_reset)1280c8ba9d2SJayachandran B static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
1290c8ba9d2SJayachandran B {
130112c60b3SRakesh Ughreja 	struct hdac_ext_link *hlink;
1310c8ba9d2SJayachandran B 	int ret;
1320c8ba9d2SJayachandran B 
133e603f11dSCezary Rojewski 	snd_hdac_set_codec_wakeup(bus, true);
1340c8ba9d2SJayachandran B 	skl_enable_miscbdcge(bus->dev, false);
1350c8ba9d2SJayachandran B 	ret = snd_hdac_bus_init_chip(bus, full_reset);
136112c60b3SRakesh Ughreja 
137112c60b3SRakesh Ughreja 	/* Reset stream-to-link mapping */
13876f56faeSRakesh Ughreja 	list_for_each_entry(hlink, &bus->hlink_list, list)
13919abfefdSTakashi Iwai 		writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
140112c60b3SRakesh Ughreja 
1410c8ba9d2SJayachandran B 	skl_enable_miscbdcge(bus->dev, true);
142e603f11dSCezary Rojewski 	snd_hdac_set_codec_wakeup(bus, false);
1430c8ba9d2SJayachandran B 
1440c8ba9d2SJayachandran B 	return ret;
1450c8ba9d2SJayachandran B }
1460c8ba9d2SJayachandran B 
skl_update_d0i3c(struct device * dev,bool enable)147a26a3f53SPardha Saradhi K void skl_update_d0i3c(struct device *dev, bool enable)
148a26a3f53SPardha Saradhi K {
149a26a3f53SPardha Saradhi K 	struct pci_dev *pci = to_pci_dev(dev);
15076f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
151a26a3f53SPardha Saradhi K 	u8 reg;
152a26a3f53SPardha Saradhi K 	int timeout = 50;
153a26a3f53SPardha Saradhi K 
154a26a3f53SPardha Saradhi K 	reg = snd_hdac_chip_readb(bus, VS_D0I3C);
155a26a3f53SPardha Saradhi K 	/* Do not write to D0I3C until command in progress bit is cleared */
156a26a3f53SPardha Saradhi K 	while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) {
157a26a3f53SPardha Saradhi K 		udelay(10);
158a26a3f53SPardha Saradhi K 		reg = snd_hdac_chip_readb(bus, VS_D0I3C);
159a26a3f53SPardha Saradhi K 	}
160a26a3f53SPardha Saradhi K 
161a26a3f53SPardha Saradhi K 	/* Highly unlikely. But if it happens, flag error explicitly */
162a26a3f53SPardha Saradhi K 	if (!timeout) {
163a26a3f53SPardha Saradhi K 		dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n");
164a26a3f53SPardha Saradhi K 		return;
165a26a3f53SPardha Saradhi K 	}
166a26a3f53SPardha Saradhi K 
167a26a3f53SPardha Saradhi K 	if (enable)
168a26a3f53SPardha Saradhi K 		reg = reg | AZX_REG_VS_D0I3C_I3;
169a26a3f53SPardha Saradhi K 	else
170a26a3f53SPardha Saradhi K 		reg = reg & (~AZX_REG_VS_D0I3C_I3);
171a26a3f53SPardha Saradhi K 
172a26a3f53SPardha Saradhi K 	snd_hdac_chip_writeb(bus, VS_D0I3C, reg);
173a26a3f53SPardha Saradhi K 
174a26a3f53SPardha Saradhi K 	timeout = 50;
175a26a3f53SPardha Saradhi K 	/* Wait for cmd in progress to be cleared before exiting the function */
176a26a3f53SPardha Saradhi K 	reg = snd_hdac_chip_readb(bus, VS_D0I3C);
177a26a3f53SPardha Saradhi K 	while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) {
178a26a3f53SPardha Saradhi K 		udelay(10);
179a26a3f53SPardha Saradhi K 		reg = snd_hdac_chip_readb(bus, VS_D0I3C);
180a26a3f53SPardha Saradhi K 	}
181a26a3f53SPardha Saradhi K 
182a26a3f53SPardha Saradhi K 	/* Highly unlikely. But if it happens, flag error explicitly */
183a26a3f53SPardha Saradhi K 	if (!timeout) {
184a26a3f53SPardha Saradhi K 		dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n");
185a26a3f53SPardha Saradhi K 		return;
186a26a3f53SPardha Saradhi K 	}
187a26a3f53SPardha Saradhi K 
188a26a3f53SPardha Saradhi K 	dev_dbg(bus->dev, "D0I3C register = 0x%x\n",
189a26a3f53SPardha Saradhi K 			snd_hdac_chip_readb(bus, VS_D0I3C));
190a26a3f53SPardha Saradhi K }
191a26a3f53SPardha Saradhi K 
1927a1954deSCezary Rojewski /**
1937a1954deSCezary Rojewski  * skl_dum_set - set DUM bit in EM2 register
1947a1954deSCezary Rojewski  * @bus: HD-audio core bus
1957a1954deSCezary Rojewski  *
1967a1954deSCezary Rojewski  * Addresses incorrect position reporting for capture streams.
1977a1954deSCezary Rojewski  * Used on device power up.
1987a1954deSCezary Rojewski  */
skl_dum_set(struct hdac_bus * bus)1997a1954deSCezary Rojewski static void skl_dum_set(struct hdac_bus *bus)
2007a1954deSCezary Rojewski {
2017a1954deSCezary Rojewski 	/* For the DUM bit to be set, CRST needs to be out of reset state */
2027a1954deSCezary Rojewski 	if (!(snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)) {
2037a1954deSCezary Rojewski 		skl_enable_miscbdcge(bus->dev, false);
2047a1954deSCezary Rojewski 		snd_hdac_bus_exit_link_reset(bus);
2057a1954deSCezary Rojewski 		skl_enable_miscbdcge(bus->dev, true);
2067a1954deSCezary Rojewski 	}
2077a1954deSCezary Rojewski 
2087a1954deSCezary Rojewski 	snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM);
2097a1954deSCezary Rojewski }
2107a1954deSCezary Rojewski 
211d8c2dab8SJeeja KP /* called from IRQ */
skl_stream_update(struct hdac_bus * bus,struct hdac_stream * hstr)212d8c2dab8SJeeja KP static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
213d8c2dab8SJeeja KP {
214d8c2dab8SJeeja KP 	snd_pcm_period_elapsed(hstr->substream);
215d8c2dab8SJeeja KP }
216d8c2dab8SJeeja KP 
skl_interrupt(int irq,void * dev_id)217d8c2dab8SJeeja KP static irqreturn_t skl_interrupt(int irq, void *dev_id)
218d8c2dab8SJeeja KP {
21976f56faeSRakesh Ughreja 	struct hdac_bus *bus = dev_id;
220d8c2dab8SJeeja KP 	u32 status;
221d8c2dab8SJeeja KP 
222d8c2dab8SJeeja KP 	if (!pm_runtime_active(bus->dev))
223d8c2dab8SJeeja KP 		return IRQ_NONE;
224d8c2dab8SJeeja KP 
225d8c2dab8SJeeja KP 	spin_lock(&bus->reg_lock);
226d8c2dab8SJeeja KP 
227d8c2dab8SJeeja KP 	status = snd_hdac_chip_readl(bus, INTSTS);
228d8c2dab8SJeeja KP 	if (status == 0 || status == 0xffffffff) {
229d8c2dab8SJeeja KP 		spin_unlock(&bus->reg_lock);
230d8c2dab8SJeeja KP 		return IRQ_NONE;
231d8c2dab8SJeeja KP 	}
232d8c2dab8SJeeja KP 
233d8c2dab8SJeeja KP 	/* clear rirb int */
234d8c2dab8SJeeja KP 	status = snd_hdac_chip_readb(bus, RIRBSTS);
235d8c2dab8SJeeja KP 	if (status & RIRB_INT_MASK) {
236d8c2dab8SJeeja KP 		if (status & RIRB_INT_RESPONSE)
237d8c2dab8SJeeja KP 			snd_hdac_bus_update_rirb(bus);
238d8c2dab8SJeeja KP 		snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
239d8c2dab8SJeeja KP 	}
240d8c2dab8SJeeja KP 
241d8c2dab8SJeeja KP 	spin_unlock(&bus->reg_lock);
242d8c2dab8SJeeja KP 
243d8c2dab8SJeeja KP 	return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
244d8c2dab8SJeeja KP }
245d8c2dab8SJeeja KP 
skl_threaded_handler(int irq,void * dev_id)246d8c2dab8SJeeja KP static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
247d8c2dab8SJeeja KP {
24876f56faeSRakesh Ughreja 	struct hdac_bus *bus = dev_id;
249d8c2dab8SJeeja KP 	u32 status;
250d8c2dab8SJeeja KP 
251d8c2dab8SJeeja KP 	status = snd_hdac_chip_readl(bus, INTSTS);
252d8c2dab8SJeeja KP 
253d8c2dab8SJeeja KP 	snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update);
254d8c2dab8SJeeja KP 
255d8c2dab8SJeeja KP 	return IRQ_HANDLED;
256d8c2dab8SJeeja KP }
257d8c2dab8SJeeja KP 
skl_acquire_irq(struct hdac_bus * bus,int do_disconnect)25876f56faeSRakesh Ughreja static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect)
259d8c2dab8SJeeja KP {
260bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
261d8c2dab8SJeeja KP 	int ret;
262d8c2dab8SJeeja KP 
263d8c2dab8SJeeja KP 	ret = request_threaded_irq(skl->pci->irq, skl_interrupt,
264d8c2dab8SJeeja KP 			skl_threaded_handler,
265d8c2dab8SJeeja KP 			IRQF_SHARED,
26676f56faeSRakesh Ughreja 			KBUILD_MODNAME, bus);
267d8c2dab8SJeeja KP 	if (ret) {
268d8c2dab8SJeeja KP 		dev_err(bus->dev,
269d8c2dab8SJeeja KP 			"unable to grab IRQ %d, disabling device\n",
270d8c2dab8SJeeja KP 			skl->pci->irq);
271d8c2dab8SJeeja KP 		return ret;
272d8c2dab8SJeeja KP 	}
273d8c2dab8SJeeja KP 
274d8c2dab8SJeeja KP 	bus->irq = skl->pci->irq;
275d8c2dab8SJeeja KP 	pci_intx(skl->pci, 1);
276d8c2dab8SJeeja KP 
277d8c2dab8SJeeja KP 	return 0;
278d8c2dab8SJeeja KP }
279d8c2dab8SJeeja KP 
skl_suspend_late(struct device * dev)2808b4a133cSJayachandran B static int skl_suspend_late(struct device *dev)
2818b4a133cSJayachandran B {
2828b4a133cSJayachandran B 	struct pci_dev *pci = to_pci_dev(dev);
28376f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
284bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
2858b4a133cSJayachandran B 
2868b4a133cSJayachandran B 	return skl_suspend_late_dsp(skl);
2878b4a133cSJayachandran B }
2888b4a133cSJayachandran B 
289d8c2dab8SJeeja KP #ifdef CONFIG_PM
_skl_suspend(struct hdac_bus * bus)29076f56faeSRakesh Ughreja static int _skl_suspend(struct hdac_bus *bus)
291d8c2dab8SJeeja KP {
292bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
29351a01b8cSDharageswari R 	struct pci_dev *pci = to_pci_dev(bus->dev);
2942a29b200SJeeja KP 	int ret;
295d8c2dab8SJeeja KP 
29676f56faeSRakesh Ughreja 	snd_hdac_ext_bus_link_power_down_all(bus);
29701bb84b5SJeeja KP 
2982a29b200SJeeja KP 	ret = skl_suspend_dsp(skl);
2992a29b200SJeeja KP 	if (ret < 0)
3002a29b200SJeeja KP 		return ret;
301d8c2dab8SJeeja KP 
302d8c2dab8SJeeja KP 	snd_hdac_bus_stop_chip(bus);
30351a01b8cSDharageswari R 	update_pci_dword(pci, AZX_PCIREG_PGCTL,
30451a01b8cSDharageswari R 		AZX_PGCTL_LSRMD_MASK, AZX_PGCTL_LSRMD_MASK);
3050c8ba9d2SJayachandran B 	skl_enable_miscbdcge(bus->dev, false);
306d8c2dab8SJeeja KP 	snd_hdac_bus_enter_link_reset(bus);
3070c8ba9d2SJayachandran B 	skl_enable_miscbdcge(bus->dev, true);
308fe3f4442SDharageswari R 	skl_cleanup_resources(skl);
309d8c2dab8SJeeja KP 
310d8c2dab8SJeeja KP 	return 0;
311d8c2dab8SJeeja KP }
312d8c2dab8SJeeja KP 
_skl_resume(struct hdac_bus * bus)31376f56faeSRakesh Ughreja static int _skl_resume(struct hdac_bus *bus)
31461722f44SJeeja KP {
315bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
31661722f44SJeeja KP 
31761722f44SJeeja KP 	skl_init_pci(skl);
3187a1954deSCezary Rojewski 	skl_dum_set(bus);
3190c8ba9d2SJayachandran B 	skl_init_chip(bus, true);
32061722f44SJeeja KP 
32161722f44SJeeja KP 	return skl_resume_dsp(skl);
32261722f44SJeeja KP }
32361722f44SJeeja KP #endif
32461722f44SJeeja KP 
32561722f44SJeeja KP #ifdef CONFIG_PM_SLEEP
32661722f44SJeeja KP /*
32761722f44SJeeja KP  * power management
32861722f44SJeeja KP  */
skl_suspend(struct device * dev)32961722f44SJeeja KP static int skl_suspend(struct device *dev)
33061722f44SJeeja KP {
33161722f44SJeeja KP 	struct pci_dev *pci = to_pci_dev(dev);
33276f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
333bcc2a2dcSCezary Rojewski 	struct skl_dev *skl  = bus_to_skl(bus);
3344f799e73STakashi Iwai 	int ret;
33561722f44SJeeja KP 
3364557c305SJeeja KP 	/*
3374557c305SJeeja KP 	 * Do not suspend if streams which are marked ignore suspend are
3384557c305SJeeja KP 	 * running, we need to save the state for these and continue
3394557c305SJeeja KP 	 */
3404557c305SJeeja KP 	if (skl->supend_active) {
341cce6c149SVinod Koul 		/* turn off the links and stop the CORB/RIRB DMA if it is On */
34276f56faeSRakesh Ughreja 		snd_hdac_ext_bus_link_power_down_all(bus);
343cce6c149SVinod Koul 
34476f56faeSRakesh Ughreja 		if (bus->cmd_dma_state)
34576f56faeSRakesh Ughreja 			snd_hdac_bus_stop_cmd_io(bus);
346cce6c149SVinod Koul 
3471f4956fdSJeeja KP 		enable_irq_wake(bus->irq);
3484557c305SJeeja KP 		pci_save_state(pci);
3494557c305SJeeja KP 	} else {
35076f56faeSRakesh Ughreja 		ret = _skl_suspend(bus);
351af037412SSubhransu S. Prusty 		if (ret < 0)
352af037412SSubhransu S. Prusty 			return ret;
353bcc2a2dcSCezary Rojewski 		skl->fw_loaded = false;
35461722f44SJeeja KP 	}
355af037412SSubhransu S. Prusty 
3564f799e73STakashi Iwai 	return 0;
3574557c305SJeeja KP }
35861722f44SJeeja KP 
skl_resume(struct device * dev)35961722f44SJeeja KP static int skl_resume(struct device *dev)
36061722f44SJeeja KP {
36161722f44SJeeja KP 	struct pci_dev *pci = to_pci_dev(dev);
36276f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
363bcc2a2dcSCezary Rojewski 	struct skl_dev *skl  = bus_to_skl(bus);
364ca841843SGuennadi Liakhovetski 	struct hdac_ext_link *hlink;
3654557c305SJeeja KP 	int ret;
36661722f44SJeeja KP 
3674557c305SJeeja KP 	/*
3684557c305SJeeja KP 	 * resume only when we are not in suspend active, otherwise need to
3694557c305SJeeja KP 	 * restore the device
3704557c305SJeeja KP 	 */
3714557c305SJeeja KP 	if (skl->supend_active) {
3724557c305SJeeja KP 		pci_restore_state(pci);
37376f56faeSRakesh Ughreja 		snd_hdac_ext_bus_link_power_up_all(bus);
3741f4956fdSJeeja KP 		disable_irq_wake(bus->irq);
375cce6c149SVinod Koul 		/*
376cce6c149SVinod Koul 		 * turn On the links which are On before active suspend
377cce6c149SVinod Koul 		 * and start the CORB/RIRB DMA if On before
378cce6c149SVinod Koul 		 * active suspend.
379cce6c149SVinod Koul 		 */
38076f56faeSRakesh Ughreja 		list_for_each_entry(hlink, &bus->hlink_list, list) {
381cce6c149SVinod Koul 			if (hlink->ref_count)
382cce6c149SVinod Koul 				snd_hdac_ext_bus_link_power_up(hlink);
383cce6c149SVinod Koul 		}
384cce6c149SVinod Koul 
385cc20c4dfSArnd Bergmann 		ret = 0;
38676f56faeSRakesh Ughreja 		if (bus->cmd_dma_state)
38776f56faeSRakesh Ughreja 			snd_hdac_bus_init_cmd_io(bus);
3884557c305SJeeja KP 	} else {
38976f56faeSRakesh Ughreja 		ret = _skl_resume(bus);
3904557c305SJeeja KP 	}
3914557c305SJeeja KP 
3924557c305SJeeja KP 	return ret;
39361722f44SJeeja KP }
39461722f44SJeeja KP #endif /* CONFIG_PM_SLEEP */
39561722f44SJeeja KP 
39661722f44SJeeja KP #ifdef CONFIG_PM
skl_runtime_suspend(struct device * dev)39761722f44SJeeja KP static int skl_runtime_suspend(struct device *dev)
39861722f44SJeeja KP {
39961722f44SJeeja KP 	struct pci_dev *pci = to_pci_dev(dev);
40076f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
40161722f44SJeeja KP 
40261722f44SJeeja KP 	dev_dbg(bus->dev, "in %s\n", __func__);
40361722f44SJeeja KP 
40476f56faeSRakesh Ughreja 	return _skl_suspend(bus);
40561722f44SJeeja KP }
40661722f44SJeeja KP 
skl_runtime_resume(struct device * dev)407d8c2dab8SJeeja KP static int skl_runtime_resume(struct device *dev)
408d8c2dab8SJeeja KP {
409d8c2dab8SJeeja KP 	struct pci_dev *pci = to_pci_dev(dev);
41076f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
411d8c2dab8SJeeja KP 
412d8c2dab8SJeeja KP 	dev_dbg(bus->dev, "in %s\n", __func__);
413d8c2dab8SJeeja KP 
41476f56faeSRakesh Ughreja 	return _skl_resume(bus);
415d8c2dab8SJeeja KP }
416d8c2dab8SJeeja KP #endif /* CONFIG_PM */
417d8c2dab8SJeeja KP 
418d8c2dab8SJeeja KP static const struct dev_pm_ops skl_pm = {
419d8c2dab8SJeeja KP 	SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume)
420d8c2dab8SJeeja KP 	SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL)
4218b4a133cSJayachandran B 	.suspend_late = skl_suspend_late,
422d8c2dab8SJeeja KP };
423d8c2dab8SJeeja KP 
424d8c2dab8SJeeja KP /*
425d8c2dab8SJeeja KP  * destructor
426d8c2dab8SJeeja KP  */
skl_free(struct hdac_bus * bus)42776f56faeSRakesh Ughreja static int skl_free(struct hdac_bus *bus)
428d8c2dab8SJeeja KP {
429bcc2a2dcSCezary Rojewski 	struct skl_dev *skl  = bus_to_skl(bus);
430d8c2dab8SJeeja KP 
431ab1b732dSVinod Koul 	skl->init_done = 0; /* to be sure */
432d8c2dab8SJeeja KP 
43312054f0cSPierre-Louis Bossart 	snd_hdac_stop_streams_and_chip(bus);
434d8c2dab8SJeeja KP 
435d8c2dab8SJeeja KP 	if (bus->irq >= 0)
43676f56faeSRakesh Ughreja 		free_irq(bus->irq, (void *)bus);
437d8c2dab8SJeeja KP 	snd_hdac_bus_free_stream_pages(bus);
4380839a04eSPierre-Louis Bossart 	snd_hdac_ext_stream_free_all(bus);
4397f05ca9aSPierre-Louis Bossart 	snd_hdac_ext_link_free_all(bus);
440077411e5SVinod Koul 
441077411e5SVinod Koul 	if (bus->remap_addr)
442077411e5SVinod Koul 		iounmap(bus->remap_addr);
443077411e5SVinod Koul 
444d8c2dab8SJeeja KP 	pci_release_regions(skl->pci);
445d8c2dab8SJeeja KP 	pci_disable_device(skl->pci);
446d8c2dab8SJeeja KP 
44776f56faeSRakesh Ughreja 	snd_hdac_ext_bus_exit(bus);
448d8c2dab8SJeeja KP 
449687ae9e2STakashi Iwai 	if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
450687ae9e2STakashi Iwai 		snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
45176f56faeSRakesh Ughreja 		snd_hdac_i915_exit(bus);
452687ae9e2STakashi Iwai 	}
453ab1b732dSVinod Koul 
454d8c2dab8SJeeja KP 	return 0;
455d8c2dab8SJeeja KP }
456d8c2dab8SJeeja KP 
457bc2bd45bSSriram Periyasamy /*
458bc2bd45bSSriram Periyasamy  * For each ssp there are 3 clocks (mclk/sclk/sclkfs).
459bc2bd45bSSriram Periyasamy  * e.g. for ssp0, clocks will be named as
460bc2bd45bSSriram Periyasamy  *      "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs"
461bc2bd45bSSriram Periyasamy  * So for skl+, there are 6 ssps, so 18 clocks will be created.
462bc2bd45bSSriram Periyasamy  */
463bc2bd45bSSriram Periyasamy static struct skl_ssp_clk skl_ssp_clks[] = {
464bc2bd45bSSriram Periyasamy 	{.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"},
465bc2bd45bSSriram Periyasamy 	{.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"},
466bc2bd45bSSriram Periyasamy 	{.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"},
467bc2bd45bSSriram Periyasamy 	{.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"},
468bc2bd45bSSriram Periyasamy 	{.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"},
469bc2bd45bSSriram Periyasamy 						{.name = "ssp2_sclkfs"},
470bc2bd45bSSriram Periyasamy 	{.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"},
471bc2bd45bSSriram Periyasamy 						{.name = "ssp5_sclkfs"},
472bc2bd45bSSriram Periyasamy };
473bc2bd45bSSriram Periyasamy 
skl_find_hda_machine(struct skl_dev * skl,struct snd_soc_acpi_mach * machines)474bcc2a2dcSCezary Rojewski static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl_dev *skl,
4759cdae435SRakesh Ughreja 					struct snd_soc_acpi_mach *machines)
4769cdae435SRakesh Ughreja {
4779cdae435SRakesh Ughreja 	struct snd_soc_acpi_mach *mach;
4789cdae435SRakesh Ughreja 
4799cdae435SRakesh Ughreja 	/* point to common table */
4809cdae435SRakesh Ughreja 	mach = snd_soc_acpi_intel_hda_machines;
4819cdae435SRakesh Ughreja 
4829cdae435SRakesh Ughreja 	/* all entries in the machine table use the same firmware */
4839cdae435SRakesh Ughreja 	mach->fw_filename = machines->fw_filename;
4849cdae435SRakesh Ughreja 
4859cdae435SRakesh Ughreja 	return mach;
4869cdae435SRakesh Ughreja }
4879cdae435SRakesh Ughreja 
skl_find_machine(struct skl_dev * skl,void * driver_data)488bcc2a2dcSCezary Rojewski static int skl_find_machine(struct skl_dev *skl, void *driver_data)
489cc18c5fdSVinod Koul {
49076f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
4917feb2f78SPierre-Louis Bossart 	struct snd_soc_acpi_mach *mach = driver_data;
492752c93aaSPankaj Bharadiya 	struct skl_machine_pdata *pdata;
493cc18c5fdSVinod Koul 
4947feb2f78SPierre-Louis Bossart 	mach = snd_soc_acpi_find_machine(mach);
4959cdae435SRakesh Ughreja 	if (!mach) {
4969cdae435SRakesh Ughreja 		dev_dbg(bus->dev, "No matching I2S machine driver found\n");
4979cdae435SRakesh Ughreja 		mach = skl_find_hda_machine(skl, driver_data);
4989cdae435SRakesh Ughreja 		if (!mach) {
499cc18c5fdSVinod Koul 			dev_err(bus->dev, "No matching machine driver found\n");
500cc18c5fdSVinod Koul 			return -ENODEV;
501cc18c5fdSVinod Koul 		}
5029cdae435SRakesh Ughreja 	}
503752c93aaSPankaj Bharadiya 
504752c93aaSPankaj Bharadiya 	skl->mach = mach;
505aecf6fd8SVinod Koul 	skl->fw_name = mach->fw_filename;
5065f15f267SPierre-Louis Bossart 	pdata = mach->pdata;
507752c93aaSPankaj Bharadiya 
5085f15f267SPierre-Louis Bossart 	if (pdata) {
509752c93aaSPankaj Bharadiya 		skl->use_tplg_pcm = pdata->use_tplg_pcm;
5101169cbf6SPierre-Louis Bossart 		mach->mach_params.dmic_num =
5111169cbf6SPierre-Louis Bossart 			intel_nhlt_get_dmic_geo(&skl->pci->dev,
5121169cbf6SPierre-Louis Bossart 						skl->nhlt);
5135f15f267SPierre-Louis Bossart 	}
514752c93aaSPankaj Bharadiya 
515752c93aaSPankaj Bharadiya 	return 0;
516752c93aaSPankaj Bharadiya }
517752c93aaSPankaj Bharadiya 
skl_machine_device_register(struct skl_dev * skl)518bcc2a2dcSCezary Rojewski static int skl_machine_device_register(struct skl_dev *skl)
519752c93aaSPankaj Bharadiya {
520752c93aaSPankaj Bharadiya 	struct snd_soc_acpi_mach *mach = skl->mach;
5219cdae435SRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
522752c93aaSPankaj Bharadiya 	struct platform_device *pdev;
523752c93aaSPankaj Bharadiya 	int ret;
524cc18c5fdSVinod Koul 
525cc18c5fdSVinod Koul 	pdev = platform_device_alloc(mach->drv_name, -1);
526cc18c5fdSVinod Koul 	if (pdev == NULL) {
527cc18c5fdSVinod Koul 		dev_err(bus->dev, "platform device alloc failed\n");
528cc18c5fdSVinod Koul 		return -EIO;
529cc18c5fdSVinod Koul 	}
530cc18c5fdSVinod Koul 
5315a619b9eSPierre-Louis Bossart 	mach->mach_params.platform = dev_name(bus->dev);
5325a619b9eSPierre-Louis Bossart 	mach->mach_params.codec_mask = bus->codec_mask;
5335a619b9eSPierre-Louis Bossart 
5345a619b9eSPierre-Louis Bossart 	ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach));
5355a619b9eSPierre-Louis Bossart 	if (ret) {
5365a619b9eSPierre-Louis Bossart 		dev_err(bus->dev, "failed to add machine device platform data\n");
5375a619b9eSPierre-Louis Bossart 		platform_device_put(pdev);
5385a619b9eSPierre-Louis Bossart 		return ret;
5395a619b9eSPierre-Louis Bossart 	}
5405a619b9eSPierre-Louis Bossart 
541cc18c5fdSVinod Koul 	ret = platform_device_add(pdev);
542cc18c5fdSVinod Koul 	if (ret) {
543cc18c5fdSVinod Koul 		dev_err(bus->dev, "failed to add machine device\n");
544cc18c5fdSVinod Koul 		platform_device_put(pdev);
545cc18c5fdSVinod Koul 		return -EIO;
546cc18c5fdSVinod Koul 	}
547f65cf7d6SYong Zhi 
548f65cf7d6SYong Zhi 
549cc18c5fdSVinod Koul 	skl->i2s_dev = pdev;
550cc18c5fdSVinod Koul 
551cc18c5fdSVinod Koul 	return 0;
552cc18c5fdSVinod Koul }
553cc18c5fdSVinod Koul 
skl_machine_device_unregister(struct skl_dev * skl)554bcc2a2dcSCezary Rojewski static void skl_machine_device_unregister(struct skl_dev *skl)
555cc18c5fdSVinod Koul {
556cc18c5fdSVinod Koul 	if (skl->i2s_dev)
557cc18c5fdSVinod Koul 		platform_device_unregister(skl->i2s_dev);
558cc18c5fdSVinod Koul }
559cc18c5fdSVinod Koul 
skl_dmic_device_register(struct skl_dev * skl)560bcc2a2dcSCezary Rojewski static int skl_dmic_device_register(struct skl_dev *skl)
561d8c2dab8SJeeja KP {
56276f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
563d8c2dab8SJeeja KP 	struct platform_device *pdev;
564d8c2dab8SJeeja KP 	int ret;
565d8c2dab8SJeeja KP 
566d8c2dab8SJeeja KP 	/* SKL has one dmic port, so allocate dmic device for this */
567d8c2dab8SJeeja KP 	pdev = platform_device_alloc("dmic-codec", -1);
568d8c2dab8SJeeja KP 	if (!pdev) {
569d8c2dab8SJeeja KP 		dev_err(bus->dev, "failed to allocate dmic device\n");
570d8c2dab8SJeeja KP 		return -ENOMEM;
571d8c2dab8SJeeja KP 	}
572d8c2dab8SJeeja KP 
573d8c2dab8SJeeja KP 	ret = platform_device_add(pdev);
574d8c2dab8SJeeja KP 	if (ret) {
575d8c2dab8SJeeja KP 		dev_err(bus->dev, "failed to add dmic device: %d\n", ret);
576d8c2dab8SJeeja KP 		platform_device_put(pdev);
577d8c2dab8SJeeja KP 		return ret;
578d8c2dab8SJeeja KP 	}
579d8c2dab8SJeeja KP 	skl->dmic_dev = pdev;
580d8c2dab8SJeeja KP 
581d8c2dab8SJeeja KP 	return 0;
582d8c2dab8SJeeja KP }
583d8c2dab8SJeeja KP 
skl_dmic_device_unregister(struct skl_dev * skl)584bcc2a2dcSCezary Rojewski static void skl_dmic_device_unregister(struct skl_dev *skl)
585d8c2dab8SJeeja KP {
586d8c2dab8SJeeja KP 	if (skl->dmic_dev)
587d8c2dab8SJeeja KP 		platform_device_unregister(skl->dmic_dev);
588d8c2dab8SJeeja KP }
589d8c2dab8SJeeja KP 
590bc2bd45bSSriram Periyasamy static struct skl_clk_parent_src skl_clk_src[] = {
591bc2bd45bSSriram Periyasamy 	{ .clk_id = SKL_XTAL, .name = "xtal" },
592bc2bd45bSSriram Periyasamy 	{ .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 },
593bc2bd45bSSriram Periyasamy 	{ .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 },
594bc2bd45bSSriram Periyasamy };
595bc2bd45bSSriram Periyasamy 
skl_get_parent_clk(u8 clk_id)596bc2bd45bSSriram Periyasamy struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
597bc2bd45bSSriram Periyasamy {
598bc2bd45bSSriram Periyasamy 	unsigned int i;
599bc2bd45bSSriram Periyasamy 
600bc2bd45bSSriram Periyasamy 	for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) {
601bc2bd45bSSriram Periyasamy 		if (skl_clk_src[i].clk_id == clk_id)
602bc2bd45bSSriram Periyasamy 			return &skl_clk_src[i];
603bc2bd45bSSriram Periyasamy 	}
604bc2bd45bSSriram Periyasamy 
605bc2bd45bSSriram Periyasamy 	return NULL;
606bc2bd45bSSriram Periyasamy }
607bc2bd45bSSriram Periyasamy 
init_skl_xtal_rate(int pci_id)6088e79ec98SGuneshwor Singh static void init_skl_xtal_rate(int pci_id)
609bc2bd45bSSriram Periyasamy {
610bc2bd45bSSriram Periyasamy 	switch (pci_id) {
611*a2db8743SAmadeusz Sławiński 	case PCI_DEVICE_ID_INTEL_HDA_SKL_LP:
612*a2db8743SAmadeusz Sławiński 	case PCI_DEVICE_ID_INTEL_HDA_KBL_LP:
613bc2bd45bSSriram Periyasamy 		skl_clk_src[0].rate = 24000000;
614bc2bd45bSSriram Periyasamy 		return;
615bc2bd45bSSriram Periyasamy 
616bc2bd45bSSriram Periyasamy 	default:
617bc2bd45bSSriram Periyasamy 		skl_clk_src[0].rate = 19200000;
618bc2bd45bSSriram Periyasamy 		return;
619bc2bd45bSSriram Periyasamy 	}
620bc2bd45bSSriram Periyasamy }
621bc2bd45bSSriram Periyasamy 
skl_clock_device_register(struct skl_dev * skl)622bcc2a2dcSCezary Rojewski static int skl_clock_device_register(struct skl_dev *skl)
623bc2bd45bSSriram Periyasamy {
624bc2bd45bSSriram Periyasamy 	struct platform_device_info pdevinfo = {NULL};
625bc2bd45bSSriram Periyasamy 	struct skl_clk_pdata *clk_pdata;
626bc2bd45bSSriram Periyasamy 
6279e6c382fSCezary Rojewski 	if (!skl->nhlt)
6289e6c382fSCezary Rojewski 		return 0;
6299e6c382fSCezary Rojewski 
630bc2bd45bSSriram Periyasamy 	clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata),
631bc2bd45bSSriram Periyasamy 							GFP_KERNEL);
632bc2bd45bSSriram Periyasamy 	if (!clk_pdata)
633bc2bd45bSSriram Periyasamy 		return -ENOMEM;
634bc2bd45bSSriram Periyasamy 
635bc2bd45bSSriram Periyasamy 	init_skl_xtal_rate(skl->pci->device);
636bc2bd45bSSriram Periyasamy 
637bc2bd45bSSriram Periyasamy 	clk_pdata->parent_clks = skl_clk_src;
638bc2bd45bSSriram Periyasamy 	clk_pdata->ssp_clks = skl_ssp_clks;
639bc2bd45bSSriram Periyasamy 	clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks);
640bc2bd45bSSriram Periyasamy 
641bc2bd45bSSriram Periyasamy 	/* Query NHLT to fill the rates and parent */
642bc2bd45bSSriram Periyasamy 	skl_get_clks(skl, clk_pdata->ssp_clks);
643bc2bd45bSSriram Periyasamy 	clk_pdata->pvt_data = skl;
644bc2bd45bSSriram Periyasamy 
645bc2bd45bSSriram Periyasamy 	/* Register Platform device */
646bc2bd45bSSriram Periyasamy 	pdevinfo.parent = &skl->pci->dev;
647bc2bd45bSSriram Periyasamy 	pdevinfo.id = -1;
648bc2bd45bSSriram Periyasamy 	pdevinfo.name = "skl-ssp-clk";
649bc2bd45bSSriram Periyasamy 	pdevinfo.data = clk_pdata;
650bc2bd45bSSriram Periyasamy 	pdevinfo.size_data = sizeof(*clk_pdata);
651bc2bd45bSSriram Periyasamy 	skl->clk_dev = platform_device_register_full(&pdevinfo);
652bc2bd45bSSriram Periyasamy 	return PTR_ERR_OR_ZERO(skl->clk_dev);
653bc2bd45bSSriram Periyasamy }
654bc2bd45bSSriram Periyasamy 
skl_clock_device_unregister(struct skl_dev * skl)655bcc2a2dcSCezary Rojewski static void skl_clock_device_unregister(struct skl_dev *skl)
656bc2bd45bSSriram Periyasamy {
657bc2bd45bSSriram Periyasamy 	if (skl->clk_dev)
658bc2bd45bSSriram Periyasamy 		platform_device_unregister(skl->clk_dev);
659bc2bd45bSSriram Periyasamy }
660bc2bd45bSSriram Periyasamy 
6618c4e7c2eSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
6628c4e7c2eSPierre-Louis Bossart 
6636bae5ea9SRakesh Ughreja #define IDISP_INTEL_VENDOR_ID	0x80860000
6646bae5ea9SRakesh Ughreja 
6656bae5ea9SRakesh Ughreja /*
6666bae5ea9SRakesh Ughreja  * load the legacy codec driver
6676bae5ea9SRakesh Ughreja  */
load_codec_module(struct hda_codec * codec)6686bae5ea9SRakesh Ughreja static void load_codec_module(struct hda_codec *codec)
6696bae5ea9SRakesh Ughreja {
6706bae5ea9SRakesh Ughreja #ifdef MODULE
6716bae5ea9SRakesh Ughreja 	char modalias[MODULE_NAME_LEN];
6726bae5ea9SRakesh Ughreja 	const char *mod = NULL;
6736bae5ea9SRakesh Ughreja 
6746bae5ea9SRakesh Ughreja 	snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias));
6756bae5ea9SRakesh Ughreja 	mod = modalias;
6766bae5ea9SRakesh Ughreja 	dev_dbg(&codec->core.dev, "loading %s codec module\n", mod);
6776bae5ea9SRakesh Ughreja 	request_module(mod);
6786bae5ea9SRakesh Ughreja #endif
6796bae5ea9SRakesh Ughreja }
6806bae5ea9SRakesh Ughreja 
6818c4e7c2eSPierre-Louis Bossart #endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */
6828c4e7c2eSPierre-Louis Bossart 
skl_codec_device_init(struct hdac_bus * bus,int addr)6833fd63658SCezary Rojewski static struct hda_codec *skl_codec_device_init(struct hdac_bus *bus, int addr)
684e4746d94SCezary Rojewski {
685e4746d94SCezary Rojewski 	struct hda_codec *codec;
686e4746d94SCezary Rojewski 	int ret;
687e4746d94SCezary Rojewski 
688e4746d94SCezary Rojewski 	codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr);
689e4746d94SCezary Rojewski 	if (IS_ERR(codec)) {
690e4746d94SCezary Rojewski 		dev_err(bus->dev, "device init failed for hdac device\n");
691e4746d94SCezary Rojewski 		return codec;
692e4746d94SCezary Rojewski 	}
693e4746d94SCezary Rojewski 
694e4746d94SCezary Rojewski 	codec->core.type = HDA_DEV_ASOC;
695e4746d94SCezary Rojewski 
696e4746d94SCezary Rojewski 	ret = snd_hdac_device_register(&codec->core);
697e4746d94SCezary Rojewski 	if (ret) {
698e4746d94SCezary Rojewski 		dev_err(bus->dev, "failed to register hdac device\n");
6990aa60ddcSYang Yingliang 		put_device(&codec->core.dev);
700e4746d94SCezary Rojewski 		return ERR_PTR(ret);
701e4746d94SCezary Rojewski 	}
702e4746d94SCezary Rojewski 
703e4746d94SCezary Rojewski 	return codec;
704e4746d94SCezary Rojewski }
705e4746d94SCezary Rojewski 
706d8c2dab8SJeeja KP /*
707d8c2dab8SJeeja KP  * Probe the given codec address
708d8c2dab8SJeeja KP  */
probe_codec(struct hdac_bus * bus,int addr)70976f56faeSRakesh Ughreja static int probe_codec(struct hdac_bus *bus, int addr)
710d8c2dab8SJeeja KP {
711d8c2dab8SJeeja KP 	unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
712d8c2dab8SJeeja KP 		(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
713e6a33532SDan Carpenter 	unsigned int res = -1;
7148c4e7c2eSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
715a74bfc9eSGaosheng Cui 	struct skl_dev *skl = bus_to_skl(bus);
7166bae5ea9SRakesh Ughreja 	struct hdac_hda_priv *hda_codec;
7178c4e7c2eSPierre-Louis Bossart #endif
7183fd63658SCezary Rojewski 	struct hda_codec *codec;
719d8c2dab8SJeeja KP 
720d8c2dab8SJeeja KP 	mutex_lock(&bus->cmd_mutex);
721d8c2dab8SJeeja KP 	snd_hdac_bus_send_cmd(bus, cmd);
722d8c2dab8SJeeja KP 	snd_hdac_bus_get_response(bus, addr, &res);
723d8c2dab8SJeeja KP 	mutex_unlock(&bus->cmd_mutex);
724d8c2dab8SJeeja KP 	if (res == -1)
725d8c2dab8SJeeja KP 		return -EIO;
72600deadb5SRakesh Ughreja 	dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res);
727d8c2dab8SJeeja KP 
7288c4e7c2eSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
7296bae5ea9SRakesh Ughreja 	hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec),
7306bae5ea9SRakesh Ughreja 				 GFP_KERNEL);
7316bae5ea9SRakesh Ughreja 	if (!hda_codec)
7326298542fSRakesh Ughreja 		return -ENOMEM;
7336298542fSRakesh Ughreja 
7343fd63658SCezary Rojewski 	codec = skl_codec_device_init(bus, addr);
7353fd63658SCezary Rojewski 	if (IS_ERR(codec))
7363fd63658SCezary Rojewski 		return PTR_ERR(codec);
7376bae5ea9SRakesh Ughreja 
7383fd63658SCezary Rojewski 	hda_codec->codec = codec;
7393fd63658SCezary Rojewski 	dev_set_drvdata(&codec->core.dev, hda_codec);
7406bae5ea9SRakesh Ughreja 
7416bae5ea9SRakesh Ughreja 	/* use legacy bus only for HDA codecs, idisp uses ext bus */
7426bae5ea9SRakesh Ughreja 	if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) {
7433fd63658SCezary Rojewski 		codec->core.type = HDA_DEV_LEGACY;
7443fd63658SCezary Rojewski 		load_codec_module(hda_codec->codec);
7456bae5ea9SRakesh Ughreja 	}
7466bae5ea9SRakesh Ughreja 	return 0;
7478c4e7c2eSPierre-Louis Bossart #else
7483fd63658SCezary Rojewski 	codec = skl_codec_device_init(bus, addr);
7493fd63658SCezary Rojewski 	return PTR_ERR_OR_ZERO(codec);
7508c4e7c2eSPierre-Louis Bossart #endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */
751d8c2dab8SJeeja KP }
752d8c2dab8SJeeja KP 
753d8c2dab8SJeeja KP /* Codec initialization */
skl_codec_create(struct hdac_bus * bus)75476f56faeSRakesh Ughreja static void skl_codec_create(struct hdac_bus *bus)
755d8c2dab8SJeeja KP {
756d8c2dab8SJeeja KP 	int c, max_slots;
757d8c2dab8SJeeja KP 
758d8c2dab8SJeeja KP 	max_slots = HDA_MAX_CODECS;
759d8c2dab8SJeeja KP 
760d8c2dab8SJeeja KP 	/* First try to probe all given codec slots */
761d8c2dab8SJeeja KP 	for (c = 0; c < max_slots; c++) {
762d8c2dab8SJeeja KP 		if ((bus->codec_mask & (1 << c))) {
76376f56faeSRakesh Ughreja 			if (probe_codec(bus, c) < 0) {
764d8c2dab8SJeeja KP 				/*
765d8c2dab8SJeeja KP 				 * Some BIOSen give you wrong codec addresses
766d8c2dab8SJeeja KP 				 * that don't exist
767d8c2dab8SJeeja KP 				 */
768d8c2dab8SJeeja KP 				dev_warn(bus->dev,
769d8c2dab8SJeeja KP 					 "Codec #%d probe error; disabling it...\n", c);
770d8c2dab8SJeeja KP 				bus->codec_mask &= ~(1 << c);
771d8c2dab8SJeeja KP 				/*
772d8c2dab8SJeeja KP 				 * More badly, accessing to a non-existing
773d8c2dab8SJeeja KP 				 * codec often screws up the controller bus,
774d8c2dab8SJeeja KP 				 * and disturbs the further communications.
775d8c2dab8SJeeja KP 				 * Thus if an error occurs during probing,
776d8c2dab8SJeeja KP 				 * better to reset the controller bus to get
777d8c2dab8SJeeja KP 				 * back to the sanity state.
778d8c2dab8SJeeja KP 				 */
779d8c2dab8SJeeja KP 				snd_hdac_bus_stop_chip(bus);
7800c8ba9d2SJayachandran B 				skl_init_chip(bus, true);
781d8c2dab8SJeeja KP 			}
782d8c2dab8SJeeja KP 		}
783d8c2dab8SJeeja KP 	}
784d8c2dab8SJeeja KP }
785d8c2dab8SJeeja KP 
skl_i915_init(struct hdac_bus * bus)786ab1b732dSVinod Koul static int skl_i915_init(struct hdac_bus *bus)
787ab1b732dSVinod Koul {
788ab1b732dSVinod Koul 	int err;
789ab1b732dSVinod Koul 
790ab1b732dSVinod Koul 	/*
791ab1b732dSVinod Koul 	 * The HDMI codec is in GPU so we need to ensure that it is powered
792ab1b732dSVinod Koul 	 * up and ready for probe
793ab1b732dSVinod Koul 	 */
794ab1b732dSVinod Koul 	err = snd_hdac_i915_init(bus);
795ab1b732dSVinod Koul 	if (err < 0)
796ab1b732dSVinod Koul 		return err;
797ab1b732dSVinod Koul 
7984f799e73STakashi Iwai 	snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
799ab1b732dSVinod Koul 
8004f799e73STakashi Iwai 	return 0;
801ab1b732dSVinod Koul }
802ab1b732dSVinod Koul 
skl_probe_work(struct work_struct * work)803ab1b732dSVinod Koul static void skl_probe_work(struct work_struct *work)
804ab1b732dSVinod Koul {
805bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = container_of(work, struct skl_dev, probe_work);
80676f56faeSRakesh Ughreja 	struct hdac_bus *bus = skl_to_bus(skl);
807ca841843SGuennadi Liakhovetski 	struct hdac_ext_link *hlink;
808ab1b732dSVinod Koul 	int err;
809ab1b732dSVinod Koul 
810ab1b732dSVinod Koul 	if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
811ab1b732dSVinod Koul 		err = skl_i915_init(bus);
812ab1b732dSVinod Koul 		if (err < 0)
813ab1b732dSVinod Koul 			return;
814ab1b732dSVinod Koul 	}
815ab1b732dSVinod Koul 
8162ef81057SCezary Rojewski 	skl_init_pci(skl);
8172ef81057SCezary Rojewski 	skl_dum_set(bus);
8182ef81057SCezary Rojewski 
819ab1b732dSVinod Koul 	err = skl_init_chip(bus, true);
820ab1b732dSVinod Koul 	if (err < 0) {
821ab1b732dSVinod Koul 		dev_err(bus->dev, "Init chip failed with err: %d\n", err);
822ab1b732dSVinod Koul 		goto out_err;
823ab1b732dSVinod Koul 	}
824ab1b732dSVinod Koul 
825ab1b732dSVinod Koul 	/* codec detection */
826ab1b732dSVinod Koul 	if (!bus->codec_mask)
827ab1b732dSVinod Koul 		dev_info(bus->dev, "no hda codecs found!\n");
828ab1b732dSVinod Koul 
829ab1b732dSVinod Koul 	/* create codec instances */
83076f56faeSRakesh Ughreja 	skl_codec_create(bus);
831ab1b732dSVinod Koul 
832752c93aaSPankaj Bharadiya 	/* register platform dai and controls */
833752c93aaSPankaj Bharadiya 	err = skl_platform_register(bus->dev);
834752c93aaSPankaj Bharadiya 	if (err < 0) {
835752c93aaSPankaj Bharadiya 		dev_err(bus->dev, "platform register failed: %d\n", err);
836687ae9e2STakashi Iwai 		goto out_err;
837752c93aaSPankaj Bharadiya 	}
838752c93aaSPankaj Bharadiya 
839752c93aaSPankaj Bharadiya 	err = skl_machine_device_register(skl);
840752c93aaSPankaj Bharadiya 	if (err < 0) {
841752c93aaSPankaj Bharadiya 		dev_err(bus->dev, "machine register failed: %d\n", err);
842752c93aaSPankaj Bharadiya 		goto out_err;
843752c93aaSPankaj Bharadiya 	}
844752c93aaSPankaj Bharadiya 
8454c10473dSPierre-Louis Bossart 	/*
8464c10473dSPierre-Louis Bossart 	 * we are done probing so decrement link counts
8474c10473dSPierre-Louis Bossart 	 */
8484c10473dSPierre-Louis Bossart 	list_for_each_entry(hlink, &bus->hlink_list, list)
8494c10473dSPierre-Louis Bossart 		snd_hdac_ext_bus_link_put(bus, hlink);
8504c10473dSPierre-Louis Bossart 
8514f799e73STakashi Iwai 	if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
8524f799e73STakashi Iwai 		snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
853ab1b732dSVinod Koul 
854ab1b732dSVinod Koul 	/* configure PM */
855ab1b732dSVinod Koul 	pm_runtime_put_noidle(bus->dev);
856ab1b732dSVinod Koul 	pm_runtime_allow(bus->dev);
857ab1b732dSVinod Koul 	skl->init_done = 1;
858ab1b732dSVinod Koul 
859ab1b732dSVinod Koul 	return;
860ab1b732dSVinod Koul 
861ab1b732dSVinod Koul out_err:
862ab1b732dSVinod Koul 	if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
8634f799e73STakashi Iwai 		snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
864ab1b732dSVinod Koul }
865ab1b732dSVinod Koul 
866d8c2dab8SJeeja KP /*
867d8c2dab8SJeeja KP  * constructor
868d8c2dab8SJeeja KP  */
skl_create(struct pci_dev * pci,struct skl_dev ** rskl)869d8c2dab8SJeeja KP static int skl_create(struct pci_dev *pci,
870bcc2a2dcSCezary Rojewski 		      struct skl_dev **rskl)
871d8c2dab8SJeeja KP {
8726bae5ea9SRakesh Ughreja 	struct hdac_ext_bus_ops *ext_ops = NULL;
873bcc2a2dcSCezary Rojewski 	struct skl_dev *skl;
87476f56faeSRakesh Ughreja 	struct hdac_bus *bus;
87500deadb5SRakesh Ughreja 	struct hda_bus *hbus;
876d8c2dab8SJeeja KP 	int err;
877d8c2dab8SJeeja KP 
878d8c2dab8SJeeja KP 	*rskl = NULL;
879d8c2dab8SJeeja KP 
880d8c2dab8SJeeja KP 	err = pci_enable_device(pci);
881d8c2dab8SJeeja KP 	if (err < 0)
882d8c2dab8SJeeja KP 		return err;
883d8c2dab8SJeeja KP 
884d8c2dab8SJeeja KP 	skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL);
885d8c2dab8SJeeja KP 	if (!skl) {
886d8c2dab8SJeeja KP 		pci_disable_device(pci);
887d8c2dab8SJeeja KP 		return -ENOMEM;
888d8c2dab8SJeeja KP 	}
88976f56faeSRakesh Ughreja 
89000deadb5SRakesh Ughreja 	hbus = skl_to_hbus(skl);
89176f56faeSRakesh Ughreja 	bus = skl_to_bus(skl);
8926bae5ea9SRakesh Ughreja 
893776cb3b8SAmadeusz Sławiński 	INIT_LIST_HEAD(&skl->ppl_list);
894776cb3b8SAmadeusz Sławiński 	INIT_LIST_HEAD(&skl->bind_list);
895776cb3b8SAmadeusz Sławiński 
8968c4e7c2eSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
8976bae5ea9SRakesh Ughreja 	ext_ops = snd_soc_hdac_hda_get_ops();
8986bae5ea9SRakesh Ughreja #endif
899ae91a189STakashi Iwai 	snd_hdac_ext_bus_init(bus, &pci->dev, NULL, ext_ops);
90076f56faeSRakesh Ughreja 	bus->use_posbuf = 1;
901d8c2dab8SJeeja KP 	skl->pci = pci;
902ab1b732dSVinod Koul 	INIT_WORK(&skl->probe_work, skl_probe_work);
90376f56faeSRakesh Ughreja 	bus->bdl_pos_adj = 0;
904d8c2dab8SJeeja KP 
90500deadb5SRakesh Ughreja 	mutex_init(&hbus->prepare_mutex);
90600deadb5SRakesh Ughreja 	hbus->pci = pci;
90700deadb5SRakesh Ughreja 	hbus->mixer_assigned = -1;
90800deadb5SRakesh Ughreja 	hbus->modelname = "sklbus";
90900deadb5SRakesh Ughreja 
910d8c2dab8SJeeja KP 	*rskl = skl;
911d8c2dab8SJeeja KP 
912d8c2dab8SJeeja KP 	return 0;
913d8c2dab8SJeeja KP }
914d8c2dab8SJeeja KP 
skl_first_init(struct hdac_bus * bus)91576f56faeSRakesh Ughreja static int skl_first_init(struct hdac_bus *bus)
916d8c2dab8SJeeja KP {
917bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
918d8c2dab8SJeeja KP 	struct pci_dev *pci = skl->pci;
919d8c2dab8SJeeja KP 	int err;
920d8c2dab8SJeeja KP 	unsigned short gcap;
921d8c2dab8SJeeja KP 	int cp_streams, pb_streams, start_idx;
922d8c2dab8SJeeja KP 
923d8c2dab8SJeeja KP 	err = pci_request_regions(pci, "Skylake HD audio");
924d8c2dab8SJeeja KP 	if (err < 0)
925d8c2dab8SJeeja KP 		return err;
926d8c2dab8SJeeja KP 
927d8c2dab8SJeeja KP 	bus->addr = pci_resource_start(pci, 0);
928d8c2dab8SJeeja KP 	bus->remap_addr = pci_ioremap_bar(pci, 0);
929d8c2dab8SJeeja KP 	if (bus->remap_addr == NULL) {
930d8c2dab8SJeeja KP 		dev_err(bus->dev, "ioremap error\n");
931d8c2dab8SJeeja KP 		return -ENXIO;
932d8c2dab8SJeeja KP 	}
933d8c2dab8SJeeja KP 
934ec8ae570SVinod Koul 	snd_hdac_bus_parse_capabilities(bus);
93505057001SJeeja KP 
936fa11ab56SPierre-Louis Bossart 	/* check if PPCAP exists */
937fa11ab56SPierre-Louis Bossart 	if (!bus->ppcap) {
938135ab457SPierre-Louis Bossart 		dev_err(bus->dev, "bus ppcap not set, HDAudio or DSP not present?\n");
939fa11ab56SPierre-Louis Bossart 		return -ENODEV;
940fa11ab56SPierre-Louis Bossart 	}
941fa11ab56SPierre-Louis Bossart 
942542cedecSYu Zhao 	if (skl_acquire_irq(bus, 0) < 0)
943542cedecSYu Zhao 		return -EBUSY;
944542cedecSYu Zhao 
945d8c2dab8SJeeja KP 	pci_set_master(pci);
946542cedecSYu Zhao 	synchronize_irq(bus->irq);
947d8c2dab8SJeeja KP 
948d8c2dab8SJeeja KP 	gcap = snd_hdac_chip_readw(bus, GCAP);
949d8c2dab8SJeeja KP 	dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap);
950d8c2dab8SJeeja KP 
951fa11ab56SPierre-Louis Bossart 	/* read number of streams from GCAP register */
952fa11ab56SPierre-Louis Bossart 	cp_streams = (gcap >> 8) & 0x0f;
953fa11ab56SPierre-Louis Bossart 	pb_streams = (gcap >> 12) & 0x0f;
954fa11ab56SPierre-Louis Bossart 
955fa11ab56SPierre-Louis Bossart 	if (!pb_streams && !cp_streams) {
956fa11ab56SPierre-Louis Bossart 		dev_err(bus->dev, "no streams found in GCAP definitions?\n");
957fa11ab56SPierre-Louis Bossart 		return -EIO;
958fa11ab56SPierre-Louis Bossart 	}
959fa11ab56SPierre-Louis Bossart 
960fa11ab56SPierre-Louis Bossart 	bus->num_streams = cp_streams + pb_streams;
961fa11ab56SPierre-Louis Bossart 
962d8c2dab8SJeeja KP 	/* allow 64bit DMA address if supported by H/W */
963d3afb002STakashi Iwai 	if (dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(64)))
964d3afb002STakashi Iwai 		dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(32));
965c22a8086STakashi Iwai 	dma_set_max_seg_size(bus->dev, UINT_MAX);
966d8c2dab8SJeeja KP 
967d8c2dab8SJeeja KP 	/* initialize streams */
968d8c2dab8SJeeja KP 	snd_hdac_ext_stream_init_all
96976f56faeSRakesh Ughreja 		(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
970d8c2dab8SJeeja KP 	start_idx = cp_streams;
971d8c2dab8SJeeja KP 	snd_hdac_ext_stream_init_all
97276f56faeSRakesh Ughreja 		(bus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
973d8c2dab8SJeeja KP 
974d8c2dab8SJeeja KP 	err = snd_hdac_bus_alloc_stream_pages(bus);
975d8c2dab8SJeeja KP 	if (err < 0)
976d8c2dab8SJeeja KP 		return err;
977d8c2dab8SJeeja KP 
9782ef81057SCezary Rojewski 	return 0;
979d8c2dab8SJeeja KP }
980d8c2dab8SJeeja KP 
skl_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)981d8c2dab8SJeeja KP static int skl_probe(struct pci_dev *pci,
982d8c2dab8SJeeja KP 		     const struct pci_device_id *pci_id)
983d8c2dab8SJeeja KP {
984bcc2a2dcSCezary Rojewski 	struct skl_dev *skl;
985d8c2dab8SJeeja KP 	struct hdac_bus *bus = NULL;
986d8c2dab8SJeeja KP 	int err;
987d8c2dab8SJeeja KP 
988d82b51c8SPierre-Louis Bossart 	switch (skl_pci_binding) {
989d82b51c8SPierre-Louis Bossart 	case SND_SKL_PCI_BIND_AUTO:
99082d9d54aSJaroslav Kysela 		err = snd_intel_dsp_driver_probe(pci);
99182d9d54aSJaroslav Kysela 		if (err != SND_INTEL_DSP_DRIVER_ANY &&
99282d9d54aSJaroslav Kysela 		    err != SND_INTEL_DSP_DRIVER_SST)
993d82b51c8SPierre-Louis Bossart 			return -ENODEV;
994d82b51c8SPierre-Louis Bossart 		break;
995d82b51c8SPierre-Louis Bossart 	case SND_SKL_PCI_BIND_LEGACY:
996135ab457SPierre-Louis Bossart 		dev_info(&pci->dev, "Module parameter forced binding with HDAudio legacy, aborting probe\n");
997d82b51c8SPierre-Louis Bossart 		return -ENODEV;
998d82b51c8SPierre-Louis Bossart 	case SND_SKL_PCI_BIND_ASOC:
999d82b51c8SPierre-Louis Bossart 		dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n");
1000d82b51c8SPierre-Louis Bossart 		break;
1001d82b51c8SPierre-Louis Bossart 	default:
1002d82b51c8SPierre-Louis Bossart 		dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n");
1003d82b51c8SPierre-Louis Bossart 		break;
1004d82b51c8SPierre-Louis Bossart 	}
1005d82b51c8SPierre-Louis Bossart 
1006d8c2dab8SJeeja KP 	/* we use ext core ops, so provide NULL for ops here */
100719abfefdSTakashi Iwai 	err = skl_create(pci, &skl);
1008d8c2dab8SJeeja KP 	if (err < 0)
1009d8c2dab8SJeeja KP 		return err;
1010d8c2dab8SJeeja KP 
101176f56faeSRakesh Ughreja 	bus = skl_to_bus(skl);
1012d8c2dab8SJeeja KP 
101376f56faeSRakesh Ughreja 	err = skl_first_init(bus);
1014f231c34cSPierre-Louis Bossart 	if (err < 0) {
1015f231c34cSPierre-Louis Bossart 		dev_err(bus->dev, "skl_first_init failed with err: %d\n", err);
1016d8c2dab8SJeeja KP 		goto out_free;
1017f231c34cSPierre-Louis Bossart 	}
1018d8c2dab8SJeeja KP 
10194b235c43SVinod Koul 	skl->pci_id = pci->device;
10204b235c43SVinod Koul 
10212e9dc2b6SVinod Koul 	device_disable_async_suspend(bus->dev);
10222e9dc2b6SVinod Koul 
10231169cbf6SPierre-Louis Bossart 	skl->nhlt = intel_nhlt_init(bus->dev);
102487b2bdf0SJeeja KP 
1025979cf59aSWei Yongjun 	if (skl->nhlt == NULL) {
1026f231c34cSPierre-Louis Bossart #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC)
1027f231c34cSPierre-Louis Bossart 		dev_err(bus->dev, "no nhlt info found\n");
1028979cf59aSWei Yongjun 		err = -ENODEV;
1029ab1b732dSVinod Koul 		goto out_free;
1030f231c34cSPierre-Louis Bossart #else
1031135ab457SPierre-Louis Bossart 		dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDAudio codec\n");
1032f231c34cSPierre-Louis Bossart #endif
1033f231c34cSPierre-Louis Bossart 	} else {
103487b2bdf0SJeeja KP 
10350cf5a171SSubhransu S. Prusty 		err = skl_nhlt_create_sysfs(skl);
1036f231c34cSPierre-Louis Bossart 		if (err < 0) {
1037f231c34cSPierre-Louis Bossart 			dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err);
10380cf5a171SSubhransu S. Prusty 			goto out_nhlt_free;
1039f231c34cSPierre-Louis Bossart 		}
10400cf5a171SSubhransu S. Prusty 
10414b235c43SVinod Koul 		skl_nhlt_update_topology_bin(skl);
10424b235c43SVinod Koul 
1043bc2bd45bSSriram Periyasamy 		/* create device for dsp clk */
1044bc2bd45bSSriram Periyasamy 		err = skl_clock_device_register(skl);
1045f231c34cSPierre-Louis Bossart 		if (err < 0) {
1046f231c34cSPierre-Louis Bossart 			dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err);
1047bc2bd45bSSriram Periyasamy 			goto out_clk_free;
1048f231c34cSPierre-Louis Bossart 		}
1049f231c34cSPierre-Louis Bossart 	}
1050f231c34cSPierre-Louis Bossart 
1051f231c34cSPierre-Louis Bossart 	pci_set_drvdata(skl->pci, bus);
1052f231c34cSPierre-Louis Bossart 
1053bc2bd45bSSriram Periyasamy 
1054752c93aaSPankaj Bharadiya 	err = skl_find_machine(skl, (void *)pci_id->driver_data);
1055f231c34cSPierre-Louis Bossart 	if (err < 0) {
1056f231c34cSPierre-Louis Bossart 		dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err);
1057c286b3f9SJeeja KP 		goto out_nhlt_free;
1058f231c34cSPierre-Louis Bossart 	}
1059cc18c5fdSVinod Koul 
10602a29b200SJeeja KP 	err = skl_init_dsp(skl);
10612a29b200SJeeja KP 	if (err < 0) {
10622a29b200SJeeja KP 		dev_dbg(bus->dev, "error failed to register dsp\n");
1063752c93aaSPankaj Bharadiya 		goto out_nhlt_free;
106405057001SJeeja KP 	}
1065bcc2a2dcSCezary Rojewski 	skl->enable_miscbdcge = skl_enable_miscbdcge;
1066bcc2a2dcSCezary Rojewski 	skl->clock_power_gating = skl_clock_power_gating;
10677f981bdcSPierre-Louis Bossart 
1068ec8ae570SVinod Koul 	if (bus->mlcap)
106976f56faeSRakesh Ughreja 		snd_hdac_ext_bus_get_ml_capabilities(bus);
107005057001SJeeja KP 
1071d8c2dab8SJeeja KP 	/* create device for soc dmic */
1072d8c2dab8SJeeja KP 	err = skl_dmic_device_register(skl);
1073f231c34cSPierre-Louis Bossart 	if (err < 0) {
1074f231c34cSPierre-Louis Bossart 		dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err);
10752a29b200SJeeja KP 		goto out_dsp_free;
1076f231c34cSPierre-Louis Bossart 	}
1077d8c2dab8SJeeja KP 
1078ab1b732dSVinod Koul 	schedule_work(&skl->probe_work);
1079d8c2dab8SJeeja KP 
1080d8c2dab8SJeeja KP 	return 0;
1081d8c2dab8SJeeja KP 
10822a29b200SJeeja KP out_dsp_free:
10832a29b200SJeeja KP 	skl_free_dsp(skl);
1084bc2bd45bSSriram Periyasamy out_clk_free:
1085bc2bd45bSSriram Periyasamy 	skl_clock_device_unregister(skl);
1086c286b3f9SJeeja KP out_nhlt_free:
10879e6c382fSCezary Rojewski 	if (skl->nhlt)
10881169cbf6SPierre-Louis Bossart 		intel_nhlt_free(skl->nhlt);
1089d8c2dab8SJeeja KP out_free:
109076f56faeSRakesh Ughreja 	skl_free(bus);
1091d8c2dab8SJeeja KP 
1092d8c2dab8SJeeja KP 	return err;
1093d8c2dab8SJeeja KP }
1094d8c2dab8SJeeja KP 
skl_shutdown(struct pci_dev * pci)1095c5a76a24SJeeja KP static void skl_shutdown(struct pci_dev *pci)
1096c5a76a24SJeeja KP {
109776f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
1098c5a76a24SJeeja KP 	struct hdac_stream *s;
1099c5a76a24SJeeja KP 	struct hdac_ext_stream *stream;
1100bcc2a2dcSCezary Rojewski 	struct skl_dev *skl;
1101c5a76a24SJeeja KP 
110276f56faeSRakesh Ughreja 	if (!bus)
1103c5a76a24SJeeja KP 		return;
1104c5a76a24SJeeja KP 
110576f56faeSRakesh Ughreja 	skl = bus_to_skl(bus);
1106c5a76a24SJeeja KP 
1107ab1b732dSVinod Koul 	if (!skl->init_done)
1108c5a76a24SJeeja KP 		return;
1109c5a76a24SJeeja KP 
111017110723SCezary Rojewski 	snd_hdac_stop_streams(bus);
111117110723SCezary Rojewski 	snd_hdac_ext_bus_link_power_down_all(bus);
111217110723SCezary Rojewski 	skl_dsp_sleep(skl->dsp);
111317110723SCezary Rojewski 
1114c5a76a24SJeeja KP 	list_for_each_entry(s, &bus->stream_list, list) {
1115c5a76a24SJeeja KP 		stream = stream_to_hdac_ext_stream(s);
111676f56faeSRakesh Ughreja 		snd_hdac_ext_stream_decouple(bus, stream, false);
1117c5a76a24SJeeja KP 	}
1118c5a76a24SJeeja KP 
1119c5a76a24SJeeja KP 	snd_hdac_bus_stop_chip(bus);
1120c5a76a24SJeeja KP }
1121c5a76a24SJeeja KP 
skl_remove(struct pci_dev * pci)1122d8c2dab8SJeeja KP static void skl_remove(struct pci_dev *pci)
1123d8c2dab8SJeeja KP {
112476f56faeSRakesh Ughreja 	struct hdac_bus *bus = pci_get_drvdata(pci);
1125bcc2a2dcSCezary Rojewski 	struct skl_dev *skl = bus_to_skl(bus);
1126d8c2dab8SJeeja KP 
1127776cb3b8SAmadeusz Sławiński 	cancel_work_sync(&skl->probe_work);
1128d8018361SVinod Koul 
1129d8c2dab8SJeeja KP 	pm_runtime_get_noresume(&pci->dev);
11307373f481SVinod Koul 
11317373f481SVinod Koul 	/* codec removal, invoke bus_device_remove */
113276f56faeSRakesh Ughreja 	snd_hdac_ext_bus_device_remove(bus);
11337373f481SVinod Koul 
1134d8c2dab8SJeeja KP 	skl_platform_unregister(&pci->dev);
11352a29b200SJeeja KP 	skl_free_dsp(skl);
1136cc18c5fdSVinod Koul 	skl_machine_device_unregister(skl);
1137d8c2dab8SJeeja KP 	skl_dmic_device_unregister(skl);
1138bc2bd45bSSriram Periyasamy 	skl_clock_device_unregister(skl);
11390cf5a171SSubhransu S. Prusty 	skl_nhlt_remove_sysfs(skl);
11409e6c382fSCezary Rojewski 	if (skl->nhlt)
11411169cbf6SPierre-Louis Bossart 		intel_nhlt_free(skl->nhlt);
114276f56faeSRakesh Ughreja 	skl_free(bus);
1143d8c2dab8SJeeja KP }
1144d8c2dab8SJeeja KP 
1145d8c2dab8SJeeja KP /* PCI IDs */
1146d8c2dab8SJeeja KP static const struct pci_device_id skl_ids[] = {
114735bc99aaSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
1148*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &snd_soc_acpi_intel_skl_machines) },
114935bc99aaSPierre-Louis Bossart #endif
115035bc99aaSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
1151*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_APL, &snd_soc_acpi_intel_bxt_machines) },
115235bc99aaSPierre-Louis Bossart #endif
115335bc99aaSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
1154*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &snd_soc_acpi_intel_kbl_machines) },
115535bc99aaSPierre-Louis Bossart #endif
115635bc99aaSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
1157*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_GML, &snd_soc_acpi_intel_glk_machines) },
115835bc99aaSPierre-Louis Bossart #endif
115935bc99aaSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
1160*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &snd_soc_acpi_intel_cnl_machines) },
116135bc99aaSPierre-Louis Bossart #endif
116235bc99aaSPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
1163*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &snd_soc_acpi_intel_cnl_machines) },
116435bc99aaSPierre-Louis Bossart #endif
11655f740b24SEvan Green #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP)
1166*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &snd_soc_acpi_intel_cnl_machines) },
11675f740b24SEvan Green #endif
11685f740b24SEvan Green #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H)
1169*a2db8743SAmadeusz Sławiński 	{ PCI_DEVICE_DATA(INTEL, HDA_CML_H, &snd_soc_acpi_intel_cnl_machines) },
11705f740b24SEvan Green #endif
1171d8c2dab8SJeeja KP 	{ 0, }
1172d8c2dab8SJeeja KP };
1173d8c2dab8SJeeja KP MODULE_DEVICE_TABLE(pci, skl_ids);
1174d8c2dab8SJeeja KP 
1175d8c2dab8SJeeja KP /* pci_driver definition */
1176d8c2dab8SJeeja KP static struct pci_driver skl_driver = {
1177d8c2dab8SJeeja KP 	.name = KBUILD_MODNAME,
1178d8c2dab8SJeeja KP 	.id_table = skl_ids,
1179d8c2dab8SJeeja KP 	.probe = skl_probe,
1180d8c2dab8SJeeja KP 	.remove = skl_remove,
1181c5a76a24SJeeja KP 	.shutdown = skl_shutdown,
1182d8c2dab8SJeeja KP 	.driver = {
1183d8c2dab8SJeeja KP 		.pm = &skl_pm,
1184d8c2dab8SJeeja KP 	},
1185d8c2dab8SJeeja KP };
1186d8c2dab8SJeeja KP module_pci_driver(skl_driver);
1187d8c2dab8SJeeja KP 
1188d8c2dab8SJeeja KP MODULE_LICENSE("GPL v2");
1189d8c2dab8SJeeja KP MODULE_DESCRIPTION("Intel Skylake ASoC HDA driver");
1190