171bb8a1bSVinod Koul // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 271bb8a1bSVinod Koul // Copyright(c) 2015-17 Intel Corporation. 371bb8a1bSVinod Koul 471bb8a1bSVinod Koul /* 571bb8a1bSVinod Koul * Soundwire Intel Master Driver 671bb8a1bSVinod Koul */ 771bb8a1bSVinod Koul 871bb8a1bSVinod Koul #include <linux/acpi.h> 979ee6631SPierre-Louis Bossart #include <linux/debugfs.h> 1071bb8a1bSVinod Koul #include <linux/delay.h> 114abbd783SPaul Gortmaker #include <linux/module.h> 1271bb8a1bSVinod Koul #include <linux/interrupt.h> 13df72b719SPierre-Louis Bossart #include <linux/io.h> 1471bb8a1bSVinod Koul #include <linux/platform_device.h> 1537a2d22bSVinod Koul #include <sound/pcm_params.h> 16ab2c9132SRander Wang #include <linux/pm_runtime.h> 1737a2d22bSVinod Koul #include <sound/soc.h> 1871bb8a1bSVinod Koul #include <linux/soundwire/sdw_registers.h> 1971bb8a1bSVinod Koul #include <linux/soundwire/sdw.h> 2071bb8a1bSVinod Koul #include <linux/soundwire/sdw_intel.h> 2171bb8a1bSVinod Koul #include "cadence_master.h" 2279ee6631SPierre-Louis Bossart #include "bus.h" 2371bb8a1bSVinod Koul #include "intel.h" 2471bb8a1bSVinod Koul 25ebf878edSPierre-Louis Bossart #define INTEL_MASTER_SUSPEND_DELAY_MS 3000 26ebf878edSPierre-Louis Bossart 27ebf878edSPierre-Louis Bossart /* 28ebf878edSPierre-Louis Bossart * debug/config flags for the Intel SoundWire Master. 29ebf878edSPierre-Louis Bossart * 30ebf878edSPierre-Louis Bossart * Since we may have multiple masters active, we can have up to 8 31ebf878edSPierre-Louis Bossart * flags reused in each byte, with master0 using the ls-byte, etc. 32ebf878edSPierre-Louis Bossart */ 33ebf878edSPierre-Louis Bossart 34ebf878edSPierre-Louis Bossart #define SDW_INTEL_MASTER_DISABLE_PM_RUNTIME BIT(0) 35ebf878edSPierre-Louis Bossart #define SDW_INTEL_MASTER_DISABLE_CLOCK_STOP BIT(1) 36a2d9c161SPierre-Louis Bossart #define SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE BIT(2) 37ebf878edSPierre-Louis Bossart 38ebf878edSPierre-Louis Bossart static int md_flags; 39ebf878edSPierre-Louis Bossart module_param_named(sdw_md_flags, md_flags, int, 0444); 40ebf878edSPierre-Louis Bossart MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)"); 41ebf878edSPierre-Louis Bossart 4271bb8a1bSVinod Koul /* Intel SHIM Registers Definition */ 4371bb8a1bSVinod Koul #define SDW_SHIM_LCAP 0x0 4471bb8a1bSVinod Koul #define SDW_SHIM_LCTL 0x4 4571bb8a1bSVinod Koul #define SDW_SHIM_IPPTR 0x8 4671bb8a1bSVinod Koul #define SDW_SHIM_SYNC 0xC 4771bb8a1bSVinod Koul 487cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x)) 497cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x)) 507cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x)) 517cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x)) 527cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x)) 537cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x)) 5471bb8a1bSVinod Koul 557cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y))) 567cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y))) 577cc6e315SPierre-Louis Bossart #define SDW_SHIM_PDMSCAP(x) (0x062 + 0x60 * (x)) 587cc6e315SPierre-Louis Bossart #define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x)) 597cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x)) 6071bb8a1bSVinod Koul 6171bb8a1bSVinod Koul #define SDW_SHIM_WAKEEN 0x190 6271bb8a1bSVinod Koul #define SDW_SHIM_WAKESTS 0x192 6371bb8a1bSVinod Koul 6471bb8a1bSVinod Koul #define SDW_SHIM_LCTL_SPA BIT(0) 6571bb8a1bSVinod Koul #define SDW_SHIM_LCTL_CPA BIT(8) 6671bb8a1bSVinod Koul 674a17c441SPierre-Louis Bossart #define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1) 684a17c441SPierre-Louis Bossart #define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1) 6971bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0) 7071bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCCPU BIT(15) 7171bb8a1bSVinod Koul #define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16) 7271bb8a1bSVinod Koul #define SDW_SHIM_SYNC_CMDSYNC BIT(16) 7371bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCGO BIT(24) 7471bb8a1bSVinod Koul 7571bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0) 7671bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4) 7771bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8) 7871bb8a1bSVinod Koul 7971bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0) 8071bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4) 8171bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8) 8271bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_DIR BIT(15) 8371bb8a1bSVinod Koul 8471bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_ISS GENMASK(3, 0) 8571bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_OSS GENMASK(7, 4) 8671bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_BSS GENMASK(12, 8) 8771bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_CPSS GENMASK(15, 13) 8871bb8a1bSVinod Koul 8971bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_MIF BIT(0) 9071bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_CO BIT(1) 9171bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_COE BIT(2) 9271bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DO BIT(3) 9371bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DOE BIT(4) 9471bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_BKE BIT(5) 9571bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_WPDD BIT(6) 9671bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_CIBD BIT(8) 9771bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DIBD BIT(9) 9871bb8a1bSVinod Koul 9971bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DACTQE BIT(0) 10071bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DODS BIT(1) 10171bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3) 10271bb8a1bSVinod Koul 10371bb8a1bSVinod Koul #define SDW_SHIM_WAKEEN_ENABLE BIT(0) 10471bb8a1bSVinod Koul #define SDW_SHIM_WAKESTS_STATUS BIT(0) 10571bb8a1bSVinod Koul 10671bb8a1bSVinod Koul /* Intel ALH Register definitions */ 1077cc6e315SPierre-Louis Bossart #define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x))) 10879ee6631SPierre-Louis Bossart #define SDW_ALH_NUM_STREAMS 64 10971bb8a1bSVinod Koul 11071bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_DMAT_VAL 0x3 11171bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0) 11271bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16) 11371bb8a1bSVinod Koul 114c46302ecSVinod Koul enum intel_pdi_type { 115c46302ecSVinod Koul INTEL_PDI_IN = 0, 116c46302ecSVinod Koul INTEL_PDI_OUT = 1, 117c46302ecSVinod Koul INTEL_PDI_BD = 2, 118c46302ecSVinod Koul }; 119c46302ecSVinod Koul 12071bb8a1bSVinod Koul #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns) 12171bb8a1bSVinod Koul 12271bb8a1bSVinod Koul /* 12371bb8a1bSVinod Koul * Read, write helpers for HW registers 12471bb8a1bSVinod Koul */ 12571bb8a1bSVinod Koul static inline int intel_readl(void __iomem *base, int offset) 12671bb8a1bSVinod Koul { 12771bb8a1bSVinod Koul return readl(base + offset); 12871bb8a1bSVinod Koul } 12971bb8a1bSVinod Koul 13071bb8a1bSVinod Koul static inline void intel_writel(void __iomem *base, int offset, int value) 13171bb8a1bSVinod Koul { 13271bb8a1bSVinod Koul writel(value, base + offset); 13371bb8a1bSVinod Koul } 13471bb8a1bSVinod Koul 13571bb8a1bSVinod Koul static inline u16 intel_readw(void __iomem *base, int offset) 13671bb8a1bSVinod Koul { 13771bb8a1bSVinod Koul return readw(base + offset); 13871bb8a1bSVinod Koul } 13971bb8a1bSVinod Koul 14071bb8a1bSVinod Koul static inline void intel_writew(void __iomem *base, int offset, u16 value) 14171bb8a1bSVinod Koul { 14271bb8a1bSVinod Koul writew(value, base + offset); 14371bb8a1bSVinod Koul } 14471bb8a1bSVinod Koul 1457d2845d5SPierre-Louis Bossart static int intel_wait_bit(void __iomem *base, int offset, u32 mask, u32 target) 14671bb8a1bSVinod Koul { 14771bb8a1bSVinod Koul int timeout = 10; 14871bb8a1bSVinod Koul u32 reg_read; 14971bb8a1bSVinod Koul 15071bb8a1bSVinod Koul do { 15171bb8a1bSVinod Koul reg_read = readl(base + offset); 1527d2845d5SPierre-Louis Bossart if ((reg_read & mask) == target) 15371bb8a1bSVinod Koul return 0; 15471bb8a1bSVinod Koul 15571bb8a1bSVinod Koul timeout--; 1567d2845d5SPierre-Louis Bossart usleep_range(50, 100); 15771bb8a1bSVinod Koul } while (timeout != 0); 15871bb8a1bSVinod Koul 15971bb8a1bSVinod Koul return -EAGAIN; 16071bb8a1bSVinod Koul } 16171bb8a1bSVinod Koul 1627d2845d5SPierre-Louis Bossart static int intel_clear_bit(void __iomem *base, int offset, u32 value, u32 mask) 1637d2845d5SPierre-Louis Bossart { 1647d2845d5SPierre-Louis Bossart writel(value, base + offset); 1657d2845d5SPierre-Louis Bossart return intel_wait_bit(base, offset, mask, 0); 1667d2845d5SPierre-Louis Bossart } 1677d2845d5SPierre-Louis Bossart 16871bb8a1bSVinod Koul static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask) 16971bb8a1bSVinod Koul { 17071bb8a1bSVinod Koul writel(value, base + offset); 1717d2845d5SPierre-Louis Bossart return intel_wait_bit(base, offset, mask, mask); 17271bb8a1bSVinod Koul } 17371bb8a1bSVinod Koul 17471bb8a1bSVinod Koul /* 17579ee6631SPierre-Louis Bossart * debugfs 17679ee6631SPierre-Louis Bossart */ 17779ee6631SPierre-Louis Bossart #ifdef CONFIG_DEBUG_FS 17879ee6631SPierre-Louis Bossart 17979ee6631SPierre-Louis Bossart #define RD_BUF (2 * PAGE_SIZE) 18079ee6631SPierre-Louis Bossart 18179ee6631SPierre-Louis Bossart static ssize_t intel_sprintf(void __iomem *mem, bool l, 18279ee6631SPierre-Louis Bossart char *buf, size_t pos, unsigned int reg) 18379ee6631SPierre-Louis Bossart { 18479ee6631SPierre-Louis Bossart int value; 18579ee6631SPierre-Louis Bossart 18679ee6631SPierre-Louis Bossart if (l) 18779ee6631SPierre-Louis Bossart value = intel_readl(mem, reg); 18879ee6631SPierre-Louis Bossart else 18979ee6631SPierre-Louis Bossart value = intel_readw(mem, reg); 19079ee6631SPierre-Louis Bossart 19179ee6631SPierre-Louis Bossart return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value); 19279ee6631SPierre-Louis Bossart } 19379ee6631SPierre-Louis Bossart 19479ee6631SPierre-Louis Bossart static int intel_reg_show(struct seq_file *s_file, void *data) 19579ee6631SPierre-Louis Bossart { 19679ee6631SPierre-Louis Bossart struct sdw_intel *sdw = s_file->private; 1972523486bSPierre-Louis Bossart void __iomem *s = sdw->link_res->shim; 1982523486bSPierre-Louis Bossart void __iomem *a = sdw->link_res->alh; 19979ee6631SPierre-Louis Bossart char *buf; 20079ee6631SPierre-Louis Bossart ssize_t ret; 20179ee6631SPierre-Louis Bossart int i, j; 20279ee6631SPierre-Louis Bossart unsigned int links, reg; 20379ee6631SPierre-Louis Bossart 20479ee6631SPierre-Louis Bossart buf = kzalloc(RD_BUF, GFP_KERNEL); 20579ee6631SPierre-Louis Bossart if (!buf) 20679ee6631SPierre-Louis Bossart return -ENOMEM; 20779ee6631SPierre-Louis Bossart 20879ee6631SPierre-Louis Bossart links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0); 20979ee6631SPierre-Louis Bossart 21079ee6631SPierre-Louis Bossart ret = scnprintf(buf, RD_BUF, "Register Value\n"); 21179ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n"); 21279ee6631SPierre-Louis Bossart 21379ee6631SPierre-Louis Bossart for (i = 0; i < links; i++) { 21479ee6631SPierre-Louis Bossart reg = SDW_SHIM_LCAP + i * 4; 21579ee6631SPierre-Louis Bossart ret += intel_sprintf(s, true, buf, ret, reg); 21679ee6631SPierre-Louis Bossart } 21779ee6631SPierre-Louis Bossart 21879ee6631SPierre-Louis Bossart for (i = 0; i < links; i++) { 21979ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i); 22079ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i)); 22179ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i)); 22279ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i)); 22379ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i)); 22479ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i)); 22579ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i)); 22679ee6631SPierre-Louis Bossart 22779ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\n PCMSyCH registers\n"); 22879ee6631SPierre-Louis Bossart 22979ee6631SPierre-Louis Bossart /* 23079ee6631SPierre-Louis Bossart * the value 10 is the number of PDIs. We will need a 23179ee6631SPierre-Louis Bossart * cleanup to remove hard-coded Intel configurations 23279ee6631SPierre-Louis Bossart * from cadence_master.c 23379ee6631SPierre-Louis Bossart */ 23479ee6631SPierre-Louis Bossart for (j = 0; j < 10; j++) { 23579ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, 23679ee6631SPierre-Louis Bossart SDW_SHIM_PCMSYCHM(i, j)); 23779ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, 23879ee6631SPierre-Louis Bossart SDW_SHIM_PCMSYCHC(i, j)); 23979ee6631SPierre-Louis Bossart } 24079ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\n PDMSCAP, IOCTL, CTMCTL\n"); 24179ee6631SPierre-Louis Bossart 24279ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i)); 24379ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i)); 24479ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i)); 24579ee6631SPierre-Louis Bossart } 24679ee6631SPierre-Louis Bossart 24779ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n"); 24879ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN); 24979ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS); 25079ee6631SPierre-Louis Bossart 25179ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n"); 25279ee6631SPierre-Louis Bossart for (i = 0; i < SDW_ALH_NUM_STREAMS; i++) 25379ee6631SPierre-Louis Bossart ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i)); 25479ee6631SPierre-Louis Bossart 25579ee6631SPierre-Louis Bossart seq_printf(s_file, "%s", buf); 25679ee6631SPierre-Louis Bossart kfree(buf); 25779ee6631SPierre-Louis Bossart 25879ee6631SPierre-Louis Bossart return 0; 25979ee6631SPierre-Louis Bossart } 26079ee6631SPierre-Louis Bossart DEFINE_SHOW_ATTRIBUTE(intel_reg); 26179ee6631SPierre-Louis Bossart 26279ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw) 26379ee6631SPierre-Louis Bossart { 26479ee6631SPierre-Louis Bossart struct dentry *root = sdw->cdns.bus.debugfs; 26579ee6631SPierre-Louis Bossart 26679ee6631SPierre-Louis Bossart if (!root) 26779ee6631SPierre-Louis Bossart return; 26879ee6631SPierre-Louis Bossart 26979ee6631SPierre-Louis Bossart sdw->debugfs = debugfs_create_dir("intel-sdw", root); 27079ee6631SPierre-Louis Bossart 27179ee6631SPierre-Louis Bossart debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw, 27279ee6631SPierre-Louis Bossart &intel_reg_fops); 27379ee6631SPierre-Louis Bossart 27479ee6631SPierre-Louis Bossart sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs); 27579ee6631SPierre-Louis Bossart } 27679ee6631SPierre-Louis Bossart 27779ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw) 27879ee6631SPierre-Louis Bossart { 27979ee6631SPierre-Louis Bossart debugfs_remove_recursive(sdw->debugfs); 28079ee6631SPierre-Louis Bossart } 28179ee6631SPierre-Louis Bossart #else 28279ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw) {} 28379ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw) {} 28479ee6631SPierre-Louis Bossart #endif /* CONFIG_DEBUG_FS */ 28579ee6631SPierre-Louis Bossart 28679ee6631SPierre-Louis Bossart /* 28771bb8a1bSVinod Koul * shim ops 28871bb8a1bSVinod Koul */ 28971bb8a1bSVinod Koul 29071bb8a1bSVinod Koul static int intel_link_power_up(struct sdw_intel *sdw) 29171bb8a1bSVinod Koul { 29271bb8a1bSVinod Koul unsigned int link_id = sdw->instance; 2932523486bSPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 2944a17c441SPierre-Louis Bossart u32 *shim_mask = sdw->link_res->shim_mask; 2954a17c441SPierre-Louis Bossart struct sdw_bus *bus = &sdw->cdns.bus; 2964a17c441SPierre-Louis Bossart struct sdw_master_prop *prop = &bus->prop; 29771bb8a1bSVinod Koul int spa_mask, cpa_mask; 2984a17c441SPierre-Louis Bossart int link_control; 2994a17c441SPierre-Louis Bossart int ret = 0; 3004a17c441SPierre-Louis Bossart u32 syncprd; 3014a17c441SPierre-Louis Bossart u32 sync_reg; 3024a17c441SPierre-Louis Bossart 3034a17c441SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock); 3044a17c441SPierre-Louis Bossart 3054a17c441SPierre-Louis Bossart /* 3064a17c441SPierre-Louis Bossart * The hardware relies on an internal counter, typically 4kHz, 3074a17c441SPierre-Louis Bossart * to generate the SoundWire SSP - which defines a 'safe' 3084a17c441SPierre-Louis Bossart * synchronization point between commands and audio transport 3094a17c441SPierre-Louis Bossart * and allows for multi link synchronization. The SYNCPRD value 3104a17c441SPierre-Louis Bossart * is only dependent on the oscillator clock provided to 3114a17c441SPierre-Louis Bossart * the IP, so adjust based on _DSD properties reported in DSDT 3124a17c441SPierre-Louis Bossart * tables. The values reported are based on either 24MHz 3134a17c441SPierre-Louis Bossart * (CNL/CML) or 38.4 MHz (ICL/TGL+). 3144a17c441SPierre-Louis Bossart */ 3154a17c441SPierre-Louis Bossart if (prop->mclk_freq % 6000000) 3164a17c441SPierre-Louis Bossart syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4; 3174a17c441SPierre-Louis Bossart else 3184a17c441SPierre-Louis Bossart syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; 3194a17c441SPierre-Louis Bossart 3204a17c441SPierre-Louis Bossart if (!*shim_mask) { 3214a17c441SPierre-Louis Bossart /* we first need to program the SyncPRD/CPU registers */ 3224a17c441SPierre-Louis Bossart dev_dbg(sdw->cdns.dev, 3234a17c441SPierre-Louis Bossart "%s: first link up, programming SYNCPRD\n", __func__); 3244a17c441SPierre-Louis Bossart 3254a17c441SPierre-Louis Bossart /* set SyncPRD period */ 3264a17c441SPierre-Louis Bossart sync_reg = intel_readl(shim, SDW_SHIM_SYNC); 3274a17c441SPierre-Louis Bossart sync_reg |= (syncprd << 3284a17c441SPierre-Louis Bossart SDW_REG_SHIFT(SDW_SHIM_SYNC_SYNCPRD)); 3294a17c441SPierre-Louis Bossart 3304a17c441SPierre-Louis Bossart /* Set SyncCPU bit */ 3314a17c441SPierre-Louis Bossart sync_reg |= SDW_SHIM_SYNC_SYNCCPU; 3324a17c441SPierre-Louis Bossart intel_writel(shim, SDW_SHIM_SYNC, sync_reg); 3334a17c441SPierre-Louis Bossart } 33471bb8a1bSVinod Koul 33571bb8a1bSVinod Koul /* Link power up sequence */ 33671bb8a1bSVinod Koul link_control = intel_readl(shim, SDW_SHIM_LCTL); 33771bb8a1bSVinod Koul spa_mask = (SDW_SHIM_LCTL_SPA << link_id); 33871bb8a1bSVinod Koul cpa_mask = (SDW_SHIM_LCTL_CPA << link_id); 33971bb8a1bSVinod Koul link_control |= spa_mask; 34071bb8a1bSVinod Koul 34171bb8a1bSVinod Koul ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); 3424a17c441SPierre-Louis Bossart if (ret < 0) { 3434a17c441SPierre-Louis Bossart dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret); 3444a17c441SPierre-Louis Bossart goto out; 34571bb8a1bSVinod Koul } 34671bb8a1bSVinod Koul 3474a17c441SPierre-Louis Bossart if (!*shim_mask) { 3484a17c441SPierre-Louis Bossart /* SyncCPU will change once link is active */ 3494a17c441SPierre-Louis Bossart ret = intel_wait_bit(shim, SDW_SHIM_SYNC, 3504a17c441SPierre-Louis Bossart SDW_SHIM_SYNC_SYNCCPU, 0); 3514a17c441SPierre-Louis Bossart if (ret < 0) { 3524a17c441SPierre-Louis Bossart dev_err(sdw->cdns.dev, 3534a17c441SPierre-Louis Bossart "Failed to set SHIM_SYNC: %d\n", ret); 3544a17c441SPierre-Louis Bossart goto out; 3554a17c441SPierre-Louis Bossart } 3564a17c441SPierre-Louis Bossart } 3574a17c441SPierre-Louis Bossart 3584a17c441SPierre-Louis Bossart *shim_mask |= BIT(link_id); 3594a17c441SPierre-Louis Bossart 3604a17c441SPierre-Louis Bossart sdw->cdns.link_up = true; 3614a17c441SPierre-Louis Bossart out: 3624a17c441SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock); 3634a17c441SPierre-Louis Bossart 3644a17c441SPierre-Louis Bossart return ret; 3654a17c441SPierre-Louis Bossart } 3664a17c441SPierre-Louis Bossart 3674a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */ 3684a17c441SPierre-Louis Bossart static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw) 36971bb8a1bSVinod Koul { 3702523486bSPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 37171bb8a1bSVinod Koul unsigned int link_id = sdw->instance; 3724a17c441SPierre-Louis Bossart u16 ioctl; 37371bb8a1bSVinod Koul 37471bb8a1bSVinod Koul /* Switch to MIP from Glue logic */ 37571bb8a1bSVinod Koul ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); 37671bb8a1bSVinod Koul 37771bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_DOE); 37871bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 3794a17c441SPierre-Louis Bossart usleep_range(10, 15); 38071bb8a1bSVinod Koul 38171bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_DO); 38271bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 3834a17c441SPierre-Louis Bossart usleep_range(10, 15); 38471bb8a1bSVinod Koul 38571bb8a1bSVinod Koul ioctl |= (SDW_SHIM_IOCTL_MIF); 38671bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 3874a17c441SPierre-Louis Bossart usleep_range(10, 15); 38871bb8a1bSVinod Koul 38971bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_BKE); 39071bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_COE); 39171bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 3924a17c441SPierre-Louis Bossart usleep_range(10, 15); 3934a17c441SPierre-Louis Bossart 3944a17c441SPierre-Louis Bossart /* at this point Master IP has full control of the I/Os */ 3954a17c441SPierre-Louis Bossart } 3964a17c441SPierre-Louis Bossart 3974a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */ 3984a17c441SPierre-Louis Bossart static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw) 3994a17c441SPierre-Louis Bossart { 4004a17c441SPierre-Louis Bossart unsigned int link_id = sdw->instance; 4014a17c441SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 4024a17c441SPierre-Louis Bossart u16 ioctl; 4034a17c441SPierre-Louis Bossart 4044a17c441SPierre-Louis Bossart /* Glue logic */ 4054a17c441SPierre-Louis Bossart ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); 4064a17c441SPierre-Louis Bossart ioctl |= SDW_SHIM_IOCTL_BKE; 4074a17c441SPierre-Louis Bossart ioctl |= SDW_SHIM_IOCTL_COE; 4084a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 4094a17c441SPierre-Louis Bossart usleep_range(10, 15); 4104a17c441SPierre-Louis Bossart 4114a17c441SPierre-Louis Bossart ioctl &= ~(SDW_SHIM_IOCTL_MIF); 4124a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 4134a17c441SPierre-Louis Bossart usleep_range(10, 15); 4144a17c441SPierre-Louis Bossart 4154a17c441SPierre-Louis Bossart /* at this point Integration Glue has full control of the I/Os */ 4164a17c441SPierre-Louis Bossart } 4174a17c441SPierre-Louis Bossart 4184a17c441SPierre-Louis Bossart static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) 4194a17c441SPierre-Louis Bossart { 4204a17c441SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 4214a17c441SPierre-Louis Bossart unsigned int link_id = sdw->instance; 4224a17c441SPierre-Louis Bossart int ret = 0; 4234a17c441SPierre-Louis Bossart u16 ioctl = 0, act = 0; 4244a17c441SPierre-Louis Bossart 4254a17c441SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock); 4264a17c441SPierre-Louis Bossart 4274a17c441SPierre-Louis Bossart /* Initialize Shim */ 4284a17c441SPierre-Louis Bossart ioctl |= SDW_SHIM_IOCTL_BKE; 4294a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 4304a17c441SPierre-Louis Bossart usleep_range(10, 15); 4314a17c441SPierre-Louis Bossart 4324a17c441SPierre-Louis Bossart ioctl |= SDW_SHIM_IOCTL_WPDD; 4334a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 4344a17c441SPierre-Louis Bossart usleep_range(10, 15); 4354a17c441SPierre-Louis Bossart 4364a17c441SPierre-Louis Bossart ioctl |= SDW_SHIM_IOCTL_DO; 4374a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 4384a17c441SPierre-Louis Bossart usleep_range(10, 15); 4394a17c441SPierre-Louis Bossart 4404a17c441SPierre-Louis Bossart ioctl |= SDW_SHIM_IOCTL_DOE; 4414a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 4424a17c441SPierre-Louis Bossart usleep_range(10, 15); 4434a17c441SPierre-Louis Bossart 4444a17c441SPierre-Louis Bossart intel_shim_glue_to_master_ip(sdw); 44571bb8a1bSVinod Koul 44671bb8a1bSVinod Koul act |= 0x1 << SDW_REG_SHIFT(SDW_SHIM_CTMCTL_DOAIS); 44771bb8a1bSVinod Koul act |= SDW_SHIM_CTMCTL_DACTQE; 44871bb8a1bSVinod Koul act |= SDW_SHIM_CTMCTL_DODS; 44971bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act); 4504a17c441SPierre-Louis Bossart usleep_range(10, 15); 45171bb8a1bSVinod Koul 4524a17c441SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock); 45371bb8a1bSVinod Koul 45471bb8a1bSVinod Koul return ret; 45571bb8a1bSVinod Koul } 45671bb8a1bSVinod Koul 457ab2c9132SRander Wang static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) 4584a17c441SPierre-Louis Bossart { 4594a17c441SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 4604a17c441SPierre-Louis Bossart unsigned int link_id = sdw->instance; 4614a17c441SPierre-Louis Bossart u16 wake_en, wake_sts; 4624a17c441SPierre-Louis Bossart 4634a17c441SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock); 4644a17c441SPierre-Louis Bossart wake_en = intel_readw(shim, SDW_SHIM_WAKEEN); 4654a17c441SPierre-Louis Bossart 4664a17c441SPierre-Louis Bossart if (wake_enable) { 4674a17c441SPierre-Louis Bossart /* Enable the wakeup */ 4684a17c441SPierre-Louis Bossart wake_en |= (SDW_SHIM_WAKEEN_ENABLE << link_id); 4694a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_WAKEEN, wake_en); 4704a17c441SPierre-Louis Bossart } else { 4714a17c441SPierre-Louis Bossart /* Disable the wake up interrupt */ 4724a17c441SPierre-Louis Bossart wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id); 4734a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_WAKEEN, wake_en); 4744a17c441SPierre-Louis Bossart 4754a17c441SPierre-Louis Bossart /* Clear wake status */ 4764a17c441SPierre-Louis Bossart wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); 4774a17c441SPierre-Louis Bossart wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id); 4784a17c441SPierre-Louis Bossart intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); 4794a17c441SPierre-Louis Bossart } 4804a17c441SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock); 4814a17c441SPierre-Louis Bossart } 4824a17c441SPierre-Louis Bossart 4839b3b4b3fSPierre-Louis Bossart static int intel_link_power_down(struct sdw_intel *sdw) 4844a17c441SPierre-Louis Bossart { 4854a17c441SPierre-Louis Bossart int link_control, spa_mask, cpa_mask; 4864a17c441SPierre-Louis Bossart unsigned int link_id = sdw->instance; 4874a17c441SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 4884a17c441SPierre-Louis Bossart u32 *shim_mask = sdw->link_res->shim_mask; 4894a17c441SPierre-Louis Bossart int ret = 0; 4904a17c441SPierre-Louis Bossart 4914a17c441SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock); 4924a17c441SPierre-Louis Bossart 4934a17c441SPierre-Louis Bossart intel_shim_master_ip_to_glue(sdw); 4944a17c441SPierre-Louis Bossart 4954a17c441SPierre-Louis Bossart /* Link power down sequence */ 4964a17c441SPierre-Louis Bossart link_control = intel_readl(shim, SDW_SHIM_LCTL); 4974a17c441SPierre-Louis Bossart spa_mask = ~(SDW_SHIM_LCTL_SPA << link_id); 4984a17c441SPierre-Louis Bossart cpa_mask = (SDW_SHIM_LCTL_CPA << link_id); 4994a17c441SPierre-Louis Bossart link_control &= spa_mask; 5004a17c441SPierre-Louis Bossart 5014a17c441SPierre-Louis Bossart ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); 5024a17c441SPierre-Louis Bossart 5034a17c441SPierre-Louis Bossart if (!(*shim_mask & BIT(link_id))) 5044a17c441SPierre-Louis Bossart dev_err(sdw->cdns.dev, 5054a17c441SPierre-Louis Bossart "%s: Unbalanced power-up/down calls\n", __func__); 5064a17c441SPierre-Louis Bossart 5074a17c441SPierre-Louis Bossart *shim_mask &= ~BIT(link_id); 5084a17c441SPierre-Louis Bossart 5094a17c441SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock); 5104a17c441SPierre-Louis Bossart 51171bb8a1bSVinod Koul if (ret < 0) 5124a17c441SPierre-Louis Bossart return ret; 5134a17c441SPierre-Louis Bossart 5144a17c441SPierre-Louis Bossart sdw->cdns.link_up = false; 5154a17c441SPierre-Louis Bossart return 0; 5164a17c441SPierre-Louis Bossart } 5174a17c441SPierre-Louis Bossart 51802629e45SPierre-Louis Bossart static void intel_shim_sync_arm(struct sdw_intel *sdw) 51902629e45SPierre-Louis Bossart { 52002629e45SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 52102629e45SPierre-Louis Bossart u32 sync_reg; 52202629e45SPierre-Louis Bossart 52302629e45SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock); 52402629e45SPierre-Louis Bossart 52502629e45SPierre-Louis Bossart /* update SYNC register */ 52602629e45SPierre-Louis Bossart sync_reg = intel_readl(shim, SDW_SHIM_SYNC); 52702629e45SPierre-Louis Bossart sync_reg |= (SDW_SHIM_SYNC_CMDSYNC << sdw->instance); 52802629e45SPierre-Louis Bossart intel_writel(shim, SDW_SHIM_SYNC, sync_reg); 52902629e45SPierre-Louis Bossart 53002629e45SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock); 53102629e45SPierre-Louis Bossart } 53202629e45SPierre-Louis Bossart 533437e3289SPierre-Louis Bossart static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw) 534437e3289SPierre-Louis Bossart { 535437e3289SPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 536437e3289SPierre-Louis Bossart u32 sync_reg; 537437e3289SPierre-Louis Bossart int ret; 538437e3289SPierre-Louis Bossart 539437e3289SPierre-Louis Bossart /* Read SYNC register */ 540437e3289SPierre-Louis Bossart sync_reg = intel_readl(shim, SDW_SHIM_SYNC); 541437e3289SPierre-Louis Bossart 542437e3289SPierre-Louis Bossart /* 543437e3289SPierre-Louis Bossart * Set SyncGO bit to synchronously trigger a bank switch for 544437e3289SPierre-Louis Bossart * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all 545437e3289SPierre-Louis Bossart * the Masters. 546437e3289SPierre-Louis Bossart */ 547437e3289SPierre-Louis Bossart sync_reg |= SDW_SHIM_SYNC_SYNCGO; 548437e3289SPierre-Louis Bossart 549437e3289SPierre-Louis Bossart ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, 550437e3289SPierre-Louis Bossart SDW_SHIM_SYNC_SYNCGO); 551437e3289SPierre-Louis Bossart 552437e3289SPierre-Louis Bossart if (ret < 0) 553437e3289SPierre-Louis Bossart dev_err(sdw->cdns.dev, "SyncGO clear failed: %d\n", ret); 55471bb8a1bSVinod Koul 55571bb8a1bSVinod Koul return ret; 55671bb8a1bSVinod Koul } 55771bb8a1bSVinod Koul 55837a2d22bSVinod Koul /* 55937a2d22bSVinod Koul * PDI routines 56037a2d22bSVinod Koul */ 56137a2d22bSVinod Koul static void intel_pdi_init(struct sdw_intel *sdw, 56237a2d22bSVinod Koul struct sdw_cdns_stream_config *config) 56337a2d22bSVinod Koul { 5642523486bSPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 56537a2d22bSVinod Koul unsigned int link_id = sdw->instance; 56637a2d22bSVinod Koul int pcm_cap, pdm_cap; 56737a2d22bSVinod Koul 56837a2d22bSVinod Koul /* PCM Stream Capability */ 56937a2d22bSVinod Koul pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id)); 57037a2d22bSVinod Koul 57137a2d22bSVinod Koul config->pcm_bd = (pcm_cap & SDW_SHIM_PCMSCAP_BSS) >> 57237a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_BSS); 57337a2d22bSVinod Koul config->pcm_in = (pcm_cap & SDW_SHIM_PCMSCAP_ISS) >> 57437a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_ISS); 57537a2d22bSVinod Koul config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >> 57637a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS); 57737a2d22bSVinod Koul 578121f4361SPierre-Louis Bossart dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n", 579121f4361SPierre-Louis Bossart config->pcm_bd, config->pcm_in, config->pcm_out); 580121f4361SPierre-Louis Bossart 58137a2d22bSVinod Koul /* PDM Stream Capability */ 58237a2d22bSVinod Koul pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); 58337a2d22bSVinod Koul 58437a2d22bSVinod Koul config->pdm_bd = (pdm_cap & SDW_SHIM_PDMSCAP_BSS) >> 58537a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_BSS); 58637a2d22bSVinod Koul config->pdm_in = (pdm_cap & SDW_SHIM_PDMSCAP_ISS) >> 58737a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS); 58837a2d22bSVinod Koul config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >> 58937a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS); 590121f4361SPierre-Louis Bossart 591121f4361SPierre-Louis Bossart dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n", 592121f4361SPierre-Louis Bossart config->pdm_bd, config->pdm_in, config->pdm_out); 59337a2d22bSVinod Koul } 59437a2d22bSVinod Koul 59537a2d22bSVinod Koul static int 59637a2d22bSVinod Koul intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm) 59737a2d22bSVinod Koul { 5982523486bSPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 59937a2d22bSVinod Koul unsigned int link_id = sdw->instance; 60037a2d22bSVinod Koul int count; 60137a2d22bSVinod Koul 60237a2d22bSVinod Koul if (pcm) { 60337a2d22bSVinod Koul count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num)); 60418046335SPierre-Louis Bossart 60518046335SPierre-Louis Bossart /* 60618046335SPierre-Louis Bossart * WORKAROUND: on all existing Intel controllers, pdi 60718046335SPierre-Louis Bossart * number 2 reports channel count as 1 even though it 60818046335SPierre-Louis Bossart * supports 8 channels. Performing hardcoding for pdi 60918046335SPierre-Louis Bossart * number 2. 61018046335SPierre-Louis Bossart */ 61118046335SPierre-Louis Bossart if (pdi_num == 2) 61218046335SPierre-Louis Bossart count = 7; 61318046335SPierre-Louis Bossart 61437a2d22bSVinod Koul } else { 61537a2d22bSVinod Koul count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); 61637a2d22bSVinod Koul count = ((count & SDW_SHIM_PDMSCAP_CPSS) >> 61737a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_CPSS)); 61837a2d22bSVinod Koul } 61937a2d22bSVinod Koul 62037a2d22bSVinod Koul /* zero based values for channel count in register */ 62137a2d22bSVinod Koul count++; 62237a2d22bSVinod Koul 62337a2d22bSVinod Koul return count; 62437a2d22bSVinod Koul } 62537a2d22bSVinod Koul 62637a2d22bSVinod Koul static int intel_pdi_get_ch_update(struct sdw_intel *sdw, 62737a2d22bSVinod Koul struct sdw_cdns_pdi *pdi, 62837a2d22bSVinod Koul unsigned int num_pdi, 62937a2d22bSVinod Koul unsigned int *num_ch, bool pcm) 63037a2d22bSVinod Koul { 63137a2d22bSVinod Koul int i, ch_count = 0; 63237a2d22bSVinod Koul 63337a2d22bSVinod Koul for (i = 0; i < num_pdi; i++) { 63437a2d22bSVinod Koul pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm); 63537a2d22bSVinod Koul ch_count += pdi->ch_count; 63637a2d22bSVinod Koul pdi++; 63737a2d22bSVinod Koul } 63837a2d22bSVinod Koul 63937a2d22bSVinod Koul *num_ch = ch_count; 64037a2d22bSVinod Koul return 0; 64137a2d22bSVinod Koul } 64237a2d22bSVinod Koul 64337a2d22bSVinod Koul static int intel_pdi_stream_ch_update(struct sdw_intel *sdw, 64437a2d22bSVinod Koul struct sdw_cdns_streams *stream, bool pcm) 64537a2d22bSVinod Koul { 64637a2d22bSVinod Koul intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd, 64737a2d22bSVinod Koul &stream->num_ch_bd, pcm); 64837a2d22bSVinod Koul 64937a2d22bSVinod Koul intel_pdi_get_ch_update(sdw, stream->in, stream->num_in, 65037a2d22bSVinod Koul &stream->num_ch_in, pcm); 65137a2d22bSVinod Koul 65237a2d22bSVinod Koul intel_pdi_get_ch_update(sdw, stream->out, stream->num_out, 65337a2d22bSVinod Koul &stream->num_ch_out, pcm); 65437a2d22bSVinod Koul 65537a2d22bSVinod Koul return 0; 65637a2d22bSVinod Koul } 65737a2d22bSVinod Koul 65837a2d22bSVinod Koul static int intel_pdi_ch_update(struct sdw_intel *sdw) 65937a2d22bSVinod Koul { 66037a2d22bSVinod Koul /* First update PCM streams followed by PDM streams */ 66137a2d22bSVinod Koul intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true); 66237a2d22bSVinod Koul intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false); 66337a2d22bSVinod Koul 66437a2d22bSVinod Koul return 0; 66537a2d22bSVinod Koul } 66637a2d22bSVinod Koul 66737a2d22bSVinod Koul static void 66837a2d22bSVinod Koul intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) 66937a2d22bSVinod Koul { 6702523486bSPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 67137a2d22bSVinod Koul unsigned int link_id = sdw->instance; 67237a2d22bSVinod Koul int pdi_conf = 0; 67337a2d22bSVinod Koul 674c134f914SPierre-Louis Bossart /* the Bulk and PCM streams are not contiguous */ 675c134f914SPierre-Louis Bossart pdi->intel_alh_id = (link_id * 16) + pdi->num + 3; 676c134f914SPierre-Louis Bossart if (pdi->num >= 2) 677c134f914SPierre-Louis Bossart pdi->intel_alh_id += 2; 67837a2d22bSVinod Koul 67937a2d22bSVinod Koul /* 68037a2d22bSVinod Koul * Program stream parameters to stream SHIM register 68137a2d22bSVinod Koul * This is applicable for PCM stream only. 68237a2d22bSVinod Koul */ 68337a2d22bSVinod Koul if (pdi->type != SDW_STREAM_PCM) 68437a2d22bSVinod Koul return; 68537a2d22bSVinod Koul 68637a2d22bSVinod Koul if (pdi->dir == SDW_DATA_DIR_RX) 68737a2d22bSVinod Koul pdi_conf |= SDW_SHIM_PCMSYCM_DIR; 68837a2d22bSVinod Koul else 68937a2d22bSVinod Koul pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR); 69037a2d22bSVinod Koul 69137a2d22bSVinod Koul pdi_conf |= (pdi->intel_alh_id << 69237a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_STREAM)); 69337a2d22bSVinod Koul pdi_conf |= (pdi->l_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_LCHN)); 69437a2d22bSVinod Koul pdi_conf |= (pdi->h_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_HCHN)); 69537a2d22bSVinod Koul 69637a2d22bSVinod Koul intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf); 69737a2d22bSVinod Koul } 69837a2d22bSVinod Koul 69937a2d22bSVinod Koul static void 70037a2d22bSVinod Koul intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) 70137a2d22bSVinod Koul { 7022523486bSPierre-Louis Bossart void __iomem *alh = sdw->link_res->alh; 70337a2d22bSVinod Koul unsigned int link_id = sdw->instance; 70437a2d22bSVinod Koul unsigned int conf; 70537a2d22bSVinod Koul 706c134f914SPierre-Louis Bossart /* the Bulk and PCM streams are not contiguous */ 707c134f914SPierre-Louis Bossart pdi->intel_alh_id = (link_id * 16) + pdi->num + 3; 708c134f914SPierre-Louis Bossart if (pdi->num >= 2) 709c134f914SPierre-Louis Bossart pdi->intel_alh_id += 2; 71037a2d22bSVinod Koul 71137a2d22bSVinod Koul /* Program Stream config ALH register */ 71237a2d22bSVinod Koul conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id)); 71337a2d22bSVinod Koul 71437a2d22bSVinod Koul conf |= (SDW_ALH_STRMZCFG_DMAT_VAL << 71537a2d22bSVinod Koul SDW_REG_SHIFT(SDW_ALH_STRMZCFG_DMAT)); 71637a2d22bSVinod Koul 71737a2d22bSVinod Koul conf |= ((pdi->ch_count - 1) << 71837a2d22bSVinod Koul SDW_REG_SHIFT(SDW_ALH_STRMZCFG_CHN)); 71937a2d22bSVinod Koul 72037a2d22bSVinod Koul intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf); 72137a2d22bSVinod Koul } 72237a2d22bSVinod Koul 7234b206d34SRander Wang static int intel_params_stream(struct sdw_intel *sdw, 724c46302ecSVinod Koul struct snd_pcm_substream *substream, 725c46302ecSVinod Koul struct snd_soc_dai *dai, 7264b206d34SRander Wang struct snd_pcm_hw_params *hw_params, 7274b206d34SRander Wang int link_id, int alh_stream_id) 728c46302ecSVinod Koul { 7292523486bSPierre-Louis Bossart struct sdw_intel_link_res *res = sdw->link_res; 7304b206d34SRander Wang struct sdw_intel_stream_params_data params_data; 73105c8afe4SPierre-Louis Bossart 7324b206d34SRander Wang params_data.substream = substream; 7334b206d34SRander Wang params_data.dai = dai; 7344b206d34SRander Wang params_data.hw_params = hw_params; 7354b206d34SRander Wang params_data.link_id = link_id; 7364b206d34SRander Wang params_data.alh_stream_id = alh_stream_id; 737c46302ecSVinod Koul 7384b206d34SRander Wang if (res->ops && res->ops->params_stream && res->dev) 7394b206d34SRander Wang return res->ops->params_stream(res->dev, 7404b206d34SRander Wang ¶ms_data); 741c46302ecSVinod Koul return -EIO; 742c46302ecSVinod Koul } 743c46302ecSVinod Koul 744eff346f2SPierre-Louis Bossart static int intel_free_stream(struct sdw_intel *sdw, 745eff346f2SPierre-Louis Bossart struct snd_pcm_substream *substream, 746eff346f2SPierre-Louis Bossart struct snd_soc_dai *dai, 747eff346f2SPierre-Louis Bossart int link_id) 748eff346f2SPierre-Louis Bossart { 749eff346f2SPierre-Louis Bossart struct sdw_intel_link_res *res = sdw->link_res; 750eff346f2SPierre-Louis Bossart struct sdw_intel_stream_free_data free_data; 751eff346f2SPierre-Louis Bossart 752eff346f2SPierre-Louis Bossart free_data.substream = substream; 753eff346f2SPierre-Louis Bossart free_data.dai = dai; 754eff346f2SPierre-Louis Bossart free_data.link_id = link_id; 755eff346f2SPierre-Louis Bossart 756eff346f2SPierre-Louis Bossart if (res->ops && res->ops->free_stream && res->dev) 757eff346f2SPierre-Louis Bossart return res->ops->free_stream(res->dev, 758eff346f2SPierre-Louis Bossart &free_data); 759eff346f2SPierre-Louis Bossart 760eff346f2SPierre-Louis Bossart return 0; 761eff346f2SPierre-Louis Bossart } 762eff346f2SPierre-Louis Bossart 763c46302ecSVinod Koul /* 76430246e2dSShreyas NC * bank switch routines 76530246e2dSShreyas NC */ 76630246e2dSShreyas NC 76730246e2dSShreyas NC static int intel_pre_bank_switch(struct sdw_bus *bus) 76830246e2dSShreyas NC { 76930246e2dSShreyas NC struct sdw_cdns *cdns = bus_to_cdns(bus); 77030246e2dSShreyas NC struct sdw_intel *sdw = cdns_to_intel(cdns); 77130246e2dSShreyas NC 77230246e2dSShreyas NC /* Write to register only for multi-link */ 77330246e2dSShreyas NC if (!bus->multi_link) 77430246e2dSShreyas NC return 0; 77530246e2dSShreyas NC 77602629e45SPierre-Louis Bossart intel_shim_sync_arm(sdw); 77730246e2dSShreyas NC 77830246e2dSShreyas NC return 0; 77930246e2dSShreyas NC } 78030246e2dSShreyas NC 78130246e2dSShreyas NC static int intel_post_bank_switch(struct sdw_bus *bus) 78230246e2dSShreyas NC { 78330246e2dSShreyas NC struct sdw_cdns *cdns = bus_to_cdns(bus); 78430246e2dSShreyas NC struct sdw_intel *sdw = cdns_to_intel(cdns); 7852523486bSPierre-Louis Bossart void __iomem *shim = sdw->link_res->shim; 78630246e2dSShreyas NC int sync_reg, ret; 78730246e2dSShreyas NC 78830246e2dSShreyas NC /* Write to register only for multi-link */ 78930246e2dSShreyas NC if (!bus->multi_link) 79030246e2dSShreyas NC return 0; 79130246e2dSShreyas NC 7924a17c441SPierre-Louis Bossart mutex_lock(sdw->link_res->shim_lock); 7934a17c441SPierre-Louis Bossart 79430246e2dSShreyas NC /* Read SYNC register */ 79530246e2dSShreyas NC sync_reg = intel_readl(shim, SDW_SHIM_SYNC); 79630246e2dSShreyas NC 79730246e2dSShreyas NC /* 79830246e2dSShreyas NC * post_bank_switch() ops is called from the bus in loop for 79930246e2dSShreyas NC * all the Masters in the steam with the expectation that 80030246e2dSShreyas NC * we trigger the bankswitch for the only first Master in the list 80130246e2dSShreyas NC * and do nothing for the other Masters 80230246e2dSShreyas NC * 80330246e2dSShreyas NC * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master. 80430246e2dSShreyas NC */ 8054a17c441SPierre-Louis Bossart if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) { 8064a17c441SPierre-Louis Bossart ret = 0; 8074a17c441SPierre-Louis Bossart goto unlock; 8084a17c441SPierre-Louis Bossart } 80930246e2dSShreyas NC 810437e3289SPierre-Louis Bossart ret = intel_shim_sync_go_unlocked(sdw); 8114a17c441SPierre-Louis Bossart unlock: 8124a17c441SPierre-Louis Bossart mutex_unlock(sdw->link_res->shim_lock); 81330246e2dSShreyas NC 81430246e2dSShreyas NC if (ret < 0) 81517ed5befSPierre-Louis Bossart dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret); 81630246e2dSShreyas NC 81730246e2dSShreyas NC return ret; 81830246e2dSShreyas NC } 81930246e2dSShreyas NC 82030246e2dSShreyas NC /* 821c46302ecSVinod Koul * DAI routines 822c46302ecSVinod Koul */ 823c46302ecSVinod Koul 8245e7484d0SRander Wang static int intel_startup(struct snd_pcm_substream *substream, 8255e7484d0SRander Wang struct snd_soc_dai *dai) 8265e7484d0SRander Wang { 827ebf878edSPierre-Louis Bossart struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 828ebf878edSPierre-Louis Bossart int ret; 829ebf878edSPierre-Louis Bossart 830ebf878edSPierre-Louis Bossart ret = pm_runtime_get_sync(cdns->dev); 831ebf878edSPierre-Louis Bossart if (ret < 0 && ret != -EACCES) { 832ebf878edSPierre-Louis Bossart dev_err_ratelimited(cdns->dev, 833ebf878edSPierre-Louis Bossart "pm_runtime_get_sync failed in %s, ret %d\n", 834ebf878edSPierre-Louis Bossart __func__, ret); 835ebf878edSPierre-Louis Bossart pm_runtime_put_noidle(cdns->dev); 836ebf878edSPierre-Louis Bossart return ret; 837ebf878edSPierre-Louis Bossart } 838ff16d1e5SPierre-Louis Bossart return 0; 8395e7484d0SRander Wang } 8405e7484d0SRander Wang 841c46302ecSVinod Koul static int intel_hw_params(struct snd_pcm_substream *substream, 842c46302ecSVinod Koul struct snd_pcm_hw_params *params, 843c46302ecSVinod Koul struct snd_soc_dai *dai) 844c46302ecSVinod Koul { 845c46302ecSVinod Koul struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 846c46302ecSVinod Koul struct sdw_intel *sdw = cdns_to_intel(cdns); 847c46302ecSVinod Koul struct sdw_cdns_dma_data *dma; 84857a34790SPierre-Louis Bossart struct sdw_cdns_pdi *pdi; 849c46302ecSVinod Koul struct sdw_stream_config sconfig; 850c46302ecSVinod Koul struct sdw_port_config *pconfig; 85157a34790SPierre-Louis Bossart int ch, dir; 85257a34790SPierre-Louis Bossart int ret; 853c46302ecSVinod Koul bool pcm = true; 854c46302ecSVinod Koul 855c46302ecSVinod Koul dma = snd_soc_dai_get_dma_data(dai, substream); 856c46302ecSVinod Koul if (!dma) 857c46302ecSVinod Koul return -EIO; 858c46302ecSVinod Koul 859c46302ecSVinod Koul ch = params_channels(params); 860c46302ecSVinod Koul if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 861c46302ecSVinod Koul dir = SDW_DATA_DIR_RX; 862c46302ecSVinod Koul else 863c46302ecSVinod Koul dir = SDW_DATA_DIR_TX; 864c46302ecSVinod Koul 86557a34790SPierre-Louis Bossart if (dma->stream_type == SDW_STREAM_PDM) 866c46302ecSVinod Koul pcm = false; 867c46302ecSVinod Koul 86857a34790SPierre-Louis Bossart if (pcm) 8691b53385eSBard Liao pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id); 87057a34790SPierre-Louis Bossart else 8711b53385eSBard Liao pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id); 872c46302ecSVinod Koul 87357a34790SPierre-Louis Bossart if (!pdi) { 874c46302ecSVinod Koul ret = -EINVAL; 87557a34790SPierre-Louis Bossart goto error; 876c46302ecSVinod Koul } 87757a34790SPierre-Louis Bossart 87857a34790SPierre-Louis Bossart /* do run-time configurations for SHIM, ALH and PDI/PORT */ 87957a34790SPierre-Louis Bossart intel_pdi_shim_configure(sdw, pdi); 88057a34790SPierre-Louis Bossart intel_pdi_alh_configure(sdw, pdi); 88157a34790SPierre-Louis Bossart sdw_cdns_config_stream(cdns, ch, dir, pdi); 88257a34790SPierre-Louis Bossart 883a5a0239cSBard Liao /* store pdi and hw_params, may be needed in prepare step */ 884a5a0239cSBard Liao dma->suspended = false; 885a5a0239cSBard Liao dma->pdi = pdi; 886a5a0239cSBard Liao dma->hw_params = params; 887c46302ecSVinod Koul 888c46302ecSVinod Koul /* Inform DSP about PDI stream number */ 8894b206d34SRander Wang ret = intel_params_stream(sdw, substream, dai, params, 8904b206d34SRander Wang sdw->instance, 89157a34790SPierre-Louis Bossart pdi->intel_alh_id); 892c46302ecSVinod Koul if (ret) 89357a34790SPierre-Louis Bossart goto error; 894c46302ecSVinod Koul 895c46302ecSVinod Koul sconfig.direction = dir; 896c46302ecSVinod Koul sconfig.ch_count = ch; 897c46302ecSVinod Koul sconfig.frame_rate = params_rate(params); 898c46302ecSVinod Koul sconfig.type = dma->stream_type; 899c46302ecSVinod Koul 900c46302ecSVinod Koul if (dma->stream_type == SDW_STREAM_PDM) { 901c46302ecSVinod Koul sconfig.frame_rate *= 50; 902c46302ecSVinod Koul sconfig.bps = 1; 903c46302ecSVinod Koul } else { 904c46302ecSVinod Koul sconfig.bps = snd_pcm_format_width(params_format(params)); 905c46302ecSVinod Koul } 906c46302ecSVinod Koul 907c46302ecSVinod Koul /* Port configuration */ 90857a34790SPierre-Louis Bossart pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL); 909c46302ecSVinod Koul if (!pconfig) { 910c46302ecSVinod Koul ret = -ENOMEM; 91157a34790SPierre-Louis Bossart goto error; 912c46302ecSVinod Koul } 913c46302ecSVinod Koul 91457a34790SPierre-Louis Bossart pconfig->num = pdi->num; 91557a34790SPierre-Louis Bossart pconfig->ch_mask = (1 << ch) - 1; 916c46302ecSVinod Koul 917c46302ecSVinod Koul ret = sdw_stream_add_master(&cdns->bus, &sconfig, 91857a34790SPierre-Louis Bossart pconfig, 1, dma->stream); 91957a34790SPierre-Louis Bossart if (ret) 92017ed5befSPierre-Louis Bossart dev_err(cdns->dev, "add master to stream failed:%d\n", ret); 921c46302ecSVinod Koul 922c46302ecSVinod Koul kfree(pconfig); 92357a34790SPierre-Louis Bossart error: 924c46302ecSVinod Koul return ret; 925c46302ecSVinod Koul } 926c46302ecSVinod Koul 92727b198f4SRander Wang static int intel_prepare(struct snd_pcm_substream *substream, 92827b198f4SRander Wang struct snd_soc_dai *dai) 92927b198f4SRander Wang { 930a5a0239cSBard Liao struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 931a5a0239cSBard Liao struct sdw_intel *sdw = cdns_to_intel(cdns); 93227b198f4SRander Wang struct sdw_cdns_dma_data *dma; 933a5a0239cSBard Liao int ch, dir; 934a5a0239cSBard Liao int ret; 93527b198f4SRander Wang 93627b198f4SRander Wang dma = snd_soc_dai_get_dma_data(dai, substream); 93727b198f4SRander Wang if (!dma) { 93827b198f4SRander Wang dev_err(dai->dev, "failed to get dma data in %s", 93927b198f4SRander Wang __func__); 94027b198f4SRander Wang return -EIO; 94127b198f4SRander Wang } 94227b198f4SRander Wang 943a5a0239cSBard Liao if (dma->suspended) { 944a5a0239cSBard Liao dma->suspended = false; 945a5a0239cSBard Liao 946a5a0239cSBard Liao /* 947a5a0239cSBard Liao * .prepare() is called after system resume, where we 948a5a0239cSBard Liao * need to reinitialize the SHIM/ALH/Cadence IP. 949a5a0239cSBard Liao * .prepare() is also called to deal with underflows, 950a5a0239cSBard Liao * but in those cases we cannot touch ALH/SHIM 951a5a0239cSBard Liao * registers 952a5a0239cSBard Liao */ 953a5a0239cSBard Liao 954a5a0239cSBard Liao /* configure stream */ 955a5a0239cSBard Liao ch = params_channels(dma->hw_params); 956a5a0239cSBard Liao if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 957a5a0239cSBard Liao dir = SDW_DATA_DIR_RX; 958a5a0239cSBard Liao else 959a5a0239cSBard Liao dir = SDW_DATA_DIR_TX; 960a5a0239cSBard Liao 961a5a0239cSBard Liao intel_pdi_shim_configure(sdw, dma->pdi); 962a5a0239cSBard Liao intel_pdi_alh_configure(sdw, dma->pdi); 963a5a0239cSBard Liao sdw_cdns_config_stream(cdns, ch, dir, dma->pdi); 964a5a0239cSBard Liao 965a5a0239cSBard Liao /* Inform DSP about PDI stream number */ 966a5a0239cSBard Liao ret = intel_params_stream(sdw, substream, dai, 967a5a0239cSBard Liao dma->hw_params, 968a5a0239cSBard Liao sdw->instance, 969a5a0239cSBard Liao dma->pdi->intel_alh_id); 970a5a0239cSBard Liao if (ret) 971a5a0239cSBard Liao goto err; 972a5a0239cSBard Liao } 973a5a0239cSBard Liao 974a5a0239cSBard Liao ret = sdw_prepare_stream(dma->stream); 975a5a0239cSBard Liao 976a5a0239cSBard Liao err: 977a5a0239cSBard Liao return ret; 97827b198f4SRander Wang } 97927b198f4SRander Wang 980973a8429SRander Wang static int intel_trigger(struct snd_pcm_substream *substream, int cmd, 981973a8429SRander Wang struct snd_soc_dai *dai) 982973a8429SRander Wang { 983973a8429SRander Wang struct sdw_cdns_dma_data *dma; 984973a8429SRander Wang int ret; 985973a8429SRander Wang 986973a8429SRander Wang dma = snd_soc_dai_get_dma_data(dai, substream); 987973a8429SRander Wang if (!dma) { 988973a8429SRander Wang dev_err(dai->dev, "failed to get dma data in %s", __func__); 989973a8429SRander Wang return -EIO; 990973a8429SRander Wang } 991973a8429SRander Wang 992973a8429SRander Wang switch (cmd) { 993973a8429SRander Wang case SNDRV_PCM_TRIGGER_START: 994973a8429SRander Wang case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 995973a8429SRander Wang case SNDRV_PCM_TRIGGER_RESUME: 996973a8429SRander Wang ret = sdw_enable_stream(dma->stream); 997973a8429SRander Wang break; 998973a8429SRander Wang 999973a8429SRander Wang case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1000973a8429SRander Wang case SNDRV_PCM_TRIGGER_SUSPEND: 1001973a8429SRander Wang case SNDRV_PCM_TRIGGER_STOP: 1002973a8429SRander Wang ret = sdw_disable_stream(dma->stream); 1003973a8429SRander Wang break; 1004973a8429SRander Wang 1005973a8429SRander Wang default: 1006973a8429SRander Wang ret = -EINVAL; 1007973a8429SRander Wang break; 1008973a8429SRander Wang } 1009973a8429SRander Wang 1010973a8429SRander Wang if (ret) 1011973a8429SRander Wang dev_err(dai->dev, 1012973a8429SRander Wang "%s trigger %d failed: %d", 1013973a8429SRander Wang __func__, cmd, ret); 1014973a8429SRander Wang return ret; 1015973a8429SRander Wang } 1016973a8429SRander Wang 1017c46302ecSVinod Koul static int 1018c46302ecSVinod Koul intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 1019c46302ecSVinod Koul { 1020c46302ecSVinod Koul struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 1021eff346f2SPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns); 1022c46302ecSVinod Koul struct sdw_cdns_dma_data *dma; 1023c46302ecSVinod Koul int ret; 1024c46302ecSVinod Koul 1025c46302ecSVinod Koul dma = snd_soc_dai_get_dma_data(dai, substream); 1026c46302ecSVinod Koul if (!dma) 1027c46302ecSVinod Koul return -EIO; 1028c46302ecSVinod Koul 1029eff346f2SPierre-Louis Bossart ret = sdw_deprepare_stream(dma->stream); 1030eff346f2SPierre-Louis Bossart if (ret) { 1031eff346f2SPierre-Louis Bossart dev_err(dai->dev, "sdw_deprepare_stream: failed %d", ret); 1032eff346f2SPierre-Louis Bossart return ret; 1033eff346f2SPierre-Louis Bossart } 1034eff346f2SPierre-Louis Bossart 1035c46302ecSVinod Koul ret = sdw_stream_remove_master(&cdns->bus, dma->stream); 1036eff346f2SPierre-Louis Bossart if (ret < 0) { 103717ed5befSPierre-Louis Bossart dev_err(dai->dev, "remove master from stream %s failed: %d\n", 1038c46302ecSVinod Koul dma->stream->name, ret); 1039c46302ecSVinod Koul return ret; 1040c46302ecSVinod Koul } 1041c46302ecSVinod Koul 1042eff346f2SPierre-Louis Bossart ret = intel_free_stream(sdw, substream, dai, sdw->instance); 1043eff346f2SPierre-Louis Bossart if (ret < 0) { 1044eff346f2SPierre-Louis Bossart dev_err(dai->dev, "intel_free_stream: failed %d", ret); 1045eff346f2SPierre-Louis Bossart return ret; 1046eff346f2SPierre-Louis Bossart } 1047eff346f2SPierre-Louis Bossart 1048a5a0239cSBard Liao dma->hw_params = NULL; 1049a5a0239cSBard Liao dma->pdi = NULL; 1050a5a0239cSBard Liao 1051eff346f2SPierre-Louis Bossart return 0; 1052eff346f2SPierre-Louis Bossart } 1053eff346f2SPierre-Louis Bossart 1054183c7687SPierre-Louis Bossart static void intel_shutdown(struct snd_pcm_substream *substream, 1055183c7687SPierre-Louis Bossart struct snd_soc_dai *dai) 1056183c7687SPierre-Louis Bossart { 1057ebf878edSPierre-Louis Bossart struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 1058183c7687SPierre-Louis Bossart 1059ebf878edSPierre-Louis Bossart pm_runtime_mark_last_busy(cdns->dev); 1060ebf878edSPierre-Louis Bossart pm_runtime_put_autosuspend(cdns->dev); 1061183c7687SPierre-Louis Bossart } 1062183c7687SPierre-Louis Bossart 1063a5a0239cSBard Liao static int intel_component_dais_suspend(struct snd_soc_component *component) 1064a5a0239cSBard Liao { 1065a5a0239cSBard Liao struct sdw_cdns_dma_data *dma; 1066a5a0239cSBard Liao struct snd_soc_dai *dai; 1067a5a0239cSBard Liao 1068a5a0239cSBard Liao for_each_component_dais(component, dai) { 1069a5a0239cSBard Liao /* 1070a5a0239cSBard Liao * we don't have a .suspend dai_ops, and we don't have access 1071a5a0239cSBard Liao * to the substream, so let's mark both capture and playback 1072a5a0239cSBard Liao * DMA contexts as suspended 1073a5a0239cSBard Liao */ 1074a5a0239cSBard Liao dma = dai->playback_dma_data; 1075a5a0239cSBard Liao if (dma) 1076a5a0239cSBard Liao dma->suspended = true; 1077a5a0239cSBard Liao 1078a5a0239cSBard Liao dma = dai->capture_dma_data; 1079a5a0239cSBard Liao if (dma) 1080a5a0239cSBard Liao dma->suspended = true; 1081a5a0239cSBard Liao } 1082a5a0239cSBard Liao 1083a5a0239cSBard Liao return 0; 1084a5a0239cSBard Liao } 1085a5a0239cSBard Liao 1086c46302ecSVinod Koul static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, 1087c46302ecSVinod Koul void *stream, int direction) 1088c46302ecSVinod Koul { 1089c46302ecSVinod Koul return cdns_set_sdw_stream(dai, stream, true, direction); 1090c46302ecSVinod Koul } 1091c46302ecSVinod Koul 1092c46302ecSVinod Koul static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, 1093c46302ecSVinod Koul void *stream, int direction) 1094c46302ecSVinod Koul { 1095c46302ecSVinod Koul return cdns_set_sdw_stream(dai, stream, false, direction); 1096c46302ecSVinod Koul } 1097c46302ecSVinod Koul 109809553140SPierre-Louis Bossart static void *intel_get_sdw_stream(struct snd_soc_dai *dai, 109909553140SPierre-Louis Bossart int direction) 110009553140SPierre-Louis Bossart { 110109553140SPierre-Louis Bossart struct sdw_cdns_dma_data *dma; 110209553140SPierre-Louis Bossart 110309553140SPierre-Louis Bossart if (direction == SNDRV_PCM_STREAM_PLAYBACK) 110409553140SPierre-Louis Bossart dma = dai->playback_dma_data; 110509553140SPierre-Louis Bossart else 110609553140SPierre-Louis Bossart dma = dai->capture_dma_data; 110709553140SPierre-Louis Bossart 110809553140SPierre-Louis Bossart if (!dma) 110909553140SPierre-Louis Bossart return NULL; 111009553140SPierre-Louis Bossart 111109553140SPierre-Louis Bossart return dma->stream; 111209553140SPierre-Louis Bossart } 111309553140SPierre-Louis Bossart 1114b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pcm_dai_ops = { 11155e7484d0SRander Wang .startup = intel_startup, 1116c46302ecSVinod Koul .hw_params = intel_hw_params, 111727b198f4SRander Wang .prepare = intel_prepare, 1118973a8429SRander Wang .trigger = intel_trigger, 1119c46302ecSVinod Koul .hw_free = intel_hw_free, 1120183c7687SPierre-Louis Bossart .shutdown = intel_shutdown, 1121c46302ecSVinod Koul .set_sdw_stream = intel_pcm_set_sdw_stream, 112209553140SPierre-Louis Bossart .get_sdw_stream = intel_get_sdw_stream, 1123c46302ecSVinod Koul }; 1124c46302ecSVinod Koul 1125b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pdm_dai_ops = { 11265e7484d0SRander Wang .startup = intel_startup, 1127c46302ecSVinod Koul .hw_params = intel_hw_params, 112827b198f4SRander Wang .prepare = intel_prepare, 1129973a8429SRander Wang .trigger = intel_trigger, 1130c46302ecSVinod Koul .hw_free = intel_hw_free, 1131183c7687SPierre-Louis Bossart .shutdown = intel_shutdown, 1132c46302ecSVinod Koul .set_sdw_stream = intel_pdm_set_sdw_stream, 113309553140SPierre-Louis Bossart .get_sdw_stream = intel_get_sdw_stream, 1134c46302ecSVinod Koul }; 1135c46302ecSVinod Koul 1136c46302ecSVinod Koul static const struct snd_soc_component_driver dai_component = { 1137c46302ecSVinod Koul .name = "soundwire", 1138a5a0239cSBard Liao .suspend = intel_component_dais_suspend 1139c46302ecSVinod Koul }; 1140c46302ecSVinod Koul 1141c46302ecSVinod Koul static int intel_create_dai(struct sdw_cdns *cdns, 1142c46302ecSVinod Koul struct snd_soc_dai_driver *dais, 1143c46302ecSVinod Koul enum intel_pdi_type type, 1144c46302ecSVinod Koul u32 num, u32 off, u32 max_ch, bool pcm) 1145c46302ecSVinod Koul { 1146c46302ecSVinod Koul int i; 1147c46302ecSVinod Koul 1148c46302ecSVinod Koul if (num == 0) 1149c46302ecSVinod Koul return 0; 1150c46302ecSVinod Koul 1151c46302ecSVinod Koul /* TODO: Read supported rates/formats from hardware */ 1152c46302ecSVinod Koul for (i = off; i < (off + num); i++) { 1153bf6d6e68SPierre-Louis Bossart dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL, 1154bf6d6e68SPierre-Louis Bossart "SDW%d Pin%d", 1155c46302ecSVinod Koul cdns->instance, i); 1156c46302ecSVinod Koul if (!dais[i].name) 1157c46302ecSVinod Koul return -ENOMEM; 1158c46302ecSVinod Koul 1159c46302ecSVinod Koul if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) { 1160c46302ecSVinod Koul dais[i].playback.channels_min = 1; 1161c46302ecSVinod Koul dais[i].playback.channels_max = max_ch; 1162c46302ecSVinod Koul dais[i].playback.rates = SNDRV_PCM_RATE_48000; 1163c46302ecSVinod Koul dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE; 1164c46302ecSVinod Koul } 1165c46302ecSVinod Koul 1166c46302ecSVinod Koul if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) { 116739194128SSrinivas Kandagatla dais[i].capture.channels_min = 1; 116839194128SSrinivas Kandagatla dais[i].capture.channels_max = max_ch; 1169c46302ecSVinod Koul dais[i].capture.rates = SNDRV_PCM_RATE_48000; 1170c46302ecSVinod Koul dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE; 1171c46302ecSVinod Koul } 1172c46302ecSVinod Koul 1173c46302ecSVinod Koul if (pcm) 1174c46302ecSVinod Koul dais[i].ops = &intel_pcm_dai_ops; 1175c46302ecSVinod Koul else 1176c46302ecSVinod Koul dais[i].ops = &intel_pdm_dai_ops; 1177c46302ecSVinod Koul } 1178c46302ecSVinod Koul 1179c46302ecSVinod Koul return 0; 1180c46302ecSVinod Koul } 1181c46302ecSVinod Koul 1182c46302ecSVinod Koul static int intel_register_dai(struct sdw_intel *sdw) 1183c46302ecSVinod Koul { 1184c46302ecSVinod Koul struct sdw_cdns *cdns = &sdw->cdns; 1185c46302ecSVinod Koul struct sdw_cdns_streams *stream; 1186c46302ecSVinod Koul struct snd_soc_dai_driver *dais; 1187c46302ecSVinod Koul int num_dai, ret, off = 0; 1188c46302ecSVinod Koul 1189c46302ecSVinod Koul /* DAIs are created based on total number of PDIs supported */ 1190c46302ecSVinod Koul num_dai = cdns->pcm.num_pdi + cdns->pdm.num_pdi; 1191c46302ecSVinod Koul 1192c46302ecSVinod Koul dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL); 1193c46302ecSVinod Koul if (!dais) 1194c46302ecSVinod Koul return -ENOMEM; 1195c46302ecSVinod Koul 1196c46302ecSVinod Koul /* Create PCM DAIs */ 1197c46302ecSVinod Koul stream = &cdns->pcm; 1198c46302ecSVinod Koul 1199cf924962SBard Liao ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in, 12001215daeeSVinod Koul off, stream->num_ch_in, true); 1201c46302ecSVinod Koul if (ret) 1202c46302ecSVinod Koul return ret; 1203c46302ecSVinod Koul 1204c46302ecSVinod Koul off += cdns->pcm.num_in; 12051215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out, 12061215daeeSVinod Koul off, stream->num_ch_out, true); 1207c46302ecSVinod Koul if (ret) 1208c46302ecSVinod Koul return ret; 1209c46302ecSVinod Koul 1210c46302ecSVinod Koul off += cdns->pcm.num_out; 12111215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd, 12121215daeeSVinod Koul off, stream->num_ch_bd, true); 1213c46302ecSVinod Koul if (ret) 1214c46302ecSVinod Koul return ret; 1215c46302ecSVinod Koul 1216c46302ecSVinod Koul /* Create PDM DAIs */ 1217c46302ecSVinod Koul stream = &cdns->pdm; 1218c46302ecSVinod Koul off += cdns->pcm.num_bd; 12191215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pdm.num_in, 12201215daeeSVinod Koul off, stream->num_ch_in, false); 1221c46302ecSVinod Koul if (ret) 1222c46302ecSVinod Koul return ret; 1223c46302ecSVinod Koul 1224c46302ecSVinod Koul off += cdns->pdm.num_in; 12251215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pdm.num_out, 12261215daeeSVinod Koul off, stream->num_ch_out, false); 1227c46302ecSVinod Koul if (ret) 1228c46302ecSVinod Koul return ret; 1229c46302ecSVinod Koul 1230cf924962SBard Liao off += cdns->pdm.num_out; 12311215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pdm.num_bd, 12321215daeeSVinod Koul off, stream->num_ch_bd, false); 1233c46302ecSVinod Koul if (ret) 1234c46302ecSVinod Koul return ret; 1235c46302ecSVinod Koul 1236c46302ecSVinod Koul return snd_soc_register_component(cdns->dev, &dai_component, 1237c46302ecSVinod Koul dais, num_dai); 1238c46302ecSVinod Koul } 1239c46302ecSVinod Koul 1240085f4aceSPierre-Louis Bossart static int sdw_master_read_intel_prop(struct sdw_bus *bus) 1241085f4aceSPierre-Louis Bossart { 1242085f4aceSPierre-Louis Bossart struct sdw_master_prop *prop = &bus->prop; 1243085f4aceSPierre-Louis Bossart struct fwnode_handle *link; 1244085f4aceSPierre-Louis Bossart char name[32]; 1245395713d8SPierre-Louis Bossart u32 quirk_mask; 1246085f4aceSPierre-Louis Bossart 1247085f4aceSPierre-Louis Bossart /* Find master handle */ 1248085f4aceSPierre-Louis Bossart snprintf(name, sizeof(name), 1249085f4aceSPierre-Louis Bossart "mipi-sdw-link-%d-subproperties", bus->link_id); 1250085f4aceSPierre-Louis Bossart 1251085f4aceSPierre-Louis Bossart link = device_get_named_child_node(bus->dev, name); 1252085f4aceSPierre-Louis Bossart if (!link) { 1253085f4aceSPierre-Louis Bossart dev_err(bus->dev, "Master node %s not found\n", name); 1254085f4aceSPierre-Louis Bossart return -EIO; 1255085f4aceSPierre-Louis Bossart } 1256085f4aceSPierre-Louis Bossart 1257085f4aceSPierre-Louis Bossart fwnode_property_read_u32(link, 1258085f4aceSPierre-Louis Bossart "intel-sdw-ip-clock", 1259085f4aceSPierre-Louis Bossart &prop->mclk_freq); 1260395713d8SPierre-Louis Bossart 1261a19efb52SBard Liao /* the values reported by BIOS are the 2x clock, not the bus clock */ 1262a19efb52SBard Liao prop->mclk_freq /= 2; 1263a19efb52SBard Liao 1264395713d8SPierre-Louis Bossart fwnode_property_read_u32(link, 1265395713d8SPierre-Louis Bossart "intel-quirk-mask", 1266395713d8SPierre-Louis Bossart &quirk_mask); 1267395713d8SPierre-Louis Bossart 1268395713d8SPierre-Louis Bossart if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) 1269395713d8SPierre-Louis Bossart prop->hw_disabled = true; 1270395713d8SPierre-Louis Bossart 1271085f4aceSPierre-Louis Bossart return 0; 1272085f4aceSPierre-Louis Bossart } 1273085f4aceSPierre-Louis Bossart 127471bb8a1bSVinod Koul static int intel_prop_read(struct sdw_bus *bus) 127571bb8a1bSVinod Koul { 127671bb8a1bSVinod Koul /* Initialize with default handler to read all DisCo properties */ 127771bb8a1bSVinod Koul sdw_master_read_prop(bus); 127871bb8a1bSVinod Koul 1279085f4aceSPierre-Louis Bossart /* read Intel-specific properties */ 1280085f4aceSPierre-Louis Bossart sdw_master_read_intel_prop(bus); 1281085f4aceSPierre-Louis Bossart 128271bb8a1bSVinod Koul return 0; 128371bb8a1bSVinod Koul } 128471bb8a1bSVinod Koul 1285c91605f4SShreyas NC static struct sdw_master_ops sdw_intel_ops = { 1286c91605f4SShreyas NC .read_prop = sdw_master_read_prop, 1287c91605f4SShreyas NC .xfer_msg = cdns_xfer_msg, 1288c91605f4SShreyas NC .xfer_msg_defer = cdns_xfer_msg_defer, 1289c91605f4SShreyas NC .reset_page_addr = cdns_reset_page_addr, 129007abeff1SVinod Koul .set_bus_conf = cdns_bus_conf, 129130246e2dSShreyas NC .pre_bank_switch = intel_pre_bank_switch, 129230246e2dSShreyas NC .post_bank_switch = intel_post_bank_switch, 1293c91605f4SShreyas NC }; 1294c91605f4SShreyas NC 1295dfbe642dSPierre-Louis Bossart static int intel_init(struct sdw_intel *sdw) 1296dfbe642dSPierre-Louis Bossart { 12974a17c441SPierre-Louis Bossart bool clock_stop; 12984a17c441SPierre-Louis Bossart 1299dfbe642dSPierre-Louis Bossart /* Initialize shim and controller */ 1300dfbe642dSPierre-Louis Bossart intel_link_power_up(sdw); 13014a17c441SPierre-Louis Bossart 13024a17c441SPierre-Louis Bossart clock_stop = sdw_cdns_is_clock_stop(&sdw->cdns); 13034a17c441SPierre-Louis Bossart 13044a17c441SPierre-Louis Bossart intel_shim_init(sdw, clock_stop); 13054a17c441SPierre-Louis Bossart 13064a17c441SPierre-Louis Bossart if (clock_stop) 13074a17c441SPierre-Louis Bossart return 0; 1308dfbe642dSPierre-Louis Bossart 13097b174f24SRander Wang return sdw_cdns_init(&sdw->cdns); 1310dfbe642dSPierre-Louis Bossart } 1311dfbe642dSPierre-Louis Bossart 131271bb8a1bSVinod Koul /* 131371bb8a1bSVinod Koul * probe and init 131471bb8a1bSVinod Koul */ 1315b6109dd6SPierre-Louis Bossart static int intel_master_probe(struct platform_device *pdev) 131671bb8a1bSVinod Koul { 1317b6109dd6SPierre-Louis Bossart struct device *dev = &pdev->dev; 131871bb8a1bSVinod Koul struct sdw_intel *sdw; 131983e129afSPierre-Louis Bossart struct sdw_cdns *cdns; 1320b6109dd6SPierre-Louis Bossart struct sdw_bus *bus; 132171bb8a1bSVinod Koul int ret; 132271bb8a1bSVinod Koul 1323b6109dd6SPierre-Louis Bossart sdw = devm_kzalloc(dev, sizeof(*sdw), GFP_KERNEL); 132471bb8a1bSVinod Koul if (!sdw) 132571bb8a1bSVinod Koul return -ENOMEM; 132671bb8a1bSVinod Koul 132783e129afSPierre-Louis Bossart cdns = &sdw->cdns; 132883e129afSPierre-Louis Bossart bus = &cdns->bus; 132971bb8a1bSVinod Koul 133071bb8a1bSVinod Koul sdw->instance = pdev->id; 1331b6109dd6SPierre-Louis Bossart sdw->link_res = dev_get_platdata(dev); 133283e129afSPierre-Louis Bossart cdns->dev = dev; 133383e129afSPierre-Louis Bossart cdns->registers = sdw->link_res->registers; 133483e129afSPierre-Louis Bossart cdns->instance = sdw->instance; 133583e129afSPierre-Louis Bossart cdns->msg_count = 0; 133683e129afSPierre-Louis Bossart 1337b6109dd6SPierre-Louis Bossart bus->link_id = pdev->id; 133871bb8a1bSVinod Koul 133983e129afSPierre-Louis Bossart sdw_cdns_probe(cdns); 134071bb8a1bSVinod Koul 134171bb8a1bSVinod Koul /* Set property read ops */ 1342c91605f4SShreyas NC sdw_intel_ops.read_prop = intel_prop_read; 1343b6109dd6SPierre-Louis Bossart bus->ops = &sdw_intel_ops; 134471bb8a1bSVinod Koul 1345b6109dd6SPierre-Louis Bossart /* set driver data, accessed by snd_soc_dai_get_drvdata() */ 134683e129afSPierre-Louis Bossart dev_set_drvdata(dev, cdns); 134771bb8a1bSVinod Koul 1348b6109dd6SPierre-Louis Bossart ret = sdw_bus_master_add(bus, dev, dev->fwnode); 134971bb8a1bSVinod Koul if (ret) { 1350b6109dd6SPierre-Louis Bossart dev_err(dev, "sdw_bus_master_add fail: %d\n", ret); 13519e3d47fbSPierre-Louis Bossart return ret; 135271bb8a1bSVinod Koul } 135371bb8a1bSVinod Koul 13546d2c6669SPierre-Louis Bossart if (bus->prop.hw_disabled) 1355b6109dd6SPierre-Louis Bossart dev_info(dev, 1356b6109dd6SPierre-Louis Bossart "SoundWire master %d is disabled, will be ignored\n", 1357b6109dd6SPierre-Louis Bossart bus->link_id); 13586d2c6669SPierre-Louis Bossart 13596d2c6669SPierre-Louis Bossart return 0; 13606d2c6669SPierre-Louis Bossart } 13616d2c6669SPierre-Louis Bossart 13626d2c6669SPierre-Louis Bossart int intel_master_startup(struct platform_device *pdev) 13636d2c6669SPierre-Louis Bossart { 13646d2c6669SPierre-Louis Bossart struct sdw_cdns_stream_config config; 13656d2c6669SPierre-Louis Bossart struct device *dev = &pdev->dev; 13666d2c6669SPierre-Louis Bossart struct sdw_cdns *cdns = dev_get_drvdata(dev); 13676d2c6669SPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns); 13686d2c6669SPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus; 1369ebf878edSPierre-Louis Bossart int link_flags; 13706d2c6669SPierre-Louis Bossart int ret; 13716d2c6669SPierre-Louis Bossart 13726d2c6669SPierre-Louis Bossart if (bus->prop.hw_disabled) { 13736d2c6669SPierre-Louis Bossart dev_info(dev, 13746d2c6669SPierre-Louis Bossart "SoundWire master %d is disabled, ignoring\n", 13756d2c6669SPierre-Louis Bossart sdw->instance); 1376395713d8SPierre-Louis Bossart return 0; 1377395713d8SPierre-Louis Bossart } 1378395713d8SPierre-Louis Bossart 1379dfbe642dSPierre-Louis Bossart /* Initialize shim, controller and Cadence IP */ 1380dfbe642dSPierre-Louis Bossart ret = intel_init(sdw); 138171bb8a1bSVinod Koul if (ret) 138271bb8a1bSVinod Koul goto err_init; 138371bb8a1bSVinod Koul 138437a2d22bSVinod Koul /* Read the PDI config and initialize cadence PDI */ 138537a2d22bSVinod Koul intel_pdi_init(sdw, &config); 138683e129afSPierre-Louis Bossart ret = sdw_cdns_pdi_init(cdns, config); 138771bb8a1bSVinod Koul if (ret) 138871bb8a1bSVinod Koul goto err_init; 138971bb8a1bSVinod Koul 139037a2d22bSVinod Koul intel_pdi_ch_update(sdw); 139137a2d22bSVinod Koul 139283e129afSPierre-Louis Bossart ret = sdw_cdns_enable_interrupt(cdns, true); 139371bb8a1bSVinod Koul if (ret < 0) { 1394b6109dd6SPierre-Louis Bossart dev_err(dev, "cannot enable interrupts\n"); 139571bb8a1bSVinod Koul goto err_init; 139671bb8a1bSVinod Koul } 139771bb8a1bSVinod Koul 139883e129afSPierre-Louis Bossart ret = sdw_cdns_exit_reset(cdns); 139949ea07d3SPierre-Louis Bossart if (ret < 0) { 1400b6109dd6SPierre-Louis Bossart dev_err(dev, "unable to exit bus reset sequence\n"); 14019e3d47fbSPierre-Louis Bossart goto err_interrupt; 140249ea07d3SPierre-Louis Bossart } 140349ea07d3SPierre-Louis Bossart 1404c46302ecSVinod Koul /* Register DAIs */ 1405c46302ecSVinod Koul ret = intel_register_dai(sdw); 1406c46302ecSVinod Koul if (ret) { 1407b6109dd6SPierre-Louis Bossart dev_err(dev, "DAI registration failed: %d\n", ret); 1408b6109dd6SPierre-Louis Bossart snd_soc_unregister_component(dev); 14099e3d47fbSPierre-Louis Bossart goto err_interrupt; 1410c46302ecSVinod Koul } 1411c46302ecSVinod Koul 141279ee6631SPierre-Louis Bossart intel_debugfs_init(sdw); 141379ee6631SPierre-Louis Bossart 1414ebf878edSPierre-Louis Bossart /* Enable runtime PM */ 1415ebf878edSPierre-Louis Bossart link_flags = md_flags >> (bus->link_id * 8); 1416ebf878edSPierre-Louis Bossart if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) { 1417ebf878edSPierre-Louis Bossart pm_runtime_set_autosuspend_delay(dev, 1418ebf878edSPierre-Louis Bossart INTEL_MASTER_SUSPEND_DELAY_MS); 1419ebf878edSPierre-Louis Bossart pm_runtime_use_autosuspend(dev); 1420ebf878edSPierre-Louis Bossart pm_runtime_mark_last_busy(dev); 1421ebf878edSPierre-Louis Bossart 1422ebf878edSPierre-Louis Bossart pm_runtime_set_active(dev); 1423ebf878edSPierre-Louis Bossart pm_runtime_enable(dev); 1424ebf878edSPierre-Louis Bossart } 1425ebf878edSPierre-Louis Bossart 1426a2d9c161SPierre-Louis Bossart /* 1427a2d9c161SPierre-Louis Bossart * The runtime PM status of Slave devices is "Unsupported" 1428a2d9c161SPierre-Louis Bossart * until they report as ATTACHED. If they don't, e.g. because 1429a2d9c161SPierre-Louis Bossart * there are no Slave devices populated or if the power-on is 1430a2d9c161SPierre-Louis Bossart * delayed or dependent on a power switch, the Master will 1431a2d9c161SPierre-Louis Bossart * remain active and prevent its parent from suspending. 1432a2d9c161SPierre-Louis Bossart * 1433a2d9c161SPierre-Louis Bossart * Conditionally force the pm_runtime core to re-evaluate the 1434a2d9c161SPierre-Louis Bossart * Master status in the absence of any Slave activity. A quirk 1435a2d9c161SPierre-Louis Bossart * is provided to e.g. deal with Slaves that may be powered on 1436a2d9c161SPierre-Louis Bossart * with a delay. A more complete solution would require the 1437a2d9c161SPierre-Louis Bossart * definition of Master properties. 1438a2d9c161SPierre-Louis Bossart */ 1439a2d9c161SPierre-Louis Bossart if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) 1440a2d9c161SPierre-Louis Bossart pm_runtime_idle(dev); 1441a2d9c161SPierre-Louis Bossart 144271bb8a1bSVinod Koul return 0; 144371bb8a1bSVinod Koul 14449e3d47fbSPierre-Louis Bossart err_interrupt: 144583e129afSPierre-Louis Bossart sdw_cdns_enable_interrupt(cdns, false); 144671bb8a1bSVinod Koul err_init: 144771bb8a1bSVinod Koul return ret; 144871bb8a1bSVinod Koul } 144971bb8a1bSVinod Koul 1450b6109dd6SPierre-Louis Bossart static int intel_master_remove(struct platform_device *pdev) 145171bb8a1bSVinod Koul { 1452b6109dd6SPierre-Louis Bossart struct device *dev = &pdev->dev; 145383e129afSPierre-Louis Bossart struct sdw_cdns *cdns = dev_get_drvdata(dev); 145483e129afSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns); 145583e129afSPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus; 1456b6109dd6SPierre-Louis Bossart 1457b6109dd6SPierre-Louis Bossart if (!bus->prop.hw_disabled) { 145879ee6631SPierre-Louis Bossart intel_debugfs_exit(sdw); 145983e129afSPierre-Louis Bossart sdw_cdns_enable_interrupt(cdns, false); 1460b6109dd6SPierre-Louis Bossart snd_soc_unregister_component(dev); 1461395713d8SPierre-Louis Bossart } 1462b6109dd6SPierre-Louis Bossart sdw_bus_master_delete(bus); 146371bb8a1bSVinod Koul 146471bb8a1bSVinod Koul return 0; 146571bb8a1bSVinod Koul } 146671bb8a1bSVinod Koul 1467ab2c9132SRander Wang int intel_master_process_wakeen_event(struct platform_device *pdev) 1468ab2c9132SRander Wang { 1469ab2c9132SRander Wang struct device *dev = &pdev->dev; 147071bb8a1bSVinod Koul struct sdw_intel *sdw; 1471ab2c9132SRander Wang struct sdw_bus *bus; 1472ab2c9132SRander Wang void __iomem *shim; 1473ab2c9132SRander Wang u16 wake_sts; 147471bb8a1bSVinod Koul 147571bb8a1bSVinod Koul sdw = platform_get_drvdata(pdev); 1476ab2c9132SRander Wang bus = &sdw->cdns.bus; 147771bb8a1bSVinod Koul 1478ab2c9132SRander Wang if (bus->prop.hw_disabled) { 1479ab2c9132SRander Wang dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", bus->link_id); 1480ab2c9132SRander Wang return 0; 148171bb8a1bSVinod Koul } 1482ab2c9132SRander Wang 1483ab2c9132SRander Wang shim = sdw->link_res->shim; 1484ab2c9132SRander Wang wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); 1485ab2c9132SRander Wang 1486ab2c9132SRander Wang if (!(wake_sts & BIT(sdw->instance))) 1487ab2c9132SRander Wang return 0; 1488ab2c9132SRander Wang 1489ab2c9132SRander Wang /* disable WAKEEN interrupt ASAP to prevent interrupt flood */ 1490ab2c9132SRander Wang intel_shim_wake(sdw, false); 1491ab2c9132SRander Wang 1492ab2c9132SRander Wang /* 1493ab2c9132SRander Wang * resume the Master, which will generate a bus reset and result in 1494ab2c9132SRander Wang * Slaves re-attaching and be re-enumerated. The SoundWire physical 1495ab2c9132SRander Wang * device which generated the wake will trigger an interrupt, which 1496ab2c9132SRander Wang * will in turn cause the corresponding Linux Slave device to be 1497ab2c9132SRander Wang * resumed and the Slave codec driver to check the status. 1498ab2c9132SRander Wang */ 1499ab2c9132SRander Wang pm_request_resume(dev); 150071bb8a1bSVinod Koul 150171bb8a1bSVinod Koul return 0; 150271bb8a1bSVinod Koul } 150371bb8a1bSVinod Koul 15049b3b4b3fSPierre-Louis Bossart /* 15059b3b4b3fSPierre-Louis Bossart * PM calls 15069b3b4b3fSPierre-Louis Bossart */ 15079b3b4b3fSPierre-Louis Bossart 15089b3b4b3fSPierre-Louis Bossart #ifdef CONFIG_PM 15099b3b4b3fSPierre-Louis Bossart 15109b3b4b3fSPierre-Louis Bossart static int intel_suspend(struct device *dev) 15119b3b4b3fSPierre-Louis Bossart { 15129b3b4b3fSPierre-Louis Bossart struct sdw_cdns *cdns = dev_get_drvdata(dev); 15139b3b4b3fSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns); 15149b3b4b3fSPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus; 15159b3b4b3fSPierre-Louis Bossart int ret; 15169b3b4b3fSPierre-Louis Bossart 15179b3b4b3fSPierre-Louis Bossart if (bus->prop.hw_disabled) { 15189b3b4b3fSPierre-Louis Bossart dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", 15199b3b4b3fSPierre-Louis Bossart bus->link_id); 15209b3b4b3fSPierre-Louis Bossart return 0; 15219b3b4b3fSPierre-Louis Bossart } 15229b3b4b3fSPierre-Louis Bossart 1523b61b8b37SPierre-Louis Bossart if (pm_runtime_suspended(dev)) { 1524b61b8b37SPierre-Louis Bossart dev_dbg(dev, "%s: pm_runtime status: suspended\n", __func__); 1525b61b8b37SPierre-Louis Bossart 1526b61b8b37SPierre-Louis Bossart return 0; 1527b61b8b37SPierre-Louis Bossart } 1528b61b8b37SPierre-Louis Bossart 15299b3b4b3fSPierre-Louis Bossart ret = sdw_cdns_enable_interrupt(cdns, false); 15309b3b4b3fSPierre-Louis Bossart if (ret < 0) { 15319b3b4b3fSPierre-Louis Bossart dev_err(dev, "cannot disable interrupts on suspend\n"); 15329b3b4b3fSPierre-Louis Bossart return ret; 15339b3b4b3fSPierre-Louis Bossart } 15349b3b4b3fSPierre-Louis Bossart 15359b3b4b3fSPierre-Louis Bossart ret = intel_link_power_down(sdw); 15369b3b4b3fSPierre-Louis Bossart if (ret) { 15379b3b4b3fSPierre-Louis Bossart dev_err(dev, "Link power down failed: %d", ret); 15389b3b4b3fSPierre-Louis Bossart return ret; 15399b3b4b3fSPierre-Louis Bossart } 15409b3b4b3fSPierre-Louis Bossart 15419b3b4b3fSPierre-Louis Bossart intel_shim_wake(sdw, false); 15429b3b4b3fSPierre-Louis Bossart 15439b3b4b3fSPierre-Louis Bossart return 0; 15449b3b4b3fSPierre-Louis Bossart } 15459b3b4b3fSPierre-Louis Bossart 1546ebf878edSPierre-Louis Bossart static int intel_suspend_runtime(struct device *dev) 1547ebf878edSPierre-Louis Bossart { 1548ebf878edSPierre-Louis Bossart struct sdw_cdns *cdns = dev_get_drvdata(dev); 1549ebf878edSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns); 1550ebf878edSPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus; 1551*a320f41eSPierre-Louis Bossart u32 clock_stop_quirks; 1552ebf878edSPierre-Louis Bossart int ret; 1553ebf878edSPierre-Louis Bossart 1554ebf878edSPierre-Louis Bossart if (bus->prop.hw_disabled) { 1555ebf878edSPierre-Louis Bossart dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", 1556ebf878edSPierre-Louis Bossart bus->link_id); 1557ebf878edSPierre-Louis Bossart return 0; 1558ebf878edSPierre-Louis Bossart } 1559ebf878edSPierre-Louis Bossart 1560*a320f41eSPierre-Louis Bossart clock_stop_quirks = sdw->link_res->clock_stop_quirks; 1561*a320f41eSPierre-Louis Bossart 1562*a320f41eSPierre-Louis Bossart if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { 1563*a320f41eSPierre-Louis Bossart 1564ebf878edSPierre-Louis Bossart ret = sdw_cdns_enable_interrupt(cdns, false); 1565ebf878edSPierre-Louis Bossart if (ret < 0) { 1566ebf878edSPierre-Louis Bossart dev_err(dev, "cannot disable interrupts on suspend\n"); 1567ebf878edSPierre-Louis Bossart return ret; 1568ebf878edSPierre-Louis Bossart } 1569ebf878edSPierre-Louis Bossart 1570ebf878edSPierre-Louis Bossart ret = intel_link_power_down(sdw); 1571ebf878edSPierre-Louis Bossart if (ret) { 1572ebf878edSPierre-Louis Bossart dev_err(dev, "Link power down failed: %d", ret); 1573ebf878edSPierre-Louis Bossart return ret; 1574ebf878edSPierre-Louis Bossart } 1575ebf878edSPierre-Louis Bossart 1576ebf878edSPierre-Louis Bossart intel_shim_wake(sdw, false); 1577ebf878edSPierre-Louis Bossart 1578*a320f41eSPierre-Louis Bossart } else { 1579*a320f41eSPierre-Louis Bossart dev_err(dev, "%s clock_stop_quirks %x unsupported\n", 1580*a320f41eSPierre-Louis Bossart __func__, clock_stop_quirks); 1581*a320f41eSPierre-Louis Bossart ret = -EINVAL; 1582*a320f41eSPierre-Louis Bossart } 1583*a320f41eSPierre-Louis Bossart 1584*a320f41eSPierre-Louis Bossart return ret; 1585ebf878edSPierre-Louis Bossart } 1586ebf878edSPierre-Louis Bossart 15879b3b4b3fSPierre-Louis Bossart static int intel_resume(struct device *dev) 15889b3b4b3fSPierre-Louis Bossart { 15899b3b4b3fSPierre-Louis Bossart struct sdw_cdns *cdns = dev_get_drvdata(dev); 15909b3b4b3fSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns); 15919b3b4b3fSPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus; 1592a2d9c161SPierre-Louis Bossart int link_flags; 15939b3b4b3fSPierre-Louis Bossart int ret; 15949b3b4b3fSPierre-Louis Bossart 15959b3b4b3fSPierre-Louis Bossart if (bus->prop.hw_disabled) { 15969b3b4b3fSPierre-Louis Bossart dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", 15979b3b4b3fSPierre-Louis Bossart bus->link_id); 15989b3b4b3fSPierre-Louis Bossart return 0; 15999b3b4b3fSPierre-Louis Bossart } 16009b3b4b3fSPierre-Louis Bossart 1601b61b8b37SPierre-Louis Bossart if (pm_runtime_suspended(dev)) { 1602b61b8b37SPierre-Louis Bossart dev_dbg(dev, "%s: pm_runtime status was suspended, forcing active\n", __func__); 1603b61b8b37SPierre-Louis Bossart 1604b61b8b37SPierre-Louis Bossart /* follow required sequence from runtime_pm.rst */ 1605b61b8b37SPierre-Louis Bossart pm_runtime_disable(dev); 1606b61b8b37SPierre-Louis Bossart pm_runtime_set_active(dev); 1607b61b8b37SPierre-Louis Bossart pm_runtime_mark_last_busy(dev); 1608b61b8b37SPierre-Louis Bossart pm_runtime_enable(dev); 1609a2d9c161SPierre-Louis Bossart 1610a2d9c161SPierre-Louis Bossart link_flags = md_flags >> (bus->link_id * 8); 1611a2d9c161SPierre-Louis Bossart if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) 1612a2d9c161SPierre-Louis Bossart pm_runtime_idle(dev); 1613b61b8b37SPierre-Louis Bossart } 1614b61b8b37SPierre-Louis Bossart 16159b3b4b3fSPierre-Louis Bossart ret = intel_init(sdw); 16169b3b4b3fSPierre-Louis Bossart if (ret) { 16179b3b4b3fSPierre-Louis Bossart dev_err(dev, "%s failed: %d", __func__, ret); 16189b3b4b3fSPierre-Louis Bossart return ret; 16199b3b4b3fSPierre-Louis Bossart } 16209b3b4b3fSPierre-Louis Bossart 162199b6a30fSPierre-Louis Bossart /* 162299b6a30fSPierre-Louis Bossart * make sure all Slaves are tagged as UNATTACHED and provide 162399b6a30fSPierre-Louis Bossart * reason for reinitialization 162499b6a30fSPierre-Louis Bossart */ 162599b6a30fSPierre-Louis Bossart sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET); 162699b6a30fSPierre-Louis Bossart 16279b3b4b3fSPierre-Louis Bossart ret = sdw_cdns_enable_interrupt(cdns, true); 16289b3b4b3fSPierre-Louis Bossart if (ret < 0) { 16299b3b4b3fSPierre-Louis Bossart dev_err(dev, "cannot enable interrupts during resume\n"); 16309b3b4b3fSPierre-Louis Bossart return ret; 16319b3b4b3fSPierre-Louis Bossart } 16329b3b4b3fSPierre-Louis Bossart 16339b3b4b3fSPierre-Louis Bossart ret = sdw_cdns_exit_reset(cdns); 16349b3b4b3fSPierre-Louis Bossart if (ret < 0) { 16359b3b4b3fSPierre-Louis Bossart dev_err(dev, "unable to exit bus reset sequence during resume\n"); 16369b3b4b3fSPierre-Louis Bossart return ret; 16379b3b4b3fSPierre-Louis Bossart } 16389b3b4b3fSPierre-Louis Bossart 1639cb1e6d59SPierre-Louis Bossart /* 1640cb1e6d59SPierre-Louis Bossart * after system resume, the pm_runtime suspend() may kick in 1641cb1e6d59SPierre-Louis Bossart * during the enumeration, before any children device force the 1642cb1e6d59SPierre-Louis Bossart * master device to remain active. Using pm_runtime_get() 1643cb1e6d59SPierre-Louis Bossart * routines is not really possible, since it'd prevent the 1644cb1e6d59SPierre-Louis Bossart * master from suspending. 1645cb1e6d59SPierre-Louis Bossart * A reasonable compromise is to update the pm_runtime 1646cb1e6d59SPierre-Louis Bossart * counters and delay the pm_runtime suspend by several 1647cb1e6d59SPierre-Louis Bossart * seconds, by when all enumeration should be complete. 1648cb1e6d59SPierre-Louis Bossart */ 1649cb1e6d59SPierre-Louis Bossart pm_runtime_mark_last_busy(dev); 1650cb1e6d59SPierre-Louis Bossart 16519b3b4b3fSPierre-Louis Bossart return ret; 16529b3b4b3fSPierre-Louis Bossart } 16539b3b4b3fSPierre-Louis Bossart 1654ebf878edSPierre-Louis Bossart static int intel_resume_runtime(struct device *dev) 1655ebf878edSPierre-Louis Bossart { 1656ebf878edSPierre-Louis Bossart struct sdw_cdns *cdns = dev_get_drvdata(dev); 1657ebf878edSPierre-Louis Bossart struct sdw_intel *sdw = cdns_to_intel(cdns); 1658ebf878edSPierre-Louis Bossart struct sdw_bus *bus = &cdns->bus; 1659*a320f41eSPierre-Louis Bossart u32 clock_stop_quirks; 1660ebf878edSPierre-Louis Bossart int ret; 1661ebf878edSPierre-Louis Bossart 1662ebf878edSPierre-Louis Bossart if (bus->prop.hw_disabled) { 1663ebf878edSPierre-Louis Bossart dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", 1664ebf878edSPierre-Louis Bossart bus->link_id); 1665ebf878edSPierre-Louis Bossart return 0; 1666ebf878edSPierre-Louis Bossart } 1667ebf878edSPierre-Louis Bossart 1668*a320f41eSPierre-Louis Bossart clock_stop_quirks = sdw->link_res->clock_stop_quirks; 1669*a320f41eSPierre-Louis Bossart 1670*a320f41eSPierre-Louis Bossart if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { 1671ebf878edSPierre-Louis Bossart ret = intel_init(sdw); 1672ebf878edSPierre-Louis Bossart if (ret) { 1673ebf878edSPierre-Louis Bossart dev_err(dev, "%s failed: %d", __func__, ret); 1674ebf878edSPierre-Louis Bossart return ret; 1675ebf878edSPierre-Louis Bossart } 1676ebf878edSPierre-Louis Bossart 167799b6a30fSPierre-Louis Bossart /* 167899b6a30fSPierre-Louis Bossart * make sure all Slaves are tagged as UNATTACHED and provide 167999b6a30fSPierre-Louis Bossart * reason for reinitialization 168099b6a30fSPierre-Louis Bossart */ 168199b6a30fSPierre-Louis Bossart sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET); 168299b6a30fSPierre-Louis Bossart 1683ebf878edSPierre-Louis Bossart ret = sdw_cdns_enable_interrupt(cdns, true); 1684ebf878edSPierre-Louis Bossart if (ret < 0) { 1685ebf878edSPierre-Louis Bossart dev_err(dev, "cannot enable interrupts during resume\n"); 1686ebf878edSPierre-Louis Bossart return ret; 1687ebf878edSPierre-Louis Bossart } 1688ebf878edSPierre-Louis Bossart 1689ebf878edSPierre-Louis Bossart ret = sdw_cdns_exit_reset(cdns); 1690ebf878edSPierre-Louis Bossart if (ret < 0) { 1691ebf878edSPierre-Louis Bossart dev_err(dev, "unable to exit bus reset sequence during resume\n"); 1692ebf878edSPierre-Louis Bossart return ret; 1693ebf878edSPierre-Louis Bossart } 1694*a320f41eSPierre-Louis Bossart } else { 1695*a320f41eSPierre-Louis Bossart dev_err(dev, "%s clock_stop_quirks %x unsupported\n", 1696*a320f41eSPierre-Louis Bossart __func__, clock_stop_quirks); 1697*a320f41eSPierre-Louis Bossart ret = -EINVAL; 1698*a320f41eSPierre-Louis Bossart } 1699ebf878edSPierre-Louis Bossart 1700ebf878edSPierre-Louis Bossart return ret; 1701ebf878edSPierre-Louis Bossart } 1702ebf878edSPierre-Louis Bossart 17039b3b4b3fSPierre-Louis Bossart #endif 17049b3b4b3fSPierre-Louis Bossart 17059b3b4b3fSPierre-Louis Bossart static const struct dev_pm_ops intel_pm = { 17069b3b4b3fSPierre-Louis Bossart SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume) 1707ebf878edSPierre-Louis Bossart SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL) 17089b3b4b3fSPierre-Louis Bossart }; 17099b3b4b3fSPierre-Louis Bossart 171071bb8a1bSVinod Koul static struct platform_driver sdw_intel_drv = { 1711b6109dd6SPierre-Louis Bossart .probe = intel_master_probe, 1712b6109dd6SPierre-Louis Bossart .remove = intel_master_remove, 171371bb8a1bSVinod Koul .driver = { 17146d2c6669SPierre-Louis Bossart .name = "intel-sdw", 17159b3b4b3fSPierre-Louis Bossart .pm = &intel_pm, 17169b3b4b3fSPierre-Louis Bossart } 171771bb8a1bSVinod Koul }; 171871bb8a1bSVinod Koul 171971bb8a1bSVinod Koul module_platform_driver(sdw_intel_drv); 172071bb8a1bSVinod Koul 172171bb8a1bSVinod Koul MODULE_LICENSE("Dual BSD/GPL"); 17226d2c6669SPierre-Louis Bossart MODULE_ALIAS("platform:intel-sdw"); 172371bb8a1bSVinod Koul MODULE_DESCRIPTION("Intel Soundwire Master Driver"); 1724