18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * skl.c - Implementation of ASoC Intel SKL HD Audio driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014-2015 Intel Corp 68c2ecf20Sopenharmony_ci * Author: Jeeja KP <jeeja.kp@intel.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Derived mostly from Intel HDA driver with following copyrights: 98c2ecf20Sopenharmony_ci * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 108c2ecf20Sopenharmony_ci * PeiSen Hou <pshou@realtek.com.tw> 118c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/firmware.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <sound/pcm.h> 238c2ecf20Sopenharmony_ci#include <sound/soc-acpi.h> 248c2ecf20Sopenharmony_ci#include <sound/soc-acpi-intel-match.h> 258c2ecf20Sopenharmony_ci#include <sound/hda_register.h> 268c2ecf20Sopenharmony_ci#include <sound/hdaudio.h> 278c2ecf20Sopenharmony_ci#include <sound/hda_i915.h> 288c2ecf20Sopenharmony_ci#include <sound/hda_codec.h> 298c2ecf20Sopenharmony_ci#include <sound/intel-nhlt.h> 308c2ecf20Sopenharmony_ci#include <sound/intel-dsp-config.h> 318c2ecf20Sopenharmony_ci#include "skl.h" 328c2ecf20Sopenharmony_ci#include "skl-sst-dsp.h" 338c2ecf20Sopenharmony_ci#include "skl-sst-ipc.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) 368c2ecf20Sopenharmony_ci#include "../../../soc/codecs/hdac_hda.h" 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_cistatic int skl_pci_binding; 398c2ecf20Sopenharmony_cimodule_param_named(pci_binding, skl_pci_binding, int, 0444); 408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc"); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * initialize the PCI registers 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg, 468c2ecf20Sopenharmony_ci unsigned char mask, unsigned char val) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci unsigned char data; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci pci_read_config_byte(pci, reg, &data); 518c2ecf20Sopenharmony_ci data &= ~mask; 528c2ecf20Sopenharmony_ci data |= (val & mask); 538c2ecf20Sopenharmony_ci pci_write_config_byte(pci, reg, data); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void skl_init_pci(struct skl_dev *skl) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * Clear bits 0-2 of PCI register TCSEL (at offset 0x44) 628c2ecf20Sopenharmony_ci * TCSEL == Traffic Class Select Register, which sets PCI express QOS 638c2ecf20Sopenharmony_ci * Ensuring these bits are 0 clears playback static on some HD Audio 648c2ecf20Sopenharmony_ci * codecs. 658c2ecf20Sopenharmony_ci * The PCI register TCSEL is defined in the Intel manuals. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "Clearing TCSEL\n"); 688c2ecf20Sopenharmony_ci skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void update_pci_dword(struct pci_dev *pci, 728c2ecf20Sopenharmony_ci unsigned int reg, u32 mask, u32 val) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 data = 0; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci pci_read_config_dword(pci, reg, &data); 778c2ecf20Sopenharmony_ci data &= ~mask; 788c2ecf20Sopenharmony_ci data |= (val & mask); 798c2ecf20Sopenharmony_ci pci_write_config_dword(pci, reg, data); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * @dev: device pointer 868c2ecf20Sopenharmony_ci * @enable: enable/disable flag 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_cistatic void skl_enable_miscbdcge(struct device *dev, bool enable) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 918c2ecf20Sopenharmony_ci u32 val; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * skl_clock_power_gating: Enable/Disable clock and power gating 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * @dev: Device pointer 1028c2ecf20Sopenharmony_ci * @enable: Enable/Disable flag 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_cistatic void skl_clock_power_gating(struct device *dev, bool enable) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 1078c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 1088c2ecf20Sopenharmony_ci u32 val; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Update PDCGE bit of CGCTL register */ 1118c2ecf20Sopenharmony_ci val = enable ? AZX_CGCTL_ADSPDCGE : 0; 1128c2ecf20Sopenharmony_ci update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_ADSPDCGE, val); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Update L1SEN bit of EM2 register */ 1158c2ecf20Sopenharmony_ci val = enable ? AZX_REG_VS_EM2_L1SEN : 0; 1168c2ecf20Sopenharmony_ci snd_hdac_chip_updatel(bus, VS_EM2, AZX_REG_VS_EM2_L1SEN, val); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Update ADSPPGD bit of PGCTL register */ 1198c2ecf20Sopenharmony_ci val = enable ? 0 : AZX_PGCTL_ADSPPGD; 1208c2ecf20Sopenharmony_ci update_pci_dword(pci, AZX_PCIREG_PGCTL, AZX_PGCTL_ADSPPGD, val); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * While performing reset, controller may not come back properly causing 1258c2ecf20Sopenharmony_ci * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset 1268c2ecf20Sopenharmony_ci * (init chip) and then again set CGCTL.MISCBDCGE to 1 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_cistatic int skl_init_chip(struct hdac_bus *bus, bool full_reset) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct hdac_ext_link *hlink; 1318c2ecf20Sopenharmony_ci int ret; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci snd_hdac_set_codec_wakeup(bus, true); 1348c2ecf20Sopenharmony_ci skl_enable_miscbdcge(bus->dev, false); 1358c2ecf20Sopenharmony_ci ret = snd_hdac_bus_init_chip(bus, full_reset); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Reset stream-to-link mapping */ 1388c2ecf20Sopenharmony_ci list_for_each_entry(hlink, &bus->hlink_list, list) 1398c2ecf20Sopenharmony_ci writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci skl_enable_miscbdcge(bus->dev, true); 1428c2ecf20Sopenharmony_ci snd_hdac_set_codec_wakeup(bus, false); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return ret; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_civoid skl_update_d0i3c(struct device *dev, bool enable) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 1508c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 1518c2ecf20Sopenharmony_ci u8 reg; 1528c2ecf20Sopenharmony_ci int timeout = 50; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci reg = snd_hdac_chip_readb(bus, VS_D0I3C); 1558c2ecf20Sopenharmony_ci /* Do not write to D0I3C until command in progress bit is cleared */ 1568c2ecf20Sopenharmony_ci while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { 1578c2ecf20Sopenharmony_ci udelay(10); 1588c2ecf20Sopenharmony_ci reg = snd_hdac_chip_readb(bus, VS_D0I3C); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Highly unlikely. But if it happens, flag error explicitly */ 1628c2ecf20Sopenharmony_ci if (!timeout) { 1638c2ecf20Sopenharmony_ci dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (enable) 1688c2ecf20Sopenharmony_ci reg = reg | AZX_REG_VS_D0I3C_I3; 1698c2ecf20Sopenharmony_ci else 1708c2ecf20Sopenharmony_ci reg = reg & (~AZX_REG_VS_D0I3C_I3); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci snd_hdac_chip_writeb(bus, VS_D0I3C, reg); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci timeout = 50; 1758c2ecf20Sopenharmony_ci /* Wait for cmd in progress to be cleared before exiting the function */ 1768c2ecf20Sopenharmony_ci reg = snd_hdac_chip_readb(bus, VS_D0I3C); 1778c2ecf20Sopenharmony_ci while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { 1788c2ecf20Sopenharmony_ci udelay(10); 1798c2ecf20Sopenharmony_ci reg = snd_hdac_chip_readb(bus, VS_D0I3C); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Highly unlikely. But if it happens, flag error explicitly */ 1838c2ecf20Sopenharmony_ci if (!timeout) { 1848c2ecf20Sopenharmony_ci dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "D0I3C register = 0x%x\n", 1898c2ecf20Sopenharmony_ci snd_hdac_chip_readb(bus, VS_D0I3C)); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * skl_dum_set - set DUM bit in EM2 register 1948c2ecf20Sopenharmony_ci * @bus: HD-audio core bus 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * Addresses incorrect position reporting for capture streams. 1978c2ecf20Sopenharmony_ci * Used on device power up. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic void skl_dum_set(struct hdac_bus *bus) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci /* For the DUM bit to be set, CRST needs to be out of reset state */ 2028c2ecf20Sopenharmony_ci if (!(snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)) { 2038c2ecf20Sopenharmony_ci skl_enable_miscbdcge(bus->dev, false); 2048c2ecf20Sopenharmony_ci snd_hdac_bus_exit_link_reset(bus); 2058c2ecf20Sopenharmony_ci skl_enable_miscbdcge(bus->dev, true); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* called from IRQ */ 2128c2ecf20Sopenharmony_cistatic void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(hstr->substream); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic irqreturn_t skl_interrupt(int irq, void *dev_id) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct hdac_bus *bus = dev_id; 2208c2ecf20Sopenharmony_ci u32 status; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!pm_runtime_active(bus->dev)) 2238c2ecf20Sopenharmony_ci return IRQ_NONE; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci spin_lock(&bus->reg_lock); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci status = snd_hdac_chip_readl(bus, INTSTS); 2288c2ecf20Sopenharmony_ci if (status == 0 || status == 0xffffffff) { 2298c2ecf20Sopenharmony_ci spin_unlock(&bus->reg_lock); 2308c2ecf20Sopenharmony_ci return IRQ_NONE; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* clear rirb int */ 2348c2ecf20Sopenharmony_ci status = snd_hdac_chip_readb(bus, RIRBSTS); 2358c2ecf20Sopenharmony_ci if (status & RIRB_INT_MASK) { 2368c2ecf20Sopenharmony_ci if (status & RIRB_INT_RESPONSE) 2378c2ecf20Sopenharmony_ci snd_hdac_bus_update_rirb(bus); 2388c2ecf20Sopenharmony_ci snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci spin_unlock(&bus->reg_lock); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic irqreturn_t skl_threaded_handler(int irq, void *dev_id) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct hdac_bus *bus = dev_id; 2498c2ecf20Sopenharmony_ci u32 status; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci status = snd_hdac_chip_readl(bus, INTSTS); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci ret = request_threaded_irq(skl->pci->irq, skl_interrupt, 2648c2ecf20Sopenharmony_ci skl_threaded_handler, 2658c2ecf20Sopenharmony_ci IRQF_SHARED, 2668c2ecf20Sopenharmony_ci KBUILD_MODNAME, bus); 2678c2ecf20Sopenharmony_ci if (ret) { 2688c2ecf20Sopenharmony_ci dev_err(bus->dev, 2698c2ecf20Sopenharmony_ci "unable to grab IRQ %d, disabling device\n", 2708c2ecf20Sopenharmony_ci skl->pci->irq); 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci bus->irq = skl->pci->irq; 2758c2ecf20Sopenharmony_ci pci_intx(skl->pci, 1); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int skl_suspend_late(struct device *dev) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 2838c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 2848c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return skl_suspend_late_dsp(skl); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 2908c2ecf20Sopenharmony_cistatic int _skl_suspend(struct hdac_bus *bus) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 2938c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(bus->dev); 2948c2ecf20Sopenharmony_ci int ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci snd_hdac_ext_bus_link_power_down_all(bus); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret = skl_suspend_dsp(skl); 2998c2ecf20Sopenharmony_ci if (ret < 0) 3008c2ecf20Sopenharmony_ci return ret; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci snd_hdac_bus_stop_chip(bus); 3038c2ecf20Sopenharmony_ci update_pci_dword(pci, AZX_PCIREG_PGCTL, 3048c2ecf20Sopenharmony_ci AZX_PGCTL_LSRMD_MASK, AZX_PGCTL_LSRMD_MASK); 3058c2ecf20Sopenharmony_ci skl_enable_miscbdcge(bus->dev, false); 3068c2ecf20Sopenharmony_ci snd_hdac_bus_enter_link_reset(bus); 3078c2ecf20Sopenharmony_ci skl_enable_miscbdcge(bus->dev, true); 3088c2ecf20Sopenharmony_ci skl_cleanup_resources(skl); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int _skl_resume(struct hdac_bus *bus) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci skl_init_pci(skl); 3188c2ecf20Sopenharmony_ci skl_dum_set(bus); 3198c2ecf20Sopenharmony_ci skl_init_chip(bus, true); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return skl_resume_dsp(skl); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci#endif 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3268c2ecf20Sopenharmony_ci/* 3278c2ecf20Sopenharmony_ci * power management 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_cistatic int skl_suspend(struct device *dev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 3328c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 3338c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 3348c2ecf20Sopenharmony_ci int ret; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* 3378c2ecf20Sopenharmony_ci * Do not suspend if streams which are marked ignore suspend are 3388c2ecf20Sopenharmony_ci * running, we need to save the state for these and continue 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci if (skl->supend_active) { 3418c2ecf20Sopenharmony_ci /* turn off the links and stop the CORB/RIRB DMA if it is On */ 3428c2ecf20Sopenharmony_ci snd_hdac_ext_bus_link_power_down_all(bus); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (bus->cmd_dma_state) 3458c2ecf20Sopenharmony_ci snd_hdac_bus_stop_cmd_io(bus); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci enable_irq_wake(bus->irq); 3488c2ecf20Sopenharmony_ci pci_save_state(pci); 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci ret = _skl_suspend(bus); 3518c2ecf20Sopenharmony_ci if (ret < 0) 3528c2ecf20Sopenharmony_ci return ret; 3538c2ecf20Sopenharmony_ci skl->fw_loaded = false; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int skl_resume(struct device *dev) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 3628c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 3638c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 3648c2ecf20Sopenharmony_ci struct hdac_ext_link *hlink; 3658c2ecf20Sopenharmony_ci int ret; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* 3688c2ecf20Sopenharmony_ci * resume only when we are not in suspend active, otherwise need to 3698c2ecf20Sopenharmony_ci * restore the device 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci if (skl->supend_active) { 3728c2ecf20Sopenharmony_ci pci_restore_state(pci); 3738c2ecf20Sopenharmony_ci snd_hdac_ext_bus_link_power_up_all(bus); 3748c2ecf20Sopenharmony_ci disable_irq_wake(bus->irq); 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * turn On the links which are On before active suspend 3778c2ecf20Sopenharmony_ci * and start the CORB/RIRB DMA if On before 3788c2ecf20Sopenharmony_ci * active suspend. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ci list_for_each_entry(hlink, &bus->hlink_list, list) { 3818c2ecf20Sopenharmony_ci if (hlink->ref_count) 3828c2ecf20Sopenharmony_ci snd_hdac_ext_bus_link_power_up(hlink); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci ret = 0; 3868c2ecf20Sopenharmony_ci if (bus->cmd_dma_state) 3878c2ecf20Sopenharmony_ci snd_hdac_bus_init_cmd_io(bus); 3888c2ecf20Sopenharmony_ci } else { 3898c2ecf20Sopenharmony_ci ret = _skl_resume(bus); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* turn off the links which are off before suspend */ 3928c2ecf20Sopenharmony_ci list_for_each_entry(hlink, &bus->hlink_list, list) { 3938c2ecf20Sopenharmony_ci if (!hlink->ref_count) 3948c2ecf20Sopenharmony_ci snd_hdac_ext_bus_link_power_down(hlink); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (!bus->cmd_dma_state) 3988c2ecf20Sopenharmony_ci snd_hdac_bus_stop_cmd_io(bus); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4068c2ecf20Sopenharmony_cistatic int skl_runtime_suspend(struct device *dev) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 4098c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "in %s\n", __func__); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return _skl_suspend(bus); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int skl_runtime_resume(struct device *dev) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 4198c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "in %s\n", __func__); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return _skl_resume(bus); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic const struct dev_pm_ops skl_pm = { 4288c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) 4298c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) 4308c2ecf20Sopenharmony_ci .suspend_late = skl_suspend_late, 4318c2ecf20Sopenharmony_ci}; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci/* 4348c2ecf20Sopenharmony_ci * destructor 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_cistatic int skl_free(struct hdac_bus *bus) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci skl->init_done = 0; /* to be sure */ 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci snd_hdac_stop_streams_and_chip(bus); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (bus->irq >= 0) 4458c2ecf20Sopenharmony_ci free_irq(bus->irq, (void *)bus); 4468c2ecf20Sopenharmony_ci snd_hdac_bus_free_stream_pages(bus); 4478c2ecf20Sopenharmony_ci snd_hdac_stream_free_all(bus); 4488c2ecf20Sopenharmony_ci snd_hdac_link_free_all(bus); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (bus->remap_addr) 4518c2ecf20Sopenharmony_ci iounmap(bus->remap_addr); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci pci_release_regions(skl->pci); 4548c2ecf20Sopenharmony_ci pci_disable_device(skl->pci); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci snd_hdac_ext_bus_exit(bus); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { 4598c2ecf20Sopenharmony_ci snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); 4608c2ecf20Sopenharmony_ci snd_hdac_i915_exit(bus); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/* 4678c2ecf20Sopenharmony_ci * For each ssp there are 3 clocks (mclk/sclk/sclkfs). 4688c2ecf20Sopenharmony_ci * e.g. for ssp0, clocks will be named as 4698c2ecf20Sopenharmony_ci * "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs" 4708c2ecf20Sopenharmony_ci * So for skl+, there are 6 ssps, so 18 clocks will be created. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_cistatic struct skl_ssp_clk skl_ssp_clks[] = { 4738c2ecf20Sopenharmony_ci {.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"}, 4748c2ecf20Sopenharmony_ci {.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"}, 4758c2ecf20Sopenharmony_ci {.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"}, 4768c2ecf20Sopenharmony_ci {.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"}, 4778c2ecf20Sopenharmony_ci {.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"}, 4788c2ecf20Sopenharmony_ci {.name = "ssp2_sclkfs"}, 4798c2ecf20Sopenharmony_ci {.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"}, 4808c2ecf20Sopenharmony_ci {.name = "ssp5_sclkfs"}, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl_dev *skl, 4848c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *machines) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* point to common table */ 4898c2ecf20Sopenharmony_ci mach = snd_soc_acpi_intel_hda_machines; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* all entries in the machine table use the same firmware */ 4928c2ecf20Sopenharmony_ci mach->fw_filename = machines->fw_filename; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return mach; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int skl_find_machine(struct skl_dev *skl, void *driver_data) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 5008c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach = driver_data; 5018c2ecf20Sopenharmony_ci struct skl_machine_pdata *pdata; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci mach = snd_soc_acpi_find_machine(mach); 5048c2ecf20Sopenharmony_ci if (!mach) { 5058c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "No matching I2S machine driver found\n"); 5068c2ecf20Sopenharmony_ci mach = skl_find_hda_machine(skl, driver_data); 5078c2ecf20Sopenharmony_ci if (!mach) { 5088c2ecf20Sopenharmony_ci dev_err(bus->dev, "No matching machine driver found\n"); 5098c2ecf20Sopenharmony_ci return -ENODEV; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci skl->mach = mach; 5148c2ecf20Sopenharmony_ci skl->fw_name = mach->fw_filename; 5158c2ecf20Sopenharmony_ci pdata = mach->pdata; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (pdata) { 5188c2ecf20Sopenharmony_ci skl->use_tplg_pcm = pdata->use_tplg_pcm; 5198c2ecf20Sopenharmony_ci mach->mach_params.dmic_num = 5208c2ecf20Sopenharmony_ci intel_nhlt_get_dmic_geo(&skl->pci->dev, 5218c2ecf20Sopenharmony_ci skl->nhlt); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return 0; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic int skl_machine_device_register(struct skl_dev *skl) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach = skl->mach; 5308c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 5318c2ecf20Sopenharmony_ci struct platform_device *pdev; 5328c2ecf20Sopenharmony_ci int ret; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci pdev = platform_device_alloc(mach->drv_name, -1); 5358c2ecf20Sopenharmony_ci if (pdev == NULL) { 5368c2ecf20Sopenharmony_ci dev_err(bus->dev, "platform device alloc failed\n"); 5378c2ecf20Sopenharmony_ci return -EIO; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci mach->mach_params.platform = dev_name(bus->dev); 5418c2ecf20Sopenharmony_ci mach->mach_params.codec_mask = bus->codec_mask; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach)); 5448c2ecf20Sopenharmony_ci if (ret) { 5458c2ecf20Sopenharmony_ci dev_err(bus->dev, "failed to add machine device platform data\n"); 5468c2ecf20Sopenharmony_ci platform_device_put(pdev); 5478c2ecf20Sopenharmony_ci return ret; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci ret = platform_device_add(pdev); 5518c2ecf20Sopenharmony_ci if (ret) { 5528c2ecf20Sopenharmony_ci dev_err(bus->dev, "failed to add machine device\n"); 5538c2ecf20Sopenharmony_ci platform_device_put(pdev); 5548c2ecf20Sopenharmony_ci return -EIO; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci skl->i2s_dev = pdev; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic void skl_machine_device_unregister(struct skl_dev *skl) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci if (skl->i2s_dev) 5668c2ecf20Sopenharmony_ci platform_device_unregister(skl->i2s_dev); 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic int skl_dmic_device_register(struct skl_dev *skl) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 5728c2ecf20Sopenharmony_ci struct platform_device *pdev; 5738c2ecf20Sopenharmony_ci int ret; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* SKL has one dmic port, so allocate dmic device for this */ 5768c2ecf20Sopenharmony_ci pdev = platform_device_alloc("dmic-codec", -1); 5778c2ecf20Sopenharmony_ci if (!pdev) { 5788c2ecf20Sopenharmony_ci dev_err(bus->dev, "failed to allocate dmic device\n"); 5798c2ecf20Sopenharmony_ci return -ENOMEM; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci ret = platform_device_add(pdev); 5838c2ecf20Sopenharmony_ci if (ret) { 5848c2ecf20Sopenharmony_ci dev_err(bus->dev, "failed to add dmic device: %d\n", ret); 5858c2ecf20Sopenharmony_ci platform_device_put(pdev); 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci skl->dmic_dev = pdev; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic void skl_dmic_device_unregister(struct skl_dev *skl) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci if (skl->dmic_dev) 5968c2ecf20Sopenharmony_ci platform_device_unregister(skl->dmic_dev); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic struct skl_clk_parent_src skl_clk_src[] = { 6008c2ecf20Sopenharmony_ci { .clk_id = SKL_XTAL, .name = "xtal" }, 6018c2ecf20Sopenharmony_ci { .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 }, 6028c2ecf20Sopenharmony_ci { .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 }, 6038c2ecf20Sopenharmony_ci}; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistruct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci unsigned int i; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) { 6108c2ecf20Sopenharmony_ci if (skl_clk_src[i].clk_id == clk_id) 6118c2ecf20Sopenharmony_ci return &skl_clk_src[i]; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return NULL; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic void init_skl_xtal_rate(int pci_id) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci switch (pci_id) { 6208c2ecf20Sopenharmony_ci case 0x9d70: 6218c2ecf20Sopenharmony_ci case 0x9d71: 6228c2ecf20Sopenharmony_ci skl_clk_src[0].rate = 24000000; 6238c2ecf20Sopenharmony_ci return; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci default: 6268c2ecf20Sopenharmony_ci skl_clk_src[0].rate = 19200000; 6278c2ecf20Sopenharmony_ci return; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic int skl_clock_device_register(struct skl_dev *skl) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci struct platform_device_info pdevinfo = {NULL}; 6348c2ecf20Sopenharmony_ci struct skl_clk_pdata *clk_pdata; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (!skl->nhlt) 6378c2ecf20Sopenharmony_ci return 0; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata), 6408c2ecf20Sopenharmony_ci GFP_KERNEL); 6418c2ecf20Sopenharmony_ci if (!clk_pdata) 6428c2ecf20Sopenharmony_ci return -ENOMEM; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci init_skl_xtal_rate(skl->pci->device); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci clk_pdata->parent_clks = skl_clk_src; 6478c2ecf20Sopenharmony_ci clk_pdata->ssp_clks = skl_ssp_clks; 6488c2ecf20Sopenharmony_ci clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Query NHLT to fill the rates and parent */ 6518c2ecf20Sopenharmony_ci skl_get_clks(skl, clk_pdata->ssp_clks); 6528c2ecf20Sopenharmony_ci clk_pdata->pvt_data = skl; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Register Platform device */ 6558c2ecf20Sopenharmony_ci pdevinfo.parent = &skl->pci->dev; 6568c2ecf20Sopenharmony_ci pdevinfo.id = -1; 6578c2ecf20Sopenharmony_ci pdevinfo.name = "skl-ssp-clk"; 6588c2ecf20Sopenharmony_ci pdevinfo.data = clk_pdata; 6598c2ecf20Sopenharmony_ci pdevinfo.size_data = sizeof(*clk_pdata); 6608c2ecf20Sopenharmony_ci skl->clk_dev = platform_device_register_full(&pdevinfo); 6618c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(skl->clk_dev); 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic void skl_clock_device_unregister(struct skl_dev *skl) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci if (skl->clk_dev) 6678c2ecf20Sopenharmony_ci platform_device_unregister(skl->clk_dev); 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci#define IDISP_INTEL_VENDOR_ID 0x80860000 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci/* 6758c2ecf20Sopenharmony_ci * load the legacy codec driver 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_cistatic void load_codec_module(struct hda_codec *codec) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci#ifdef MODULE 6808c2ecf20Sopenharmony_ci char modalias[MODULE_NAME_LEN]; 6818c2ecf20Sopenharmony_ci const char *mod = NULL; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); 6848c2ecf20Sopenharmony_ci mod = modalias; 6858c2ecf20Sopenharmony_ci dev_dbg(&codec->core.dev, "loading %s codec module\n", mod); 6868c2ecf20Sopenharmony_ci request_module(mod); 6878c2ecf20Sopenharmony_ci#endif 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/* 6938c2ecf20Sopenharmony_ci * Probe the given codec address 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_cistatic int probe_codec(struct hdac_bus *bus, int addr) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | 6988c2ecf20Sopenharmony_ci (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; 6998c2ecf20Sopenharmony_ci unsigned int res = -1; 7008c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 7018c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) 7028c2ecf20Sopenharmony_ci struct hdac_hda_priv *hda_codec; 7038c2ecf20Sopenharmony_ci int err; 7048c2ecf20Sopenharmony_ci#endif 7058c2ecf20Sopenharmony_ci struct hdac_device *hdev; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci mutex_lock(&bus->cmd_mutex); 7088c2ecf20Sopenharmony_ci snd_hdac_bus_send_cmd(bus, cmd); 7098c2ecf20Sopenharmony_ci snd_hdac_bus_get_response(bus, addr, &res); 7108c2ecf20Sopenharmony_ci mutex_unlock(&bus->cmd_mutex); 7118c2ecf20Sopenharmony_ci if (res == -1) 7128c2ecf20Sopenharmony_ci return -EIO; 7138c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) 7168c2ecf20Sopenharmony_ci hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), 7178c2ecf20Sopenharmony_ci GFP_KERNEL); 7188c2ecf20Sopenharmony_ci if (!hda_codec) 7198c2ecf20Sopenharmony_ci return -ENOMEM; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci hda_codec->codec.bus = skl_to_hbus(skl); 7228c2ecf20Sopenharmony_ci hdev = &hda_codec->codec.core; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci err = snd_hdac_ext_bus_device_init(bus, addr, hdev, HDA_DEV_ASOC); 7258c2ecf20Sopenharmony_ci if (err < 0) 7268c2ecf20Sopenharmony_ci return err; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* use legacy bus only for HDA codecs, idisp uses ext bus */ 7298c2ecf20Sopenharmony_ci if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) { 7308c2ecf20Sopenharmony_ci hdev->type = HDA_DEV_LEGACY; 7318c2ecf20Sopenharmony_ci load_codec_module(&hda_codec->codec); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci return 0; 7348c2ecf20Sopenharmony_ci#else 7358c2ecf20Sopenharmony_ci hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); 7368c2ecf20Sopenharmony_ci if (!hdev) 7378c2ecf20Sopenharmony_ci return -ENOMEM; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return snd_hdac_ext_bus_device_init(bus, addr, hdev, HDA_DEV_ASOC); 7408c2ecf20Sopenharmony_ci#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* Codec initialization */ 7448c2ecf20Sopenharmony_cistatic void skl_codec_create(struct hdac_bus *bus) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci int c, max_slots; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci max_slots = HDA_MAX_CODECS; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci /* First try to probe all given codec slots */ 7518c2ecf20Sopenharmony_ci for (c = 0; c < max_slots; c++) { 7528c2ecf20Sopenharmony_ci if ((bus->codec_mask & (1 << c))) { 7538c2ecf20Sopenharmony_ci if (probe_codec(bus, c) < 0) { 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * Some BIOSen give you wrong codec addresses 7568c2ecf20Sopenharmony_ci * that don't exist 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci dev_warn(bus->dev, 7598c2ecf20Sopenharmony_ci "Codec #%d probe error; disabling it...\n", c); 7608c2ecf20Sopenharmony_ci bus->codec_mask &= ~(1 << c); 7618c2ecf20Sopenharmony_ci /* 7628c2ecf20Sopenharmony_ci * More badly, accessing to a non-existing 7638c2ecf20Sopenharmony_ci * codec often screws up the controller bus, 7648c2ecf20Sopenharmony_ci * and disturbs the further communications. 7658c2ecf20Sopenharmony_ci * Thus if an error occurs during probing, 7668c2ecf20Sopenharmony_ci * better to reset the controller bus to get 7678c2ecf20Sopenharmony_ci * back to the sanity state. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ci snd_hdac_bus_stop_chip(bus); 7708c2ecf20Sopenharmony_ci skl_init_chip(bus, true); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int skl_i915_init(struct hdac_bus *bus) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci int err; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* 7818c2ecf20Sopenharmony_ci * The HDMI codec is in GPU so we need to ensure that it is powered 7828c2ecf20Sopenharmony_ci * up and ready for probe 7838c2ecf20Sopenharmony_ci */ 7848c2ecf20Sopenharmony_ci err = snd_hdac_i915_init(bus); 7858c2ecf20Sopenharmony_ci if (err < 0) 7868c2ecf20Sopenharmony_ci return err; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic void skl_probe_work(struct work_struct *work) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci struct skl_dev *skl = container_of(work, struct skl_dev, probe_work); 7968c2ecf20Sopenharmony_ci struct hdac_bus *bus = skl_to_bus(skl); 7978c2ecf20Sopenharmony_ci struct hdac_ext_link *hlink; 7988c2ecf20Sopenharmony_ci int err; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { 8018c2ecf20Sopenharmony_ci err = skl_i915_init(bus); 8028c2ecf20Sopenharmony_ci if (err < 0) 8038c2ecf20Sopenharmony_ci return; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci skl_init_pci(skl); 8078c2ecf20Sopenharmony_ci skl_dum_set(bus); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci err = skl_init_chip(bus, true); 8108c2ecf20Sopenharmony_ci if (err < 0) { 8118c2ecf20Sopenharmony_ci dev_err(bus->dev, "Init chip failed with err: %d\n", err); 8128c2ecf20Sopenharmony_ci goto out_err; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* codec detection */ 8168c2ecf20Sopenharmony_ci if (!bus->codec_mask) 8178c2ecf20Sopenharmony_ci dev_info(bus->dev, "no hda codecs found!\n"); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* create codec instances */ 8208c2ecf20Sopenharmony_ci skl_codec_create(bus); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* register platform dai and controls */ 8238c2ecf20Sopenharmony_ci err = skl_platform_register(bus->dev); 8248c2ecf20Sopenharmony_ci if (err < 0) { 8258c2ecf20Sopenharmony_ci dev_err(bus->dev, "platform register failed: %d\n", err); 8268c2ecf20Sopenharmony_ci goto out_err; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci err = skl_machine_device_register(skl); 8308c2ecf20Sopenharmony_ci if (err < 0) { 8318c2ecf20Sopenharmony_ci dev_err(bus->dev, "machine register failed: %d\n", err); 8328c2ecf20Sopenharmony_ci goto out_err; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * we are done probing so decrement link counts 8378c2ecf20Sopenharmony_ci */ 8388c2ecf20Sopenharmony_ci list_for_each_entry(hlink, &bus->hlink_list, list) 8398c2ecf20Sopenharmony_ci snd_hdac_ext_bus_link_put(bus, hlink); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) 8428c2ecf20Sopenharmony_ci snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* configure PM */ 8458c2ecf20Sopenharmony_ci pm_runtime_put_noidle(bus->dev); 8468c2ecf20Sopenharmony_ci pm_runtime_allow(bus->dev); 8478c2ecf20Sopenharmony_ci skl->init_done = 1; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci return; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciout_err: 8528c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) 8538c2ecf20Sopenharmony_ci snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/* 8578c2ecf20Sopenharmony_ci * constructor 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_cistatic int skl_create(struct pci_dev *pci, 8608c2ecf20Sopenharmony_ci struct skl_dev **rskl) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct hdac_ext_bus_ops *ext_ops = NULL; 8638c2ecf20Sopenharmony_ci struct skl_dev *skl; 8648c2ecf20Sopenharmony_ci struct hdac_bus *bus; 8658c2ecf20Sopenharmony_ci struct hda_bus *hbus; 8668c2ecf20Sopenharmony_ci int err; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci *rskl = NULL; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci err = pci_enable_device(pci); 8718c2ecf20Sopenharmony_ci if (err < 0) 8728c2ecf20Sopenharmony_ci return err; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL); 8758c2ecf20Sopenharmony_ci if (!skl) { 8768c2ecf20Sopenharmony_ci pci_disable_device(pci); 8778c2ecf20Sopenharmony_ci return -ENOMEM; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci hbus = skl_to_hbus(skl); 8818c2ecf20Sopenharmony_ci bus = skl_to_bus(skl); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&skl->ppl_list); 8848c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&skl->bind_list); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) 8878c2ecf20Sopenharmony_ci ext_ops = snd_soc_hdac_hda_get_ops(); 8888c2ecf20Sopenharmony_ci#endif 8898c2ecf20Sopenharmony_ci snd_hdac_ext_bus_init(bus, &pci->dev, NULL, ext_ops); 8908c2ecf20Sopenharmony_ci bus->use_posbuf = 1; 8918c2ecf20Sopenharmony_ci skl->pci = pci; 8928c2ecf20Sopenharmony_ci INIT_WORK(&skl->probe_work, skl_probe_work); 8938c2ecf20Sopenharmony_ci bus->bdl_pos_adj = 0; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci mutex_init(&hbus->prepare_mutex); 8968c2ecf20Sopenharmony_ci hbus->pci = pci; 8978c2ecf20Sopenharmony_ci hbus->mixer_assigned = -1; 8988c2ecf20Sopenharmony_ci hbus->modelname = "sklbus"; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci *rskl = skl; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic int skl_first_init(struct hdac_bus *bus) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 9088c2ecf20Sopenharmony_ci struct pci_dev *pci = skl->pci; 9098c2ecf20Sopenharmony_ci int err; 9108c2ecf20Sopenharmony_ci unsigned short gcap; 9118c2ecf20Sopenharmony_ci int cp_streams, pb_streams, start_idx; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci err = pci_request_regions(pci, "Skylake HD audio"); 9148c2ecf20Sopenharmony_ci if (err < 0) 9158c2ecf20Sopenharmony_ci return err; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci bus->addr = pci_resource_start(pci, 0); 9188c2ecf20Sopenharmony_ci bus->remap_addr = pci_ioremap_bar(pci, 0); 9198c2ecf20Sopenharmony_ci if (bus->remap_addr == NULL) { 9208c2ecf20Sopenharmony_ci dev_err(bus->dev, "ioremap error\n"); 9218c2ecf20Sopenharmony_ci return -ENXIO; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci snd_hdac_bus_parse_capabilities(bus); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* check if PPCAP exists */ 9278c2ecf20Sopenharmony_ci if (!bus->ppcap) { 9288c2ecf20Sopenharmony_ci dev_err(bus->dev, "bus ppcap not set, HDAudio or DSP not present?\n"); 9298c2ecf20Sopenharmony_ci return -ENODEV; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (skl_acquire_irq(bus, 0) < 0) 9338c2ecf20Sopenharmony_ci return -EBUSY; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci pci_set_master(pci); 9368c2ecf20Sopenharmony_ci synchronize_irq(bus->irq); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci gcap = snd_hdac_chip_readw(bus, GCAP); 9398c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* read number of streams from GCAP register */ 9428c2ecf20Sopenharmony_ci cp_streams = (gcap >> 8) & 0x0f; 9438c2ecf20Sopenharmony_ci pb_streams = (gcap >> 12) & 0x0f; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (!pb_streams && !cp_streams) { 9468c2ecf20Sopenharmony_ci dev_err(bus->dev, "no streams found in GCAP definitions?\n"); 9478c2ecf20Sopenharmony_ci return -EIO; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci bus->num_streams = cp_streams + pb_streams; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* allow 64bit DMA address if supported by H/W */ 9538c2ecf20Sopenharmony_ci if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { 9548c2ecf20Sopenharmony_ci dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); 9558c2ecf20Sopenharmony_ci } else { 9568c2ecf20Sopenharmony_ci dma_set_mask(bus->dev, DMA_BIT_MASK(32)); 9578c2ecf20Sopenharmony_ci dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* initialize streams */ 9618c2ecf20Sopenharmony_ci snd_hdac_ext_stream_init_all 9628c2ecf20Sopenharmony_ci (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); 9638c2ecf20Sopenharmony_ci start_idx = cp_streams; 9648c2ecf20Sopenharmony_ci snd_hdac_ext_stream_init_all 9658c2ecf20Sopenharmony_ci (bus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci err = snd_hdac_bus_alloc_stream_pages(bus); 9688c2ecf20Sopenharmony_ci if (err < 0) 9698c2ecf20Sopenharmony_ci return err; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci return 0; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic int skl_probe(struct pci_dev *pci, 9758c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci struct skl_dev *skl; 9788c2ecf20Sopenharmony_ci struct hdac_bus *bus = NULL; 9798c2ecf20Sopenharmony_ci int err; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci switch (skl_pci_binding) { 9828c2ecf20Sopenharmony_ci case SND_SKL_PCI_BIND_AUTO: 9838c2ecf20Sopenharmony_ci err = snd_intel_dsp_driver_probe(pci); 9848c2ecf20Sopenharmony_ci if (err != SND_INTEL_DSP_DRIVER_ANY && 9858c2ecf20Sopenharmony_ci err != SND_INTEL_DSP_DRIVER_SST) 9868c2ecf20Sopenharmony_ci return -ENODEV; 9878c2ecf20Sopenharmony_ci break; 9888c2ecf20Sopenharmony_ci case SND_SKL_PCI_BIND_LEGACY: 9898c2ecf20Sopenharmony_ci dev_info(&pci->dev, "Module parameter forced binding with HDAudio legacy, aborting probe\n"); 9908c2ecf20Sopenharmony_ci return -ENODEV; 9918c2ecf20Sopenharmony_ci case SND_SKL_PCI_BIND_ASOC: 9928c2ecf20Sopenharmony_ci dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n"); 9938c2ecf20Sopenharmony_ci break; 9948c2ecf20Sopenharmony_ci default: 9958c2ecf20Sopenharmony_ci dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n"); 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* we use ext core ops, so provide NULL for ops here */ 10008c2ecf20Sopenharmony_ci err = skl_create(pci, &skl); 10018c2ecf20Sopenharmony_ci if (err < 0) 10028c2ecf20Sopenharmony_ci return err; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci bus = skl_to_bus(skl); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci err = skl_first_init(bus); 10078c2ecf20Sopenharmony_ci if (err < 0) { 10088c2ecf20Sopenharmony_ci dev_err(bus->dev, "skl_first_init failed with err: %d\n", err); 10098c2ecf20Sopenharmony_ci goto out_free; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci skl->pci_id = pci->device; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci device_disable_async_suspend(bus->dev); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci skl->nhlt = intel_nhlt_init(bus->dev); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (skl->nhlt == NULL) { 10198c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) 10208c2ecf20Sopenharmony_ci dev_err(bus->dev, "no nhlt info found\n"); 10218c2ecf20Sopenharmony_ci err = -ENODEV; 10228c2ecf20Sopenharmony_ci goto out_free; 10238c2ecf20Sopenharmony_ci#else 10248c2ecf20Sopenharmony_ci dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDAudio codec\n"); 10258c2ecf20Sopenharmony_ci#endif 10268c2ecf20Sopenharmony_ci } else { 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci err = skl_nhlt_create_sysfs(skl); 10298c2ecf20Sopenharmony_ci if (err < 0) { 10308c2ecf20Sopenharmony_ci dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err); 10318c2ecf20Sopenharmony_ci goto out_nhlt_free; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci skl_nhlt_update_topology_bin(skl); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* create device for dsp clk */ 10378c2ecf20Sopenharmony_ci err = skl_clock_device_register(skl); 10388c2ecf20Sopenharmony_ci if (err < 0) { 10398c2ecf20Sopenharmony_ci dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err); 10408c2ecf20Sopenharmony_ci goto out_clk_free; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci pci_set_drvdata(skl->pci, bus); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci err = skl_find_machine(skl, (void *)pci_id->driver_data); 10488c2ecf20Sopenharmony_ci if (err < 0) { 10498c2ecf20Sopenharmony_ci dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err); 10508c2ecf20Sopenharmony_ci goto out_nhlt_free; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci err = skl_init_dsp(skl); 10548c2ecf20Sopenharmony_ci if (err < 0) { 10558c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "error failed to register dsp\n"); 10568c2ecf20Sopenharmony_ci goto out_nhlt_free; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci skl->enable_miscbdcge = skl_enable_miscbdcge; 10598c2ecf20Sopenharmony_ci skl->clock_power_gating = skl_clock_power_gating; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (bus->mlcap) 10628c2ecf20Sopenharmony_ci snd_hdac_ext_bus_get_ml_capabilities(bus); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* create device for soc dmic */ 10658c2ecf20Sopenharmony_ci err = skl_dmic_device_register(skl); 10668c2ecf20Sopenharmony_ci if (err < 0) { 10678c2ecf20Sopenharmony_ci dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err); 10688c2ecf20Sopenharmony_ci goto out_dsp_free; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci schedule_work(&skl->probe_work); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci return 0; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ciout_dsp_free: 10768c2ecf20Sopenharmony_ci skl_free_dsp(skl); 10778c2ecf20Sopenharmony_ciout_clk_free: 10788c2ecf20Sopenharmony_ci skl_clock_device_unregister(skl); 10798c2ecf20Sopenharmony_ciout_nhlt_free: 10808c2ecf20Sopenharmony_ci if (skl->nhlt) 10818c2ecf20Sopenharmony_ci intel_nhlt_free(skl->nhlt); 10828c2ecf20Sopenharmony_ciout_free: 10838c2ecf20Sopenharmony_ci skl_free(bus); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci return err; 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic void skl_shutdown(struct pci_dev *pci) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 10918c2ecf20Sopenharmony_ci struct hdac_stream *s; 10928c2ecf20Sopenharmony_ci struct hdac_ext_stream *stream; 10938c2ecf20Sopenharmony_ci struct skl_dev *skl; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (!bus) 10968c2ecf20Sopenharmony_ci return; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci skl = bus_to_skl(bus); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (!skl->init_done) 11018c2ecf20Sopenharmony_ci return; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci snd_hdac_stop_streams(bus); 11048c2ecf20Sopenharmony_ci snd_hdac_ext_bus_link_power_down_all(bus); 11058c2ecf20Sopenharmony_ci skl_dsp_sleep(skl->dsp); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci list_for_each_entry(s, &bus->stream_list, list) { 11088c2ecf20Sopenharmony_ci stream = stream_to_hdac_ext_stream(s); 11098c2ecf20Sopenharmony_ci snd_hdac_ext_stream_decouple(bus, stream, false); 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci snd_hdac_bus_stop_chip(bus); 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic void skl_remove(struct pci_dev *pci) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci struct hdac_bus *bus = pci_get_drvdata(pci); 11188c2ecf20Sopenharmony_ci struct skl_dev *skl = bus_to_skl(bus); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci cancel_work_sync(&skl->probe_work); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&pci->dev); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci /* codec removal, invoke bus_device_remove */ 11258c2ecf20Sopenharmony_ci snd_hdac_ext_bus_device_remove(bus); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci skl_platform_unregister(&pci->dev); 11288c2ecf20Sopenharmony_ci skl_free_dsp(skl); 11298c2ecf20Sopenharmony_ci skl_machine_device_unregister(skl); 11308c2ecf20Sopenharmony_ci skl_dmic_device_unregister(skl); 11318c2ecf20Sopenharmony_ci skl_clock_device_unregister(skl); 11328c2ecf20Sopenharmony_ci skl_nhlt_remove_sysfs(skl); 11338c2ecf20Sopenharmony_ci if (skl->nhlt) 11348c2ecf20Sopenharmony_ci intel_nhlt_free(skl->nhlt); 11358c2ecf20Sopenharmony_ci skl_free(bus); 11368c2ecf20Sopenharmony_ci dev_set_drvdata(&pci->dev, NULL); 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/* PCI IDs */ 11408c2ecf20Sopenharmony_cistatic const struct pci_device_id skl_ids[] = { 11418c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) 11428c2ecf20Sopenharmony_ci /* Sunrise Point-LP */ 11438c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0x9d70), 11448c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines}, 11458c2ecf20Sopenharmony_ci#endif 11468c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) 11478c2ecf20Sopenharmony_ci /* BXT-P */ 11488c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0x5a98), 11498c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines}, 11508c2ecf20Sopenharmony_ci#endif 11518c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) 11528c2ecf20Sopenharmony_ci /* KBL */ 11538c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0x9D71), 11548c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines}, 11558c2ecf20Sopenharmony_ci#endif 11568c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) 11578c2ecf20Sopenharmony_ci /* GLK */ 11588c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0x3198), 11598c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines}, 11608c2ecf20Sopenharmony_ci#endif 11618c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) 11628c2ecf20Sopenharmony_ci /* CNL */ 11638c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0x9dc8), 11648c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, 11658c2ecf20Sopenharmony_ci#endif 11668c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) 11678c2ecf20Sopenharmony_ci /* CFL */ 11688c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0xa348), 11698c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, 11708c2ecf20Sopenharmony_ci#endif 11718c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) 11728c2ecf20Sopenharmony_ci /* CML-LP */ 11738c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0x02c8), 11748c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, 11758c2ecf20Sopenharmony_ci#endif 11768c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) 11778c2ecf20Sopenharmony_ci /* CML-H */ 11788c2ecf20Sopenharmony_ci { PCI_DEVICE(0x8086, 0x06c8), 11798c2ecf20Sopenharmony_ci .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, 11808c2ecf20Sopenharmony_ci#endif 11818c2ecf20Sopenharmony_ci { 0, } 11828c2ecf20Sopenharmony_ci}; 11838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, skl_ids); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci/* pci_driver definition */ 11868c2ecf20Sopenharmony_cistatic struct pci_driver skl_driver = { 11878c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 11888c2ecf20Sopenharmony_ci .id_table = skl_ids, 11898c2ecf20Sopenharmony_ci .probe = skl_probe, 11908c2ecf20Sopenharmony_ci .remove = skl_remove, 11918c2ecf20Sopenharmony_ci .shutdown = skl_shutdown, 11928c2ecf20Sopenharmony_ci .driver = { 11938c2ecf20Sopenharmony_ci .pm = &skl_pm, 11948c2ecf20Sopenharmony_ci }, 11958c2ecf20Sopenharmony_ci}; 11968c2ecf20Sopenharmony_cimodule_pci_driver(skl_driver); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 11998c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Skylake ASoC HDA driver"); 1200