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> 9*79ee6631SPierre-Louis Bossart #include <linux/debugfs.h> 1071bb8a1bSVinod Koul #include <linux/delay.h> 114abbd783SPaul Gortmaker #include <linux/module.h> 1271bb8a1bSVinod Koul #include <linux/interrupt.h> 1371bb8a1bSVinod Koul #include <linux/platform_device.h> 1437a2d22bSVinod Koul #include <sound/pcm_params.h> 1537a2d22bSVinod Koul #include <sound/soc.h> 1671bb8a1bSVinod Koul #include <linux/soundwire/sdw_registers.h> 1771bb8a1bSVinod Koul #include <linux/soundwire/sdw.h> 1871bb8a1bSVinod Koul #include <linux/soundwire/sdw_intel.h> 1971bb8a1bSVinod Koul #include "cadence_master.h" 20*79ee6631SPierre-Louis Bossart #include "bus.h" 2171bb8a1bSVinod Koul #include "intel.h" 2271bb8a1bSVinod Koul 2371bb8a1bSVinod Koul /* Intel SHIM Registers Definition */ 2471bb8a1bSVinod Koul #define SDW_SHIM_LCAP 0x0 2571bb8a1bSVinod Koul #define SDW_SHIM_LCTL 0x4 2671bb8a1bSVinod Koul #define SDW_SHIM_IPPTR 0x8 2771bb8a1bSVinod Koul #define SDW_SHIM_SYNC 0xC 2871bb8a1bSVinod Koul 297cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x)) 307cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x)) 317cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x)) 327cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x)) 337cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x)) 347cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x)) 3571bb8a1bSVinod Koul 367cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y))) 377cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y))) 387cc6e315SPierre-Louis Bossart #define SDW_SHIM_PDMSCAP(x) (0x062 + 0x60 * (x)) 397cc6e315SPierre-Louis Bossart #define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x)) 407cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x)) 4171bb8a1bSVinod Koul 4271bb8a1bSVinod Koul #define SDW_SHIM_WAKEEN 0x190 4371bb8a1bSVinod Koul #define SDW_SHIM_WAKESTS 0x192 4471bb8a1bSVinod Koul 4571bb8a1bSVinod Koul #define SDW_SHIM_LCTL_SPA BIT(0) 4671bb8a1bSVinod Koul #define SDW_SHIM_LCTL_CPA BIT(8) 4771bb8a1bSVinod Koul 4871bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCPRD_VAL 0x176F 4971bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0) 5071bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCCPU BIT(15) 5171bb8a1bSVinod Koul #define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16) 5271bb8a1bSVinod Koul #define SDW_SHIM_SYNC_CMDSYNC BIT(16) 5371bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCGO BIT(24) 5471bb8a1bSVinod Koul 5571bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0) 5671bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4) 5771bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8) 5871bb8a1bSVinod Koul 5971bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0) 6071bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4) 6171bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8) 6271bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_DIR BIT(15) 6371bb8a1bSVinod Koul 6471bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_ISS GENMASK(3, 0) 6571bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_OSS GENMASK(7, 4) 6671bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_BSS GENMASK(12, 8) 6771bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_CPSS GENMASK(15, 13) 6871bb8a1bSVinod Koul 6971bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_MIF BIT(0) 7071bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_CO BIT(1) 7171bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_COE BIT(2) 7271bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DO BIT(3) 7371bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DOE BIT(4) 7471bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_BKE BIT(5) 7571bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_WPDD BIT(6) 7671bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_CIBD BIT(8) 7771bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DIBD BIT(9) 7871bb8a1bSVinod Koul 7971bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DACTQE BIT(0) 8071bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DODS BIT(1) 8171bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3) 8271bb8a1bSVinod Koul 8371bb8a1bSVinod Koul #define SDW_SHIM_WAKEEN_ENABLE BIT(0) 8471bb8a1bSVinod Koul #define SDW_SHIM_WAKESTS_STATUS BIT(0) 8571bb8a1bSVinod Koul 8671bb8a1bSVinod Koul /* Intel ALH Register definitions */ 877cc6e315SPierre-Louis Bossart #define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x))) 88*79ee6631SPierre-Louis Bossart #define SDW_ALH_NUM_STREAMS 64 8971bb8a1bSVinod Koul 9071bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_DMAT_VAL 0x3 9171bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0) 9271bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16) 9371bb8a1bSVinod Koul 94c46302ecSVinod Koul enum intel_pdi_type { 95c46302ecSVinod Koul INTEL_PDI_IN = 0, 96c46302ecSVinod Koul INTEL_PDI_OUT = 1, 97c46302ecSVinod Koul INTEL_PDI_BD = 2, 98c46302ecSVinod Koul }; 99c46302ecSVinod Koul 10071bb8a1bSVinod Koul struct sdw_intel { 10171bb8a1bSVinod Koul struct sdw_cdns cdns; 10271bb8a1bSVinod Koul int instance; 10371bb8a1bSVinod Koul struct sdw_intel_link_res *res; 104*79ee6631SPierre-Louis Bossart #ifdef CONFIG_DEBUG_FS 105*79ee6631SPierre-Louis Bossart struct dentry *debugfs; 106*79ee6631SPierre-Louis Bossart #endif 10771bb8a1bSVinod Koul }; 10871bb8a1bSVinod Koul 10971bb8a1bSVinod Koul #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns) 11071bb8a1bSVinod Koul 11171bb8a1bSVinod Koul /* 11271bb8a1bSVinod Koul * Read, write helpers for HW registers 11371bb8a1bSVinod Koul */ 11471bb8a1bSVinod Koul static inline int intel_readl(void __iomem *base, int offset) 11571bb8a1bSVinod Koul { 11671bb8a1bSVinod Koul return readl(base + offset); 11771bb8a1bSVinod Koul } 11871bb8a1bSVinod Koul 11971bb8a1bSVinod Koul static inline void intel_writel(void __iomem *base, int offset, int value) 12071bb8a1bSVinod Koul { 12171bb8a1bSVinod Koul writel(value, base + offset); 12271bb8a1bSVinod Koul } 12371bb8a1bSVinod Koul 12471bb8a1bSVinod Koul static inline u16 intel_readw(void __iomem *base, int offset) 12571bb8a1bSVinod Koul { 12671bb8a1bSVinod Koul return readw(base + offset); 12771bb8a1bSVinod Koul } 12871bb8a1bSVinod Koul 12971bb8a1bSVinod Koul static inline void intel_writew(void __iomem *base, int offset, u16 value) 13071bb8a1bSVinod Koul { 13171bb8a1bSVinod Koul writew(value, base + offset); 13271bb8a1bSVinod Koul } 13371bb8a1bSVinod Koul 13471bb8a1bSVinod Koul static int intel_clear_bit(void __iomem *base, int offset, u32 value, u32 mask) 13571bb8a1bSVinod Koul { 13671bb8a1bSVinod Koul int timeout = 10; 13771bb8a1bSVinod Koul u32 reg_read; 13871bb8a1bSVinod Koul 13971bb8a1bSVinod Koul writel(value, base + offset); 14071bb8a1bSVinod Koul do { 14171bb8a1bSVinod Koul reg_read = readl(base + offset); 14271bb8a1bSVinod Koul if (!(reg_read & mask)) 14371bb8a1bSVinod Koul return 0; 14471bb8a1bSVinod Koul 14571bb8a1bSVinod Koul timeout--; 14671bb8a1bSVinod Koul udelay(50); 14771bb8a1bSVinod Koul } while (timeout != 0); 14871bb8a1bSVinod Koul 14971bb8a1bSVinod Koul return -EAGAIN; 15071bb8a1bSVinod Koul } 15171bb8a1bSVinod Koul 15271bb8a1bSVinod Koul static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask) 15371bb8a1bSVinod Koul { 15471bb8a1bSVinod Koul int timeout = 10; 15571bb8a1bSVinod Koul u32 reg_read; 15671bb8a1bSVinod Koul 15771bb8a1bSVinod Koul writel(value, base + offset); 15871bb8a1bSVinod Koul do { 15971bb8a1bSVinod Koul reg_read = readl(base + offset); 16071bb8a1bSVinod Koul if (reg_read & mask) 16171bb8a1bSVinod Koul return 0; 16271bb8a1bSVinod Koul 16371bb8a1bSVinod Koul timeout--; 16471bb8a1bSVinod Koul udelay(50); 16571bb8a1bSVinod Koul } while (timeout != 0); 16671bb8a1bSVinod Koul 16771bb8a1bSVinod Koul return -EAGAIN; 16871bb8a1bSVinod Koul } 16971bb8a1bSVinod Koul 17071bb8a1bSVinod Koul /* 171*79ee6631SPierre-Louis Bossart * debugfs 172*79ee6631SPierre-Louis Bossart */ 173*79ee6631SPierre-Louis Bossart #ifdef CONFIG_DEBUG_FS 174*79ee6631SPierre-Louis Bossart 175*79ee6631SPierre-Louis Bossart #define RD_BUF (2 * PAGE_SIZE) 176*79ee6631SPierre-Louis Bossart 177*79ee6631SPierre-Louis Bossart static ssize_t intel_sprintf(void __iomem *mem, bool l, 178*79ee6631SPierre-Louis Bossart char *buf, size_t pos, unsigned int reg) 179*79ee6631SPierre-Louis Bossart { 180*79ee6631SPierre-Louis Bossart int value; 181*79ee6631SPierre-Louis Bossart 182*79ee6631SPierre-Louis Bossart if (l) 183*79ee6631SPierre-Louis Bossart value = intel_readl(mem, reg); 184*79ee6631SPierre-Louis Bossart else 185*79ee6631SPierre-Louis Bossart value = intel_readw(mem, reg); 186*79ee6631SPierre-Louis Bossart 187*79ee6631SPierre-Louis Bossart return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value); 188*79ee6631SPierre-Louis Bossart } 189*79ee6631SPierre-Louis Bossart 190*79ee6631SPierre-Louis Bossart static int intel_reg_show(struct seq_file *s_file, void *data) 191*79ee6631SPierre-Louis Bossart { 192*79ee6631SPierre-Louis Bossart struct sdw_intel *sdw = s_file->private; 193*79ee6631SPierre-Louis Bossart void __iomem *s = sdw->res->shim; 194*79ee6631SPierre-Louis Bossart void __iomem *a = sdw->res->alh; 195*79ee6631SPierre-Louis Bossart char *buf; 196*79ee6631SPierre-Louis Bossart ssize_t ret; 197*79ee6631SPierre-Louis Bossart int i, j; 198*79ee6631SPierre-Louis Bossart unsigned int links, reg; 199*79ee6631SPierre-Louis Bossart 200*79ee6631SPierre-Louis Bossart buf = kzalloc(RD_BUF, GFP_KERNEL); 201*79ee6631SPierre-Louis Bossart if (!buf) 202*79ee6631SPierre-Louis Bossart return -ENOMEM; 203*79ee6631SPierre-Louis Bossart 204*79ee6631SPierre-Louis Bossart links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0); 205*79ee6631SPierre-Louis Bossart 206*79ee6631SPierre-Louis Bossart ret = scnprintf(buf, RD_BUF, "Register Value\n"); 207*79ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n"); 208*79ee6631SPierre-Louis Bossart 209*79ee6631SPierre-Louis Bossart for (i = 0; i < links; i++) { 210*79ee6631SPierre-Louis Bossart reg = SDW_SHIM_LCAP + i * 4; 211*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, true, buf, ret, reg); 212*79ee6631SPierre-Louis Bossart } 213*79ee6631SPierre-Louis Bossart 214*79ee6631SPierre-Louis Bossart for (i = 0; i < links; i++) { 215*79ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i); 216*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i)); 217*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i)); 218*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i)); 219*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i)); 220*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i)); 221*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i)); 222*79ee6631SPierre-Louis Bossart 223*79ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\n PCMSyCH registers\n"); 224*79ee6631SPierre-Louis Bossart 225*79ee6631SPierre-Louis Bossart /* 226*79ee6631SPierre-Louis Bossart * the value 10 is the number of PDIs. We will need a 227*79ee6631SPierre-Louis Bossart * cleanup to remove hard-coded Intel configurations 228*79ee6631SPierre-Louis Bossart * from cadence_master.c 229*79ee6631SPierre-Louis Bossart */ 230*79ee6631SPierre-Louis Bossart for (j = 0; j < 10; j++) { 231*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, 232*79ee6631SPierre-Louis Bossart SDW_SHIM_PCMSYCHM(i, j)); 233*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, 234*79ee6631SPierre-Louis Bossart SDW_SHIM_PCMSYCHC(i, j)); 235*79ee6631SPierre-Louis Bossart } 236*79ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\n PDMSCAP, IOCTL, CTMCTL\n"); 237*79ee6631SPierre-Louis Bossart 238*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i)); 239*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i)); 240*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i)); 241*79ee6631SPierre-Louis Bossart } 242*79ee6631SPierre-Louis Bossart 243*79ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n"); 244*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN); 245*79ee6631SPierre-Louis Bossart ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS); 246*79ee6631SPierre-Louis Bossart 247*79ee6631SPierre-Louis Bossart ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n"); 248*79ee6631SPierre-Louis Bossart for (i = 0; i < SDW_ALH_NUM_STREAMS; i++) 249*79ee6631SPierre-Louis Bossart ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i)); 250*79ee6631SPierre-Louis Bossart 251*79ee6631SPierre-Louis Bossart seq_printf(s_file, "%s", buf); 252*79ee6631SPierre-Louis Bossart kfree(buf); 253*79ee6631SPierre-Louis Bossart 254*79ee6631SPierre-Louis Bossart return 0; 255*79ee6631SPierre-Louis Bossart } 256*79ee6631SPierre-Louis Bossart DEFINE_SHOW_ATTRIBUTE(intel_reg); 257*79ee6631SPierre-Louis Bossart 258*79ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw) 259*79ee6631SPierre-Louis Bossart { 260*79ee6631SPierre-Louis Bossart struct dentry *root = sdw->cdns.bus.debugfs; 261*79ee6631SPierre-Louis Bossart 262*79ee6631SPierre-Louis Bossart if (!root) 263*79ee6631SPierre-Louis Bossart return; 264*79ee6631SPierre-Louis Bossart 265*79ee6631SPierre-Louis Bossart sdw->debugfs = debugfs_create_dir("intel-sdw", root); 266*79ee6631SPierre-Louis Bossart 267*79ee6631SPierre-Louis Bossart debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw, 268*79ee6631SPierre-Louis Bossart &intel_reg_fops); 269*79ee6631SPierre-Louis Bossart 270*79ee6631SPierre-Louis Bossart sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs); 271*79ee6631SPierre-Louis Bossart } 272*79ee6631SPierre-Louis Bossart 273*79ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw) 274*79ee6631SPierre-Louis Bossart { 275*79ee6631SPierre-Louis Bossart debugfs_remove_recursive(sdw->debugfs); 276*79ee6631SPierre-Louis Bossart } 277*79ee6631SPierre-Louis Bossart #else 278*79ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw) {} 279*79ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw) {} 280*79ee6631SPierre-Louis Bossart #endif /* CONFIG_DEBUG_FS */ 281*79ee6631SPierre-Louis Bossart 282*79ee6631SPierre-Louis Bossart /* 28371bb8a1bSVinod Koul * shim ops 28471bb8a1bSVinod Koul */ 28571bb8a1bSVinod Koul 28671bb8a1bSVinod Koul static int intel_link_power_up(struct sdw_intel *sdw) 28771bb8a1bSVinod Koul { 28871bb8a1bSVinod Koul unsigned int link_id = sdw->instance; 28971bb8a1bSVinod Koul void __iomem *shim = sdw->res->shim; 29071bb8a1bSVinod Koul int spa_mask, cpa_mask; 29171bb8a1bSVinod Koul int link_control, ret; 29271bb8a1bSVinod Koul 29371bb8a1bSVinod Koul /* Link power up sequence */ 29471bb8a1bSVinod Koul link_control = intel_readl(shim, SDW_SHIM_LCTL); 29571bb8a1bSVinod Koul spa_mask = (SDW_SHIM_LCTL_SPA << link_id); 29671bb8a1bSVinod Koul cpa_mask = (SDW_SHIM_LCTL_CPA << link_id); 29771bb8a1bSVinod Koul link_control |= spa_mask; 29871bb8a1bSVinod Koul 29971bb8a1bSVinod Koul ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); 30071bb8a1bSVinod Koul if (ret < 0) 30171bb8a1bSVinod Koul return ret; 30271bb8a1bSVinod Koul 30371bb8a1bSVinod Koul sdw->cdns.link_up = true; 30471bb8a1bSVinod Koul return 0; 30571bb8a1bSVinod Koul } 30671bb8a1bSVinod Koul 30771bb8a1bSVinod Koul static int intel_shim_init(struct sdw_intel *sdw) 30871bb8a1bSVinod Koul { 30971bb8a1bSVinod Koul void __iomem *shim = sdw->res->shim; 31071bb8a1bSVinod Koul unsigned int link_id = sdw->instance; 31171bb8a1bSVinod Koul int sync_reg, ret; 31271bb8a1bSVinod Koul u16 ioctl = 0, act = 0; 31371bb8a1bSVinod Koul 31471bb8a1bSVinod Koul /* Initialize Shim */ 31571bb8a1bSVinod Koul ioctl |= SDW_SHIM_IOCTL_BKE; 31671bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 31771bb8a1bSVinod Koul 31871bb8a1bSVinod Koul ioctl |= SDW_SHIM_IOCTL_WPDD; 31971bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 32071bb8a1bSVinod Koul 32171bb8a1bSVinod Koul ioctl |= SDW_SHIM_IOCTL_DO; 32271bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 32371bb8a1bSVinod Koul 32471bb8a1bSVinod Koul ioctl |= SDW_SHIM_IOCTL_DOE; 32571bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 32671bb8a1bSVinod Koul 32771bb8a1bSVinod Koul /* Switch to MIP from Glue logic */ 32871bb8a1bSVinod Koul ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); 32971bb8a1bSVinod Koul 33071bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_DOE); 33171bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 33271bb8a1bSVinod Koul 33371bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_DO); 33471bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 33571bb8a1bSVinod Koul 33671bb8a1bSVinod Koul ioctl |= (SDW_SHIM_IOCTL_MIF); 33771bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 33871bb8a1bSVinod Koul 33971bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_BKE); 34071bb8a1bSVinod Koul ioctl &= ~(SDW_SHIM_IOCTL_COE); 34171bb8a1bSVinod Koul 34271bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); 34371bb8a1bSVinod Koul 34471bb8a1bSVinod Koul act |= 0x1 << SDW_REG_SHIFT(SDW_SHIM_CTMCTL_DOAIS); 34571bb8a1bSVinod Koul act |= SDW_SHIM_CTMCTL_DACTQE; 34671bb8a1bSVinod Koul act |= SDW_SHIM_CTMCTL_DODS; 34771bb8a1bSVinod Koul intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act); 34871bb8a1bSVinod Koul 34971bb8a1bSVinod Koul /* Now set SyncPRD period */ 35071bb8a1bSVinod Koul sync_reg = intel_readl(shim, SDW_SHIM_SYNC); 35171bb8a1bSVinod Koul sync_reg |= (SDW_SHIM_SYNC_SYNCPRD_VAL << 35271bb8a1bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_SYNC_SYNCPRD)); 35371bb8a1bSVinod Koul 35471bb8a1bSVinod Koul /* Set SyncCPU bit */ 35571bb8a1bSVinod Koul sync_reg |= SDW_SHIM_SYNC_SYNCCPU; 35671bb8a1bSVinod Koul ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, 35771bb8a1bSVinod Koul SDW_SHIM_SYNC_SYNCCPU); 35871bb8a1bSVinod Koul if (ret < 0) 35917ed5befSPierre-Louis Bossart dev_err(sdw->cdns.dev, "Failed to set sync period: %d\n", ret); 36071bb8a1bSVinod Koul 36171bb8a1bSVinod Koul return ret; 36271bb8a1bSVinod Koul } 36371bb8a1bSVinod Koul 36437a2d22bSVinod Koul /* 36537a2d22bSVinod Koul * PDI routines 36637a2d22bSVinod Koul */ 36737a2d22bSVinod Koul static void intel_pdi_init(struct sdw_intel *sdw, 36837a2d22bSVinod Koul struct sdw_cdns_stream_config *config) 36937a2d22bSVinod Koul { 37037a2d22bSVinod Koul void __iomem *shim = sdw->res->shim; 37137a2d22bSVinod Koul unsigned int link_id = sdw->instance; 37237a2d22bSVinod Koul int pcm_cap, pdm_cap; 37337a2d22bSVinod Koul 37437a2d22bSVinod Koul /* PCM Stream Capability */ 37537a2d22bSVinod Koul pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id)); 37637a2d22bSVinod Koul 37737a2d22bSVinod Koul config->pcm_bd = (pcm_cap & SDW_SHIM_PCMSCAP_BSS) >> 37837a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_BSS); 37937a2d22bSVinod Koul config->pcm_in = (pcm_cap & SDW_SHIM_PCMSCAP_ISS) >> 38037a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_ISS); 38137a2d22bSVinod Koul config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >> 38237a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS); 38337a2d22bSVinod Koul 384121f4361SPierre-Louis Bossart dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n", 385121f4361SPierre-Louis Bossart config->pcm_bd, config->pcm_in, config->pcm_out); 386121f4361SPierre-Louis Bossart 38737a2d22bSVinod Koul /* PDM Stream Capability */ 38837a2d22bSVinod Koul pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); 38937a2d22bSVinod Koul 39037a2d22bSVinod Koul config->pdm_bd = (pdm_cap & SDW_SHIM_PDMSCAP_BSS) >> 39137a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_BSS); 39237a2d22bSVinod Koul config->pdm_in = (pdm_cap & SDW_SHIM_PDMSCAP_ISS) >> 39337a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS); 39437a2d22bSVinod Koul config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >> 39537a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS); 396121f4361SPierre-Louis Bossart 397121f4361SPierre-Louis Bossart dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n", 398121f4361SPierre-Louis Bossart config->pdm_bd, config->pdm_in, config->pdm_out); 39937a2d22bSVinod Koul } 40037a2d22bSVinod Koul 40137a2d22bSVinod Koul static int 40237a2d22bSVinod Koul intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm) 40337a2d22bSVinod Koul { 40437a2d22bSVinod Koul void __iomem *shim = sdw->res->shim; 40537a2d22bSVinod Koul unsigned int link_id = sdw->instance; 40637a2d22bSVinod Koul int count; 40737a2d22bSVinod Koul 40837a2d22bSVinod Koul if (pcm) { 40937a2d22bSVinod Koul count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num)); 41018046335SPierre-Louis Bossart 41118046335SPierre-Louis Bossart /* 41218046335SPierre-Louis Bossart * WORKAROUND: on all existing Intel controllers, pdi 41318046335SPierre-Louis Bossart * number 2 reports channel count as 1 even though it 41418046335SPierre-Louis Bossart * supports 8 channels. Performing hardcoding for pdi 41518046335SPierre-Louis Bossart * number 2. 41618046335SPierre-Louis Bossart */ 41718046335SPierre-Louis Bossart if (pdi_num == 2) 41818046335SPierre-Louis Bossart count = 7; 41918046335SPierre-Louis Bossart 42037a2d22bSVinod Koul } else { 42137a2d22bSVinod Koul count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); 42237a2d22bSVinod Koul count = ((count & SDW_SHIM_PDMSCAP_CPSS) >> 42337a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_CPSS)); 42437a2d22bSVinod Koul } 42537a2d22bSVinod Koul 42637a2d22bSVinod Koul /* zero based values for channel count in register */ 42737a2d22bSVinod Koul count++; 42837a2d22bSVinod Koul 42937a2d22bSVinod Koul return count; 43037a2d22bSVinod Koul } 43137a2d22bSVinod Koul 43237a2d22bSVinod Koul static int intel_pdi_get_ch_update(struct sdw_intel *sdw, 43337a2d22bSVinod Koul struct sdw_cdns_pdi *pdi, 43437a2d22bSVinod Koul unsigned int num_pdi, 43537a2d22bSVinod Koul unsigned int *num_ch, bool pcm) 43637a2d22bSVinod Koul { 43737a2d22bSVinod Koul int i, ch_count = 0; 43837a2d22bSVinod Koul 43937a2d22bSVinod Koul for (i = 0; i < num_pdi; i++) { 44037a2d22bSVinod Koul pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm); 44137a2d22bSVinod Koul ch_count += pdi->ch_count; 44237a2d22bSVinod Koul pdi++; 44337a2d22bSVinod Koul } 44437a2d22bSVinod Koul 44537a2d22bSVinod Koul *num_ch = ch_count; 44637a2d22bSVinod Koul return 0; 44737a2d22bSVinod Koul } 44837a2d22bSVinod Koul 44937a2d22bSVinod Koul static int intel_pdi_stream_ch_update(struct sdw_intel *sdw, 45037a2d22bSVinod Koul struct sdw_cdns_streams *stream, bool pcm) 45137a2d22bSVinod Koul { 45237a2d22bSVinod Koul intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd, 45337a2d22bSVinod Koul &stream->num_ch_bd, pcm); 45437a2d22bSVinod Koul 45537a2d22bSVinod Koul intel_pdi_get_ch_update(sdw, stream->in, stream->num_in, 45637a2d22bSVinod Koul &stream->num_ch_in, pcm); 45737a2d22bSVinod Koul 45837a2d22bSVinod Koul intel_pdi_get_ch_update(sdw, stream->out, stream->num_out, 45937a2d22bSVinod Koul &stream->num_ch_out, pcm); 46037a2d22bSVinod Koul 46137a2d22bSVinod Koul return 0; 46237a2d22bSVinod Koul } 46337a2d22bSVinod Koul 46437a2d22bSVinod Koul static int intel_pdi_ch_update(struct sdw_intel *sdw) 46537a2d22bSVinod Koul { 46637a2d22bSVinod Koul /* First update PCM streams followed by PDM streams */ 46737a2d22bSVinod Koul intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true); 46837a2d22bSVinod Koul intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false); 46937a2d22bSVinod Koul 47037a2d22bSVinod Koul return 0; 47137a2d22bSVinod Koul } 47237a2d22bSVinod Koul 47337a2d22bSVinod Koul static void 47437a2d22bSVinod Koul intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) 47537a2d22bSVinod Koul { 47637a2d22bSVinod Koul void __iomem *shim = sdw->res->shim; 47737a2d22bSVinod Koul unsigned int link_id = sdw->instance; 47837a2d22bSVinod Koul int pdi_conf = 0; 47937a2d22bSVinod Koul 48037a2d22bSVinod Koul pdi->intel_alh_id = (link_id * 16) + pdi->num + 5; 48137a2d22bSVinod Koul 48237a2d22bSVinod Koul /* 48337a2d22bSVinod Koul * Program stream parameters to stream SHIM register 48437a2d22bSVinod Koul * This is applicable for PCM stream only. 48537a2d22bSVinod Koul */ 48637a2d22bSVinod Koul if (pdi->type != SDW_STREAM_PCM) 48737a2d22bSVinod Koul return; 48837a2d22bSVinod Koul 48937a2d22bSVinod Koul if (pdi->dir == SDW_DATA_DIR_RX) 49037a2d22bSVinod Koul pdi_conf |= SDW_SHIM_PCMSYCM_DIR; 49137a2d22bSVinod Koul else 49237a2d22bSVinod Koul pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR); 49337a2d22bSVinod Koul 49437a2d22bSVinod Koul pdi_conf |= (pdi->intel_alh_id << 49537a2d22bSVinod Koul SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_STREAM)); 49637a2d22bSVinod Koul pdi_conf |= (pdi->l_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_LCHN)); 49737a2d22bSVinod Koul pdi_conf |= (pdi->h_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_HCHN)); 49837a2d22bSVinod Koul 49937a2d22bSVinod Koul intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf); 50037a2d22bSVinod Koul } 50137a2d22bSVinod Koul 50237a2d22bSVinod Koul static void 50337a2d22bSVinod Koul intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) 50437a2d22bSVinod Koul { 50537a2d22bSVinod Koul void __iomem *alh = sdw->res->alh; 50637a2d22bSVinod Koul unsigned int link_id = sdw->instance; 50737a2d22bSVinod Koul unsigned int conf; 50837a2d22bSVinod Koul 50937a2d22bSVinod Koul pdi->intel_alh_id = (link_id * 16) + pdi->num + 5; 51037a2d22bSVinod Koul 51137a2d22bSVinod Koul /* Program Stream config ALH register */ 51237a2d22bSVinod Koul conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id)); 51337a2d22bSVinod Koul 51437a2d22bSVinod Koul conf |= (SDW_ALH_STRMZCFG_DMAT_VAL << 51537a2d22bSVinod Koul SDW_REG_SHIFT(SDW_ALH_STRMZCFG_DMAT)); 51637a2d22bSVinod Koul 51737a2d22bSVinod Koul conf |= ((pdi->ch_count - 1) << 51837a2d22bSVinod Koul SDW_REG_SHIFT(SDW_ALH_STRMZCFG_CHN)); 51937a2d22bSVinod Koul 52037a2d22bSVinod Koul intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf); 52137a2d22bSVinod Koul } 52237a2d22bSVinod Koul 523c46302ecSVinod Koul static int intel_config_stream(struct sdw_intel *sdw, 524c46302ecSVinod Koul struct snd_pcm_substream *substream, 525c46302ecSVinod Koul struct snd_soc_dai *dai, 526c46302ecSVinod Koul struct snd_pcm_hw_params *hw_params, int link_id) 527c46302ecSVinod Koul { 52805c8afe4SPierre-Louis Bossart struct sdw_intel_link_res *res = sdw->res; 52905c8afe4SPierre-Louis Bossart 53005c8afe4SPierre-Louis Bossart if (res->ops && res->ops->config_stream && res->arg) 53105c8afe4SPierre-Louis Bossart return res->ops->config_stream(res->arg, 532c46302ecSVinod Koul substream, dai, hw_params, link_id); 533c46302ecSVinod Koul 534c46302ecSVinod Koul return -EIO; 535c46302ecSVinod Koul } 536c46302ecSVinod Koul 537c46302ecSVinod Koul /* 53830246e2dSShreyas NC * bank switch routines 53930246e2dSShreyas NC */ 54030246e2dSShreyas NC 54130246e2dSShreyas NC static int intel_pre_bank_switch(struct sdw_bus *bus) 54230246e2dSShreyas NC { 54330246e2dSShreyas NC struct sdw_cdns *cdns = bus_to_cdns(bus); 54430246e2dSShreyas NC struct sdw_intel *sdw = cdns_to_intel(cdns); 54530246e2dSShreyas NC void __iomem *shim = sdw->res->shim; 54630246e2dSShreyas NC int sync_reg; 54730246e2dSShreyas NC 54830246e2dSShreyas NC /* Write to register only for multi-link */ 54930246e2dSShreyas NC if (!bus->multi_link) 55030246e2dSShreyas NC return 0; 55130246e2dSShreyas NC 55230246e2dSShreyas NC /* Read SYNC register */ 55330246e2dSShreyas NC sync_reg = intel_readl(shim, SDW_SHIM_SYNC); 55430246e2dSShreyas NC sync_reg |= SDW_SHIM_SYNC_CMDSYNC << sdw->instance; 55530246e2dSShreyas NC intel_writel(shim, SDW_SHIM_SYNC, sync_reg); 55630246e2dSShreyas NC 55730246e2dSShreyas NC return 0; 55830246e2dSShreyas NC } 55930246e2dSShreyas NC 56030246e2dSShreyas NC static int intel_post_bank_switch(struct sdw_bus *bus) 56130246e2dSShreyas NC { 56230246e2dSShreyas NC struct sdw_cdns *cdns = bus_to_cdns(bus); 56330246e2dSShreyas NC struct sdw_intel *sdw = cdns_to_intel(cdns); 56430246e2dSShreyas NC void __iomem *shim = sdw->res->shim; 56530246e2dSShreyas NC int sync_reg, ret; 56630246e2dSShreyas NC 56730246e2dSShreyas NC /* Write to register only for multi-link */ 56830246e2dSShreyas NC if (!bus->multi_link) 56930246e2dSShreyas NC return 0; 57030246e2dSShreyas NC 57130246e2dSShreyas NC /* Read SYNC register */ 57230246e2dSShreyas NC sync_reg = intel_readl(shim, SDW_SHIM_SYNC); 57330246e2dSShreyas NC 57430246e2dSShreyas NC /* 57530246e2dSShreyas NC * post_bank_switch() ops is called from the bus in loop for 57630246e2dSShreyas NC * all the Masters in the steam with the expectation that 57730246e2dSShreyas NC * we trigger the bankswitch for the only first Master in the list 57830246e2dSShreyas NC * and do nothing for the other Masters 57930246e2dSShreyas NC * 58030246e2dSShreyas NC * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master. 58130246e2dSShreyas NC */ 58230246e2dSShreyas NC if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) 58330246e2dSShreyas NC return 0; 58430246e2dSShreyas NC 58530246e2dSShreyas NC /* 58630246e2dSShreyas NC * Set SyncGO bit to synchronously trigger a bank switch for 58730246e2dSShreyas NC * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all 58830246e2dSShreyas NC * the Masters. 58930246e2dSShreyas NC */ 59030246e2dSShreyas NC sync_reg |= SDW_SHIM_SYNC_SYNCGO; 59130246e2dSShreyas NC 59230246e2dSShreyas NC ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, 59330246e2dSShreyas NC SDW_SHIM_SYNC_SYNCGO); 59430246e2dSShreyas NC if (ret < 0) 59517ed5befSPierre-Louis Bossart dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret); 59630246e2dSShreyas NC 59730246e2dSShreyas NC return ret; 59830246e2dSShreyas NC } 59930246e2dSShreyas NC 60030246e2dSShreyas NC /* 601c46302ecSVinod Koul * DAI routines 602c46302ecSVinod Koul */ 603c46302ecSVinod Koul 604c46302ecSVinod Koul static struct sdw_cdns_port *intel_alloc_port(struct sdw_intel *sdw, 605c46302ecSVinod Koul u32 ch, u32 dir, bool pcm) 606c46302ecSVinod Koul { 607c46302ecSVinod Koul struct sdw_cdns *cdns = &sdw->cdns; 608c46302ecSVinod Koul struct sdw_cdns_port *port = NULL; 609c46302ecSVinod Koul int i, ret = 0; 610c46302ecSVinod Koul 611c46302ecSVinod Koul for (i = 0; i < cdns->num_ports; i++) { 6122890a636SPierre-Louis Bossart if (cdns->ports[i].assigned) 613c46302ecSVinod Koul continue; 614c46302ecSVinod Koul 615c46302ecSVinod Koul port = &cdns->ports[i]; 616c46302ecSVinod Koul port->assigned = true; 617c46302ecSVinod Koul port->direction = dir; 618c46302ecSVinod Koul port->ch = ch; 619c46302ecSVinod Koul break; 620c46302ecSVinod Koul } 621c46302ecSVinod Koul 622c46302ecSVinod Koul if (!port) { 623c46302ecSVinod Koul dev_err(cdns->dev, "Unable to find a free port\n"); 624c46302ecSVinod Koul return NULL; 625c46302ecSVinod Koul } 626c46302ecSVinod Koul 627c46302ecSVinod Koul if (pcm) { 628c46302ecSVinod Koul ret = sdw_cdns_alloc_stream(cdns, &cdns->pcm, port, ch, dir); 629c46302ecSVinod Koul if (ret) 630c46302ecSVinod Koul goto out; 631c46302ecSVinod Koul 632c46302ecSVinod Koul intel_pdi_shim_configure(sdw, port->pdi); 633c46302ecSVinod Koul sdw_cdns_config_stream(cdns, port, ch, dir, port->pdi); 634c46302ecSVinod Koul 635c46302ecSVinod Koul intel_pdi_alh_configure(sdw, port->pdi); 636c46302ecSVinod Koul 637c46302ecSVinod Koul } else { 638c46302ecSVinod Koul ret = sdw_cdns_alloc_stream(cdns, &cdns->pdm, port, ch, dir); 639c46302ecSVinod Koul } 640c46302ecSVinod Koul 641c46302ecSVinod Koul out: 642c46302ecSVinod Koul if (ret) { 643c46302ecSVinod Koul port->assigned = false; 644c46302ecSVinod Koul port = NULL; 645c46302ecSVinod Koul } 646c46302ecSVinod Koul 647c46302ecSVinod Koul return port; 648c46302ecSVinod Koul } 649c46302ecSVinod Koul 650c46302ecSVinod Koul static void intel_port_cleanup(struct sdw_cdns_dma_data *dma) 651c46302ecSVinod Koul { 652c46302ecSVinod Koul int i; 653c46302ecSVinod Koul 654c46302ecSVinod Koul for (i = 0; i < dma->nr_ports; i++) { 655c46302ecSVinod Koul if (dma->port[i]) { 656c46302ecSVinod Koul dma->port[i]->pdi->assigned = false; 657c46302ecSVinod Koul dma->port[i]->pdi = NULL; 658c46302ecSVinod Koul dma->port[i]->assigned = false; 659c46302ecSVinod Koul dma->port[i] = NULL; 660c46302ecSVinod Koul } 661c46302ecSVinod Koul } 662c46302ecSVinod Koul } 663c46302ecSVinod Koul 664c46302ecSVinod Koul static int intel_hw_params(struct snd_pcm_substream *substream, 665c46302ecSVinod Koul struct snd_pcm_hw_params *params, 666c46302ecSVinod Koul struct snd_soc_dai *dai) 667c46302ecSVinod Koul { 668c46302ecSVinod Koul struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 669c46302ecSVinod Koul struct sdw_intel *sdw = cdns_to_intel(cdns); 670c46302ecSVinod Koul struct sdw_cdns_dma_data *dma; 671c46302ecSVinod Koul struct sdw_stream_config sconfig; 672c46302ecSVinod Koul struct sdw_port_config *pconfig; 673c46302ecSVinod Koul int ret, i, ch, dir; 674c46302ecSVinod Koul bool pcm = true; 675c46302ecSVinod Koul 676c46302ecSVinod Koul dma = snd_soc_dai_get_dma_data(dai, substream); 677c46302ecSVinod Koul if (!dma) 678c46302ecSVinod Koul return -EIO; 679c46302ecSVinod Koul 680c46302ecSVinod Koul ch = params_channels(params); 681c46302ecSVinod Koul if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 682c46302ecSVinod Koul dir = SDW_DATA_DIR_RX; 683c46302ecSVinod Koul else 684c46302ecSVinod Koul dir = SDW_DATA_DIR_TX; 685c46302ecSVinod Koul 686c46302ecSVinod Koul if (dma->stream_type == SDW_STREAM_PDM) { 687c46302ecSVinod Koul /* TODO: Check whether PDM decimator is already in use */ 688c46302ecSVinod Koul dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pdm, ch, dir); 689c46302ecSVinod Koul pcm = false; 690c46302ecSVinod Koul } else { 691c46302ecSVinod Koul dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pcm, ch, dir); 692c46302ecSVinod Koul } 693c46302ecSVinod Koul 694c46302ecSVinod Koul if (!dma->nr_ports) { 69517ed5befSPierre-Louis Bossart dev_err(dai->dev, "ports/resources not available\n"); 696c46302ecSVinod Koul return -EINVAL; 697c46302ecSVinod Koul } 698c46302ecSVinod Koul 699c46302ecSVinod Koul dma->port = kcalloc(dma->nr_ports, sizeof(*dma->port), GFP_KERNEL); 700c46302ecSVinod Koul if (!dma->port) 701c46302ecSVinod Koul return -ENOMEM; 702c46302ecSVinod Koul 703c46302ecSVinod Koul for (i = 0; i < dma->nr_ports; i++) { 704c46302ecSVinod Koul dma->port[i] = intel_alloc_port(sdw, ch, dir, pcm); 705c46302ecSVinod Koul if (!dma->port[i]) { 706c46302ecSVinod Koul ret = -EINVAL; 707c46302ecSVinod Koul goto port_error; 708c46302ecSVinod Koul } 709c46302ecSVinod Koul } 710c46302ecSVinod Koul 711c46302ecSVinod Koul /* Inform DSP about PDI stream number */ 712c46302ecSVinod Koul for (i = 0; i < dma->nr_ports; i++) { 713c46302ecSVinod Koul ret = intel_config_stream(sdw, substream, dai, params, 714c46302ecSVinod Koul dma->port[i]->pdi->intel_alh_id); 715c46302ecSVinod Koul if (ret) 716c46302ecSVinod Koul goto port_error; 717c46302ecSVinod Koul } 718c46302ecSVinod Koul 719c46302ecSVinod Koul sconfig.direction = dir; 720c46302ecSVinod Koul sconfig.ch_count = ch; 721c46302ecSVinod Koul sconfig.frame_rate = params_rate(params); 722c46302ecSVinod Koul sconfig.type = dma->stream_type; 723c46302ecSVinod Koul 724c46302ecSVinod Koul if (dma->stream_type == SDW_STREAM_PDM) { 725c46302ecSVinod Koul sconfig.frame_rate *= 50; 726c46302ecSVinod Koul sconfig.bps = 1; 727c46302ecSVinod Koul } else { 728c46302ecSVinod Koul sconfig.bps = snd_pcm_format_width(params_format(params)); 729c46302ecSVinod Koul } 730c46302ecSVinod Koul 731c46302ecSVinod Koul /* Port configuration */ 732c46302ecSVinod Koul pconfig = kcalloc(dma->nr_ports, sizeof(*pconfig), GFP_KERNEL); 733c46302ecSVinod Koul if (!pconfig) { 734c46302ecSVinod Koul ret = -ENOMEM; 735c46302ecSVinod Koul goto port_error; 736c46302ecSVinod Koul } 737c46302ecSVinod Koul 738c46302ecSVinod Koul for (i = 0; i < dma->nr_ports; i++) { 739c46302ecSVinod Koul pconfig[i].num = dma->port[i]->num; 740c46302ecSVinod Koul pconfig[i].ch_mask = (1 << ch) - 1; 741c46302ecSVinod Koul } 742c46302ecSVinod Koul 743c46302ecSVinod Koul ret = sdw_stream_add_master(&cdns->bus, &sconfig, 744c46302ecSVinod Koul pconfig, dma->nr_ports, dma->stream); 745c46302ecSVinod Koul if (ret) { 74617ed5befSPierre-Louis Bossart dev_err(cdns->dev, "add master to stream failed:%d\n", ret); 747c46302ecSVinod Koul goto stream_error; 748c46302ecSVinod Koul } 749c46302ecSVinod Koul 750c46302ecSVinod Koul kfree(pconfig); 751c46302ecSVinod Koul return ret; 752c46302ecSVinod Koul 753c46302ecSVinod Koul stream_error: 754c46302ecSVinod Koul kfree(pconfig); 755c46302ecSVinod Koul port_error: 756c46302ecSVinod Koul intel_port_cleanup(dma); 757c46302ecSVinod Koul kfree(dma->port); 758c46302ecSVinod Koul return ret; 759c46302ecSVinod Koul } 760c46302ecSVinod Koul 761c46302ecSVinod Koul static int 762c46302ecSVinod Koul intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 763c46302ecSVinod Koul { 764c46302ecSVinod Koul struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); 765c46302ecSVinod Koul struct sdw_cdns_dma_data *dma; 766c46302ecSVinod Koul int ret; 767c46302ecSVinod Koul 768c46302ecSVinod Koul dma = snd_soc_dai_get_dma_data(dai, substream); 769c46302ecSVinod Koul if (!dma) 770c46302ecSVinod Koul return -EIO; 771c46302ecSVinod Koul 772c46302ecSVinod Koul ret = sdw_stream_remove_master(&cdns->bus, dma->stream); 773c46302ecSVinod Koul if (ret < 0) 77417ed5befSPierre-Louis Bossart dev_err(dai->dev, "remove master from stream %s failed: %d\n", 775c46302ecSVinod Koul dma->stream->name, ret); 776c46302ecSVinod Koul 777c46302ecSVinod Koul intel_port_cleanup(dma); 778c46302ecSVinod Koul kfree(dma->port); 779c46302ecSVinod Koul return ret; 780c46302ecSVinod Koul } 781c46302ecSVinod Koul 782183c7687SPierre-Louis Bossart static void intel_shutdown(struct snd_pcm_substream *substream, 783183c7687SPierre-Louis Bossart struct snd_soc_dai *dai) 784183c7687SPierre-Louis Bossart { 785183c7687SPierre-Louis Bossart struct sdw_cdns_dma_data *dma; 786183c7687SPierre-Louis Bossart 787183c7687SPierre-Louis Bossart dma = snd_soc_dai_get_dma_data(dai, substream); 788183c7687SPierre-Louis Bossart if (!dma) 789183c7687SPierre-Louis Bossart return; 790183c7687SPierre-Louis Bossart 791183c7687SPierre-Louis Bossart snd_soc_dai_set_dma_data(dai, substream, NULL); 792183c7687SPierre-Louis Bossart kfree(dma); 793183c7687SPierre-Louis Bossart } 794183c7687SPierre-Louis Bossart 795c46302ecSVinod Koul static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, 796c46302ecSVinod Koul void *stream, int direction) 797c46302ecSVinod Koul { 798c46302ecSVinod Koul return cdns_set_sdw_stream(dai, stream, true, direction); 799c46302ecSVinod Koul } 800c46302ecSVinod Koul 801c46302ecSVinod Koul static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, 802c46302ecSVinod Koul void *stream, int direction) 803c46302ecSVinod Koul { 804c46302ecSVinod Koul return cdns_set_sdw_stream(dai, stream, false, direction); 805c46302ecSVinod Koul } 806c46302ecSVinod Koul 807b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pcm_dai_ops = { 808c46302ecSVinod Koul .hw_params = intel_hw_params, 809c46302ecSVinod Koul .hw_free = intel_hw_free, 810183c7687SPierre-Louis Bossart .shutdown = intel_shutdown, 811c46302ecSVinod Koul .set_sdw_stream = intel_pcm_set_sdw_stream, 812c46302ecSVinod Koul }; 813c46302ecSVinod Koul 814b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pdm_dai_ops = { 815c46302ecSVinod Koul .hw_params = intel_hw_params, 816c46302ecSVinod Koul .hw_free = intel_hw_free, 817183c7687SPierre-Louis Bossart .shutdown = intel_shutdown, 818c46302ecSVinod Koul .set_sdw_stream = intel_pdm_set_sdw_stream, 819c46302ecSVinod Koul }; 820c46302ecSVinod Koul 821c46302ecSVinod Koul static const struct snd_soc_component_driver dai_component = { 822c46302ecSVinod Koul .name = "soundwire", 823c46302ecSVinod Koul }; 824c46302ecSVinod Koul 825c46302ecSVinod Koul static int intel_create_dai(struct sdw_cdns *cdns, 826c46302ecSVinod Koul struct snd_soc_dai_driver *dais, 827c46302ecSVinod Koul enum intel_pdi_type type, 828c46302ecSVinod Koul u32 num, u32 off, u32 max_ch, bool pcm) 829c46302ecSVinod Koul { 830c46302ecSVinod Koul int i; 831c46302ecSVinod Koul 832c46302ecSVinod Koul if (num == 0) 833c46302ecSVinod Koul return 0; 834c46302ecSVinod Koul 835c46302ecSVinod Koul /* TODO: Read supported rates/formats from hardware */ 836c46302ecSVinod Koul for (i = off; i < (off + num); i++) { 837c46302ecSVinod Koul dais[i].name = kasprintf(GFP_KERNEL, "SDW%d Pin%d", 838c46302ecSVinod Koul cdns->instance, i); 839c46302ecSVinod Koul if (!dais[i].name) 840c46302ecSVinod Koul return -ENOMEM; 841c46302ecSVinod Koul 842c46302ecSVinod Koul if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) { 8431215daeeSVinod Koul dais[i].playback.stream_name = 8441215daeeSVinod Koul kasprintf(GFP_KERNEL, "SDW%d Tx%d", 845c46302ecSVinod Koul cdns->instance, i); 846c46302ecSVinod Koul if (!dais[i].playback.stream_name) { 847c46302ecSVinod Koul kfree(dais[i].name); 848c46302ecSVinod Koul return -ENOMEM; 849c46302ecSVinod Koul } 850c46302ecSVinod Koul 851c46302ecSVinod Koul dais[i].playback.channels_min = 1; 852c46302ecSVinod Koul dais[i].playback.channels_max = max_ch; 853c46302ecSVinod Koul dais[i].playback.rates = SNDRV_PCM_RATE_48000; 854c46302ecSVinod Koul dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE; 855c46302ecSVinod Koul } 856c46302ecSVinod Koul 857c46302ecSVinod Koul if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) { 8581215daeeSVinod Koul dais[i].capture.stream_name = 8591215daeeSVinod Koul kasprintf(GFP_KERNEL, "SDW%d Rx%d", 860c46302ecSVinod Koul cdns->instance, i); 861c46302ecSVinod Koul if (!dais[i].capture.stream_name) { 862c46302ecSVinod Koul kfree(dais[i].name); 863c46302ecSVinod Koul kfree(dais[i].playback.stream_name); 864c46302ecSVinod Koul return -ENOMEM; 865c46302ecSVinod Koul } 866c46302ecSVinod Koul 86739194128SSrinivas Kandagatla dais[i].capture.channels_min = 1; 86839194128SSrinivas Kandagatla dais[i].capture.channels_max = max_ch; 869c46302ecSVinod Koul dais[i].capture.rates = SNDRV_PCM_RATE_48000; 870c46302ecSVinod Koul dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE; 871c46302ecSVinod Koul } 872c46302ecSVinod Koul 873c46302ecSVinod Koul dais[i].id = SDW_DAI_ID_RANGE_START + i; 874c46302ecSVinod Koul 875c46302ecSVinod Koul if (pcm) 876c46302ecSVinod Koul dais[i].ops = &intel_pcm_dai_ops; 877c46302ecSVinod Koul else 878c46302ecSVinod Koul dais[i].ops = &intel_pdm_dai_ops; 879c46302ecSVinod Koul } 880c46302ecSVinod Koul 881c46302ecSVinod Koul return 0; 882c46302ecSVinod Koul } 883c46302ecSVinod Koul 884c46302ecSVinod Koul static int intel_register_dai(struct sdw_intel *sdw) 885c46302ecSVinod Koul { 886c46302ecSVinod Koul struct sdw_cdns *cdns = &sdw->cdns; 887c46302ecSVinod Koul struct sdw_cdns_streams *stream; 888c46302ecSVinod Koul struct snd_soc_dai_driver *dais; 889c46302ecSVinod Koul int num_dai, ret, off = 0; 890c46302ecSVinod Koul 891c46302ecSVinod Koul /* DAIs are created based on total number of PDIs supported */ 892c46302ecSVinod Koul num_dai = cdns->pcm.num_pdi + cdns->pdm.num_pdi; 893c46302ecSVinod Koul 894c46302ecSVinod Koul dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL); 895c46302ecSVinod Koul if (!dais) 896c46302ecSVinod Koul return -ENOMEM; 897c46302ecSVinod Koul 898c46302ecSVinod Koul /* Create PCM DAIs */ 899c46302ecSVinod Koul stream = &cdns->pcm; 900c46302ecSVinod Koul 9011215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, stream->num_in, 9021215daeeSVinod Koul off, stream->num_ch_in, true); 903c46302ecSVinod Koul if (ret) 904c46302ecSVinod Koul return ret; 905c46302ecSVinod Koul 906c46302ecSVinod Koul off += cdns->pcm.num_in; 9071215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out, 9081215daeeSVinod Koul off, stream->num_ch_out, true); 909c46302ecSVinod Koul if (ret) 910c46302ecSVinod Koul return ret; 911c46302ecSVinod Koul 912c46302ecSVinod Koul off += cdns->pcm.num_out; 9131215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd, 9141215daeeSVinod Koul off, stream->num_ch_bd, true); 915c46302ecSVinod Koul if (ret) 916c46302ecSVinod Koul return ret; 917c46302ecSVinod Koul 918c46302ecSVinod Koul /* Create PDM DAIs */ 919c46302ecSVinod Koul stream = &cdns->pdm; 920c46302ecSVinod Koul off += cdns->pcm.num_bd; 9211215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pdm.num_in, 9221215daeeSVinod Koul off, stream->num_ch_in, false); 923c46302ecSVinod Koul if (ret) 924c46302ecSVinod Koul return ret; 925c46302ecSVinod Koul 926c46302ecSVinod Koul off += cdns->pdm.num_in; 9271215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pdm.num_out, 9281215daeeSVinod Koul off, stream->num_ch_out, false); 929c46302ecSVinod Koul if (ret) 930c46302ecSVinod Koul return ret; 931c46302ecSVinod Koul 932c46302ecSVinod Koul off += cdns->pdm.num_bd; 9331215daeeSVinod Koul ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pdm.num_bd, 9341215daeeSVinod Koul off, stream->num_ch_bd, false); 935c46302ecSVinod Koul if (ret) 936c46302ecSVinod Koul return ret; 937c46302ecSVinod Koul 938c46302ecSVinod Koul return snd_soc_register_component(cdns->dev, &dai_component, 939c46302ecSVinod Koul dais, num_dai); 940c46302ecSVinod Koul } 941c46302ecSVinod Koul 942085f4aceSPierre-Louis Bossart static int sdw_master_read_intel_prop(struct sdw_bus *bus) 943085f4aceSPierre-Louis Bossart { 944085f4aceSPierre-Louis Bossart struct sdw_master_prop *prop = &bus->prop; 945085f4aceSPierre-Louis Bossart struct fwnode_handle *link; 946085f4aceSPierre-Louis Bossart char name[32]; 947085f4aceSPierre-Louis Bossart 948085f4aceSPierre-Louis Bossart /* Find master handle */ 949085f4aceSPierre-Louis Bossart snprintf(name, sizeof(name), 950085f4aceSPierre-Louis Bossart "mipi-sdw-link-%d-subproperties", bus->link_id); 951085f4aceSPierre-Louis Bossart 952085f4aceSPierre-Louis Bossart link = device_get_named_child_node(bus->dev, name); 953085f4aceSPierre-Louis Bossart if (!link) { 954085f4aceSPierre-Louis Bossart dev_err(bus->dev, "Master node %s not found\n", name); 955085f4aceSPierre-Louis Bossart return -EIO; 956085f4aceSPierre-Louis Bossart } 957085f4aceSPierre-Louis Bossart 958085f4aceSPierre-Louis Bossart fwnode_property_read_u32(link, 959085f4aceSPierre-Louis Bossart "intel-sdw-ip-clock", 960085f4aceSPierre-Louis Bossart &prop->mclk_freq); 961085f4aceSPierre-Louis Bossart return 0; 962085f4aceSPierre-Louis Bossart } 963085f4aceSPierre-Louis Bossart 96471bb8a1bSVinod Koul static int intel_prop_read(struct sdw_bus *bus) 96571bb8a1bSVinod Koul { 96671bb8a1bSVinod Koul /* Initialize with default handler to read all DisCo properties */ 96771bb8a1bSVinod Koul sdw_master_read_prop(bus); 96871bb8a1bSVinod Koul 969085f4aceSPierre-Louis Bossart /* read Intel-specific properties */ 970085f4aceSPierre-Louis Bossart sdw_master_read_intel_prop(bus); 971085f4aceSPierre-Louis Bossart 97271bb8a1bSVinod Koul return 0; 97371bb8a1bSVinod Koul } 97471bb8a1bSVinod Koul 975c91605f4SShreyas NC static struct sdw_master_ops sdw_intel_ops = { 976c91605f4SShreyas NC .read_prop = sdw_master_read_prop, 977c91605f4SShreyas NC .xfer_msg = cdns_xfer_msg, 978c91605f4SShreyas NC .xfer_msg_defer = cdns_xfer_msg_defer, 979c91605f4SShreyas NC .reset_page_addr = cdns_reset_page_addr, 98007abeff1SVinod Koul .set_bus_conf = cdns_bus_conf, 98130246e2dSShreyas NC .pre_bank_switch = intel_pre_bank_switch, 98230246e2dSShreyas NC .post_bank_switch = intel_post_bank_switch, 983c91605f4SShreyas NC }; 984c91605f4SShreyas NC 98571bb8a1bSVinod Koul /* 98671bb8a1bSVinod Koul * probe and init 98771bb8a1bSVinod Koul */ 98871bb8a1bSVinod Koul static int intel_probe(struct platform_device *pdev) 98971bb8a1bSVinod Koul { 99037a2d22bSVinod Koul struct sdw_cdns_stream_config config; 99171bb8a1bSVinod Koul struct sdw_intel *sdw; 99271bb8a1bSVinod Koul int ret; 99371bb8a1bSVinod Koul 99471bb8a1bSVinod Koul sdw = devm_kzalloc(&pdev->dev, sizeof(*sdw), GFP_KERNEL); 99571bb8a1bSVinod Koul if (!sdw) 99671bb8a1bSVinod Koul return -ENOMEM; 99771bb8a1bSVinod Koul 99871bb8a1bSVinod Koul sdw->instance = pdev->id; 99971bb8a1bSVinod Koul sdw->res = dev_get_platdata(&pdev->dev); 100071bb8a1bSVinod Koul sdw->cdns.dev = &pdev->dev; 100171bb8a1bSVinod Koul sdw->cdns.registers = sdw->res->registers; 100271bb8a1bSVinod Koul sdw->cdns.instance = sdw->instance; 100371bb8a1bSVinod Koul sdw->cdns.msg_count = 0; 100471bb8a1bSVinod Koul sdw->cdns.bus.dev = &pdev->dev; 100571bb8a1bSVinod Koul sdw->cdns.bus.link_id = pdev->id; 100671bb8a1bSVinod Koul 100771bb8a1bSVinod Koul sdw_cdns_probe(&sdw->cdns); 100871bb8a1bSVinod Koul 100971bb8a1bSVinod Koul /* Set property read ops */ 1010c91605f4SShreyas NC sdw_intel_ops.read_prop = intel_prop_read; 1011c91605f4SShreyas NC sdw->cdns.bus.ops = &sdw_intel_ops; 101271bb8a1bSVinod Koul 101371bb8a1bSVinod Koul platform_set_drvdata(pdev, sdw); 101471bb8a1bSVinod Koul 101571bb8a1bSVinod Koul ret = sdw_add_bus_master(&sdw->cdns.bus); 101671bb8a1bSVinod Koul if (ret) { 101771bb8a1bSVinod Koul dev_err(&pdev->dev, "sdw_add_bus_master fail: %d\n", ret); 101871bb8a1bSVinod Koul goto err_master_reg; 101971bb8a1bSVinod Koul } 102071bb8a1bSVinod Koul 102171bb8a1bSVinod Koul /* Initialize shim and controller */ 102271bb8a1bSVinod Koul intel_link_power_up(sdw); 102371bb8a1bSVinod Koul intel_shim_init(sdw); 102471bb8a1bSVinod Koul 102571bb8a1bSVinod Koul ret = sdw_cdns_init(&sdw->cdns); 102671bb8a1bSVinod Koul if (ret) 102771bb8a1bSVinod Koul goto err_init; 102871bb8a1bSVinod Koul 10297094dc2bSColin Ian King ret = sdw_cdns_enable_interrupt(&sdw->cdns); 103037a2d22bSVinod Koul 103137a2d22bSVinod Koul /* Read the PDI config and initialize cadence PDI */ 103237a2d22bSVinod Koul intel_pdi_init(sdw, &config); 103337a2d22bSVinod Koul ret = sdw_cdns_pdi_init(&sdw->cdns, config); 103471bb8a1bSVinod Koul if (ret) 103571bb8a1bSVinod Koul goto err_init; 103671bb8a1bSVinod Koul 103737a2d22bSVinod Koul intel_pdi_ch_update(sdw); 103837a2d22bSVinod Koul 103971bb8a1bSVinod Koul /* Acquire IRQ */ 1040d542bc9eSPierre-Louis Bossart ret = request_threaded_irq(sdw->res->irq, sdw_cdns_irq, sdw_cdns_thread, 1041d542bc9eSPierre-Louis Bossart IRQF_SHARED, KBUILD_MODNAME, &sdw->cdns); 104271bb8a1bSVinod Koul if (ret < 0) { 104371bb8a1bSVinod Koul dev_err(sdw->cdns.dev, "unable to grab IRQ %d, disabling device\n", 104471bb8a1bSVinod Koul sdw->res->irq); 104571bb8a1bSVinod Koul goto err_init; 104671bb8a1bSVinod Koul } 104771bb8a1bSVinod Koul 1048c46302ecSVinod Koul /* Register DAIs */ 1049c46302ecSVinod Koul ret = intel_register_dai(sdw); 1050c46302ecSVinod Koul if (ret) { 105117ed5befSPierre-Louis Bossart dev_err(sdw->cdns.dev, "DAI registration failed: %d\n", ret); 1052c46302ecSVinod Koul snd_soc_unregister_component(sdw->cdns.dev); 1053c46302ecSVinod Koul goto err_dai; 1054c46302ecSVinod Koul } 1055c46302ecSVinod Koul 1056*79ee6631SPierre-Louis Bossart intel_debugfs_init(sdw); 1057*79ee6631SPierre-Louis Bossart 105871bb8a1bSVinod Koul return 0; 105971bb8a1bSVinod Koul 1060c46302ecSVinod Koul err_dai: 1061c46302ecSVinod Koul free_irq(sdw->res->irq, sdw); 106271bb8a1bSVinod Koul err_init: 106371bb8a1bSVinod Koul sdw_delete_bus_master(&sdw->cdns.bus); 106471bb8a1bSVinod Koul err_master_reg: 106571bb8a1bSVinod Koul return ret; 106671bb8a1bSVinod Koul } 106771bb8a1bSVinod Koul 106871bb8a1bSVinod Koul static int intel_remove(struct platform_device *pdev) 106971bb8a1bSVinod Koul { 107071bb8a1bSVinod Koul struct sdw_intel *sdw; 107171bb8a1bSVinod Koul 107271bb8a1bSVinod Koul sdw = platform_get_drvdata(pdev); 107371bb8a1bSVinod Koul 1074*79ee6631SPierre-Louis Bossart intel_debugfs_exit(sdw); 107571bb8a1bSVinod Koul free_irq(sdw->res->irq, sdw); 1076c46302ecSVinod Koul snd_soc_unregister_component(sdw->cdns.dev); 107771bb8a1bSVinod Koul sdw_delete_bus_master(&sdw->cdns.bus); 107871bb8a1bSVinod Koul 107971bb8a1bSVinod Koul return 0; 108071bb8a1bSVinod Koul } 108171bb8a1bSVinod Koul 108271bb8a1bSVinod Koul static struct platform_driver sdw_intel_drv = { 108371bb8a1bSVinod Koul .probe = intel_probe, 108471bb8a1bSVinod Koul .remove = intel_remove, 108571bb8a1bSVinod Koul .driver = { 108671bb8a1bSVinod Koul .name = "int-sdw", 108771bb8a1bSVinod Koul 108871bb8a1bSVinod Koul }, 108971bb8a1bSVinod Koul }; 109071bb8a1bSVinod Koul 109171bb8a1bSVinod Koul module_platform_driver(sdw_intel_drv); 109271bb8a1bSVinod Koul 109371bb8a1bSVinod Koul MODULE_LICENSE("Dual BSD/GPL"); 109471bb8a1bSVinod Koul MODULE_ALIAS("platform:int-sdw"); 109571bb8a1bSVinod Koul MODULE_DESCRIPTION("Intel Soundwire Master Driver"); 1096