xref: /linux/drivers/soundwire/intel.c (revision f067c9251797ab0ff13cb4c6d5f5a0e6dc2c65d3)
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)
37857a7c42SPierre-Louis Bossart #define SDW_INTEL_MASTER_DISABLE_MULTI_LINK		BIT(3)
38ebf878edSPierre-Louis Bossart 
39ebf878edSPierre-Louis Bossart static int md_flags;
40ebf878edSPierre-Louis Bossart module_param_named(sdw_md_flags, md_flags, int, 0444);
41ebf878edSPierre-Louis Bossart MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)");
42ebf878edSPierre-Louis Bossart 
4371bb8a1bSVinod Koul /* Intel SHIM Registers Definition */
4471bb8a1bSVinod Koul #define SDW_SHIM_LCAP			0x0
4571bb8a1bSVinod Koul #define SDW_SHIM_LCTL			0x4
4671bb8a1bSVinod Koul #define SDW_SHIM_IPPTR			0x8
4771bb8a1bSVinod Koul #define SDW_SHIM_SYNC			0xC
4871bb8a1bSVinod Koul 
497cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLSCAP(x)		(0x010 + 0x60 * (x))
507cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS0CM(x)		(0x012 + 0x60 * (x))
517cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS1CM(x)		(0x014 + 0x60 * (x))
527cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS2CM(x)		(0x016 + 0x60 * (x))
537cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTLS3CM(x)		(0x018 + 0x60 * (x))
547cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSCAP(x)		(0x020 + 0x60 * (x))
5571bb8a1bSVinod Koul 
567cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSYCHM(x, y)		(0x022 + (0x60 * (x)) + (0x2 * (y)))
577cc6e315SPierre-Louis Bossart #define SDW_SHIM_PCMSYCHC(x, y)		(0x042 + (0x60 * (x)) + (0x2 * (y)))
587cc6e315SPierre-Louis Bossart #define SDW_SHIM_PDMSCAP(x)		(0x062 + 0x60 * (x))
597cc6e315SPierre-Louis Bossart #define SDW_SHIM_IOCTL(x)		(0x06C + 0x60 * (x))
607cc6e315SPierre-Louis Bossart #define SDW_SHIM_CTMCTL(x)		(0x06E + 0x60 * (x))
6171bb8a1bSVinod Koul 
6271bb8a1bSVinod Koul #define SDW_SHIM_WAKEEN			0x190
6371bb8a1bSVinod Koul #define SDW_SHIM_WAKESTS		0x192
6471bb8a1bSVinod Koul 
6571bb8a1bSVinod Koul #define SDW_SHIM_LCTL_SPA		BIT(0)
665ee74eb2SPierre-Louis Bossart #define SDW_SHIM_LCTL_SPA_MASK		GENMASK(3, 0)
6771bb8a1bSVinod Koul #define SDW_SHIM_LCTL_CPA		BIT(8)
685ee74eb2SPierre-Louis Bossart #define SDW_SHIM_LCTL_CPA_MASK		GENMASK(11, 8)
6971bb8a1bSVinod Koul 
704a17c441SPierre-Louis Bossart #define SDW_SHIM_SYNC_SYNCPRD_VAL_24	(24000 / SDW_CADENCE_GSYNC_KHZ - 1)
714a17c441SPierre-Louis Bossart #define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4	(38400 / SDW_CADENCE_GSYNC_KHZ - 1)
7271bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCPRD		GENMASK(14, 0)
7371bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCCPU		BIT(15)
7471bb8a1bSVinod Koul #define SDW_SHIM_SYNC_CMDSYNC_MASK	GENMASK(19, 16)
7571bb8a1bSVinod Koul #define SDW_SHIM_SYNC_CMDSYNC		BIT(16)
7671bb8a1bSVinod Koul #define SDW_SHIM_SYNC_SYNCGO		BIT(24)
7771bb8a1bSVinod Koul 
7871bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_ISS		GENMASK(3, 0)
7971bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_OSS		GENMASK(7, 4)
8071bb8a1bSVinod Koul #define SDW_SHIM_PCMSCAP_BSS		GENMASK(12, 8)
8171bb8a1bSVinod Koul 
8271bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_LCHN		GENMASK(3, 0)
8371bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_HCHN		GENMASK(7, 4)
8471bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_STREAM		GENMASK(13, 8)
8571bb8a1bSVinod Koul #define SDW_SHIM_PCMSYCM_DIR		BIT(15)
8671bb8a1bSVinod Koul 
8771bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_ISS		GENMASK(3, 0)
8871bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_OSS		GENMASK(7, 4)
8971bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_BSS		GENMASK(12, 8)
9071bb8a1bSVinod Koul #define SDW_SHIM_PDMSCAP_CPSS		GENMASK(15, 13)
9171bb8a1bSVinod Koul 
9271bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_MIF		BIT(0)
9371bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_CO		BIT(1)
9471bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_COE		BIT(2)
9571bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DO		BIT(3)
9671bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DOE		BIT(4)
9771bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_BKE		BIT(5)
9871bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_WPDD		BIT(6)
9971bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_CIBD		BIT(8)
10071bb8a1bSVinod Koul #define SDW_SHIM_IOCTL_DIBD		BIT(9)
10171bb8a1bSVinod Koul 
10271bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DACTQE		BIT(0)
10371bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DODS		BIT(1)
10471bb8a1bSVinod Koul #define SDW_SHIM_CTMCTL_DOAIS		GENMASK(4, 3)
10571bb8a1bSVinod Koul 
10671bb8a1bSVinod Koul #define SDW_SHIM_WAKEEN_ENABLE		BIT(0)
10771bb8a1bSVinod Koul #define SDW_SHIM_WAKESTS_STATUS		BIT(0)
10871bb8a1bSVinod Koul 
10971bb8a1bSVinod Koul /* Intel ALH Register definitions */
1107cc6e315SPierre-Louis Bossart #define SDW_ALH_STRMZCFG(x)		(0x000 + (0x4 * (x)))
11179ee6631SPierre-Louis Bossart #define SDW_ALH_NUM_STREAMS		64
11271bb8a1bSVinod Koul 
11371bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_DMAT_VAL	0x3
11471bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_DMAT		GENMASK(7, 0)
11571bb8a1bSVinod Koul #define SDW_ALH_STRMZCFG_CHN		GENMASK(19, 16)
11671bb8a1bSVinod Koul 
117c46302ecSVinod Koul enum intel_pdi_type {
118c46302ecSVinod Koul 	INTEL_PDI_IN = 0,
119c46302ecSVinod Koul 	INTEL_PDI_OUT = 1,
120c46302ecSVinod Koul 	INTEL_PDI_BD = 2,
121c46302ecSVinod Koul };
122c46302ecSVinod Koul 
12371bb8a1bSVinod Koul #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
12471bb8a1bSVinod Koul 
12571bb8a1bSVinod Koul /*
12671bb8a1bSVinod Koul  * Read, write helpers for HW registers
12771bb8a1bSVinod Koul  */
12871bb8a1bSVinod Koul static inline int intel_readl(void __iomem *base, int offset)
12971bb8a1bSVinod Koul {
13071bb8a1bSVinod Koul 	return readl(base + offset);
13171bb8a1bSVinod Koul }
13271bb8a1bSVinod Koul 
13371bb8a1bSVinod Koul static inline void intel_writel(void __iomem *base, int offset, int value)
13471bb8a1bSVinod Koul {
13571bb8a1bSVinod Koul 	writel(value, base + offset);
13671bb8a1bSVinod Koul }
13771bb8a1bSVinod Koul 
13871bb8a1bSVinod Koul static inline u16 intel_readw(void __iomem *base, int offset)
13971bb8a1bSVinod Koul {
14071bb8a1bSVinod Koul 	return readw(base + offset);
14171bb8a1bSVinod Koul }
14271bb8a1bSVinod Koul 
14371bb8a1bSVinod Koul static inline void intel_writew(void __iomem *base, int offset, u16 value)
14471bb8a1bSVinod Koul {
14571bb8a1bSVinod Koul 	writew(value, base + offset);
14671bb8a1bSVinod Koul }
14771bb8a1bSVinod Koul 
1487d2845d5SPierre-Louis Bossart static int intel_wait_bit(void __iomem *base, int offset, u32 mask, u32 target)
14971bb8a1bSVinod Koul {
15071bb8a1bSVinod Koul 	int timeout = 10;
15171bb8a1bSVinod Koul 	u32 reg_read;
15271bb8a1bSVinod Koul 
15371bb8a1bSVinod Koul 	do {
15471bb8a1bSVinod Koul 		reg_read = readl(base + offset);
1557d2845d5SPierre-Louis Bossart 		if ((reg_read & mask) == target)
15671bb8a1bSVinod Koul 			return 0;
15771bb8a1bSVinod Koul 
15871bb8a1bSVinod Koul 		timeout--;
1597d2845d5SPierre-Louis Bossart 		usleep_range(50, 100);
16071bb8a1bSVinod Koul 	} while (timeout != 0);
16171bb8a1bSVinod Koul 
16271bb8a1bSVinod Koul 	return -EAGAIN;
16371bb8a1bSVinod Koul }
16471bb8a1bSVinod Koul 
1657d2845d5SPierre-Louis Bossart static int intel_clear_bit(void __iomem *base, int offset, u32 value, u32 mask)
1667d2845d5SPierre-Louis Bossart {
1677d2845d5SPierre-Louis Bossart 	writel(value, base + offset);
1687d2845d5SPierre-Louis Bossart 	return intel_wait_bit(base, offset, mask, 0);
1697d2845d5SPierre-Louis Bossart }
1707d2845d5SPierre-Louis Bossart 
17171bb8a1bSVinod Koul static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)
17271bb8a1bSVinod Koul {
17371bb8a1bSVinod Koul 	writel(value, base + offset);
1747d2845d5SPierre-Louis Bossart 	return intel_wait_bit(base, offset, mask, mask);
17571bb8a1bSVinod Koul }
17671bb8a1bSVinod Koul 
17771bb8a1bSVinod Koul /*
17879ee6631SPierre-Louis Bossart  * debugfs
17979ee6631SPierre-Louis Bossart  */
18079ee6631SPierre-Louis Bossart #ifdef CONFIG_DEBUG_FS
18179ee6631SPierre-Louis Bossart 
18279ee6631SPierre-Louis Bossart #define RD_BUF (2 * PAGE_SIZE)
18379ee6631SPierre-Louis Bossart 
18479ee6631SPierre-Louis Bossart static ssize_t intel_sprintf(void __iomem *mem, bool l,
18579ee6631SPierre-Louis Bossart 			     char *buf, size_t pos, unsigned int reg)
18679ee6631SPierre-Louis Bossart {
18779ee6631SPierre-Louis Bossart 	int value;
18879ee6631SPierre-Louis Bossart 
18979ee6631SPierre-Louis Bossart 	if (l)
19079ee6631SPierre-Louis Bossart 		value = intel_readl(mem, reg);
19179ee6631SPierre-Louis Bossart 	else
19279ee6631SPierre-Louis Bossart 		value = intel_readw(mem, reg);
19379ee6631SPierre-Louis Bossart 
19479ee6631SPierre-Louis Bossart 	return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);
19579ee6631SPierre-Louis Bossart }
19679ee6631SPierre-Louis Bossart 
19779ee6631SPierre-Louis Bossart static int intel_reg_show(struct seq_file *s_file, void *data)
19879ee6631SPierre-Louis Bossart {
19979ee6631SPierre-Louis Bossart 	struct sdw_intel *sdw = s_file->private;
2002523486bSPierre-Louis Bossart 	void __iomem *s = sdw->link_res->shim;
2012523486bSPierre-Louis Bossart 	void __iomem *a = sdw->link_res->alh;
20279ee6631SPierre-Louis Bossart 	char *buf;
20379ee6631SPierre-Louis Bossart 	ssize_t ret;
20479ee6631SPierre-Louis Bossart 	int i, j;
20579ee6631SPierre-Louis Bossart 	unsigned int links, reg;
20679ee6631SPierre-Louis Bossart 
20779ee6631SPierre-Louis Bossart 	buf = kzalloc(RD_BUF, GFP_KERNEL);
20879ee6631SPierre-Louis Bossart 	if (!buf)
20979ee6631SPierre-Louis Bossart 		return -ENOMEM;
21079ee6631SPierre-Louis Bossart 
21179ee6631SPierre-Louis Bossart 	links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0);
21279ee6631SPierre-Louis Bossart 
21379ee6631SPierre-Louis Bossart 	ret = scnprintf(buf, RD_BUF, "Register  Value\n");
21479ee6631SPierre-Louis Bossart 	ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
21579ee6631SPierre-Louis Bossart 
21679ee6631SPierre-Louis Bossart 	for (i = 0; i < links; i++) {
21779ee6631SPierre-Louis Bossart 		reg = SDW_SHIM_LCAP + i * 4;
21879ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, true, buf, ret, reg);
21979ee6631SPierre-Louis Bossart 	}
22079ee6631SPierre-Louis Bossart 
22179ee6631SPierre-Louis Bossart 	for (i = 0; i < links; i++) {
22279ee6631SPierre-Louis Bossart 		ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);
22379ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));
22479ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));
22579ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));
22679ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));
22779ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));
22879ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));
22979ee6631SPierre-Louis Bossart 
23079ee6631SPierre-Louis Bossart 		ret += scnprintf(buf + ret, RD_BUF - ret, "\n PCMSyCH registers\n");
23179ee6631SPierre-Louis Bossart 
23279ee6631SPierre-Louis Bossart 		/*
23379ee6631SPierre-Louis Bossart 		 * the value 10 is the number of PDIs. We will need a
23479ee6631SPierre-Louis Bossart 		 * cleanup to remove hard-coded Intel configurations
23579ee6631SPierre-Louis Bossart 		 * from cadence_master.c
23679ee6631SPierre-Louis Bossart 		 */
23779ee6631SPierre-Louis Bossart 		for (j = 0; j < 10; j++) {
23879ee6631SPierre-Louis Bossart 			ret += intel_sprintf(s, false, buf, ret,
23979ee6631SPierre-Louis Bossart 					SDW_SHIM_PCMSYCHM(i, j));
24079ee6631SPierre-Louis Bossart 			ret += intel_sprintf(s, false, buf, ret,
24179ee6631SPierre-Louis Bossart 					SDW_SHIM_PCMSYCHC(i, j));
24279ee6631SPierre-Louis Bossart 		}
24379ee6631SPierre-Louis Bossart 		ret += scnprintf(buf + ret, RD_BUF - ret, "\n PDMSCAP, IOCTL, CTMCTL\n");
24479ee6631SPierre-Louis Bossart 
24579ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i));
24679ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
24779ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
24879ee6631SPierre-Louis Bossart 	}
24979ee6631SPierre-Louis Bossart 
25079ee6631SPierre-Louis Bossart 	ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n");
25179ee6631SPierre-Louis Bossart 	ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
25279ee6631SPierre-Louis Bossart 	ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
25379ee6631SPierre-Louis Bossart 
25479ee6631SPierre-Louis Bossart 	ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n");
25579ee6631SPierre-Louis Bossart 	for (i = 0; i < SDW_ALH_NUM_STREAMS; i++)
25679ee6631SPierre-Louis Bossart 		ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
25779ee6631SPierre-Louis Bossart 
25879ee6631SPierre-Louis Bossart 	seq_printf(s_file, "%s", buf);
25979ee6631SPierre-Louis Bossart 	kfree(buf);
26079ee6631SPierre-Louis Bossart 
26179ee6631SPierre-Louis Bossart 	return 0;
26279ee6631SPierre-Louis Bossart }
26379ee6631SPierre-Louis Bossart DEFINE_SHOW_ATTRIBUTE(intel_reg);
26479ee6631SPierre-Louis Bossart 
26579ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw)
26679ee6631SPierre-Louis Bossart {
26779ee6631SPierre-Louis Bossart 	struct dentry *root = sdw->cdns.bus.debugfs;
26879ee6631SPierre-Louis Bossart 
26979ee6631SPierre-Louis Bossart 	if (!root)
27079ee6631SPierre-Louis Bossart 		return;
27179ee6631SPierre-Louis Bossart 
27279ee6631SPierre-Louis Bossart 	sdw->debugfs = debugfs_create_dir("intel-sdw", root);
27379ee6631SPierre-Louis Bossart 
27479ee6631SPierre-Louis Bossart 	debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw,
27579ee6631SPierre-Louis Bossart 			    &intel_reg_fops);
27679ee6631SPierre-Louis Bossart 
27779ee6631SPierre-Louis Bossart 	sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs);
27879ee6631SPierre-Louis Bossart }
27979ee6631SPierre-Louis Bossart 
28079ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw)
28179ee6631SPierre-Louis Bossart {
28279ee6631SPierre-Louis Bossart 	debugfs_remove_recursive(sdw->debugfs);
28379ee6631SPierre-Louis Bossart }
28479ee6631SPierre-Louis Bossart #else
28579ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw) {}
28679ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw) {}
28779ee6631SPierre-Louis Bossart #endif /* CONFIG_DEBUG_FS */
28879ee6631SPierre-Louis Bossart 
28979ee6631SPierre-Louis Bossart /*
29071bb8a1bSVinod Koul  * shim ops
29171bb8a1bSVinod Koul  */
29271bb8a1bSVinod Koul 
29371bb8a1bSVinod Koul static int intel_link_power_up(struct sdw_intel *sdw)
29471bb8a1bSVinod Koul {
29571bb8a1bSVinod Koul 	unsigned int link_id = sdw->instance;
2962523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
2974a17c441SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
2984a17c441SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
2994a17c441SPierre-Louis Bossart 	struct sdw_master_prop *prop = &bus->prop;
3005ee74eb2SPierre-Louis Bossart 	u32 spa_mask, cpa_mask;
3015ee74eb2SPierre-Louis Bossart 	u32 link_control;
3024a17c441SPierre-Louis Bossart 	int ret = 0;
3034a17c441SPierre-Louis Bossart 	u32 syncprd;
3044a17c441SPierre-Louis Bossart 	u32 sync_reg;
3054a17c441SPierre-Louis Bossart 
3064a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
3074a17c441SPierre-Louis Bossart 
3084a17c441SPierre-Louis Bossart 	/*
3094a17c441SPierre-Louis Bossart 	 * The hardware relies on an internal counter, typically 4kHz,
3104a17c441SPierre-Louis Bossart 	 * to generate the SoundWire SSP - which defines a 'safe'
3114a17c441SPierre-Louis Bossart 	 * synchronization point between commands and audio transport
3124a17c441SPierre-Louis Bossart 	 * and allows for multi link synchronization. The SYNCPRD value
3134a17c441SPierre-Louis Bossart 	 * is only dependent on the oscillator clock provided to
3144a17c441SPierre-Louis Bossart 	 * the IP, so adjust based on _DSD properties reported in DSDT
3154a17c441SPierre-Louis Bossart 	 * tables. The values reported are based on either 24MHz
3164a17c441SPierre-Louis Bossart 	 * (CNL/CML) or 38.4 MHz (ICL/TGL+).
3174a17c441SPierre-Louis Bossart 	 */
3184a17c441SPierre-Louis Bossart 	if (prop->mclk_freq % 6000000)
3194a17c441SPierre-Louis Bossart 		syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
3204a17c441SPierre-Louis Bossart 	else
3214a17c441SPierre-Louis Bossart 		syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
3224a17c441SPierre-Louis Bossart 
3234a17c441SPierre-Louis Bossart 	if (!*shim_mask) {
3245ee74eb2SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev, "%s: powering up all links\n", __func__);
3255ee74eb2SPierre-Louis Bossart 
3264a17c441SPierre-Louis Bossart 		/* we first need to program the SyncPRD/CPU registers */
3274a17c441SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev,
3284a17c441SPierre-Louis Bossart 			"%s: first link up, programming SYNCPRD\n", __func__);
3294a17c441SPierre-Louis Bossart 
3304a17c441SPierre-Louis Bossart 		/* set SyncPRD period */
3314a17c441SPierre-Louis Bossart 		sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
332*f067c925SVinod Koul 		u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD);
3334a17c441SPierre-Louis Bossart 
3344a17c441SPierre-Louis Bossart 		/* Set SyncCPU bit */
3354a17c441SPierre-Louis Bossart 		sync_reg |= SDW_SHIM_SYNC_SYNCCPU;
3364a17c441SPierre-Louis Bossart 		intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
33771bb8a1bSVinod Koul 
33871bb8a1bSVinod Koul 		/* Link power up sequence */
33971bb8a1bSVinod Koul 		link_control = intel_readl(shim, SDW_SHIM_LCTL);
3405ee74eb2SPierre-Louis Bossart 
3415ee74eb2SPierre-Louis Bossart 		/* only power-up enabled links */
3423b4979caSVinod Koul 		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask);
3433b4979caSVinod Koul 		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
3445ee74eb2SPierre-Louis Bossart 
34571bb8a1bSVinod Koul 		link_control |=  spa_mask;
34671bb8a1bSVinod Koul 
34771bb8a1bSVinod Koul 		ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
3484a17c441SPierre-Louis Bossart 		if (ret < 0) {
3494a17c441SPierre-Louis Bossart 			dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret);
3504a17c441SPierre-Louis Bossart 			goto out;
35171bb8a1bSVinod Koul 		}
35271bb8a1bSVinod Koul 
3534a17c441SPierre-Louis Bossart 		/* SyncCPU will change once link is active */
3544a17c441SPierre-Louis Bossart 		ret = intel_wait_bit(shim, SDW_SHIM_SYNC,
3554a17c441SPierre-Louis Bossart 				     SDW_SHIM_SYNC_SYNCCPU, 0);
3564a17c441SPierre-Louis Bossart 		if (ret < 0) {
3574a17c441SPierre-Louis Bossart 			dev_err(sdw->cdns.dev,
3584a17c441SPierre-Louis Bossart 				"Failed to set SHIM_SYNC: %d\n", ret);
3594a17c441SPierre-Louis Bossart 			goto out;
3604a17c441SPierre-Louis Bossart 		}
3614a17c441SPierre-Louis Bossart 	}
3624a17c441SPierre-Louis Bossart 
3634a17c441SPierre-Louis Bossart 	*shim_mask |= BIT(link_id);
3644a17c441SPierre-Louis Bossart 
3654a17c441SPierre-Louis Bossart 	sdw->cdns.link_up = true;
3664a17c441SPierre-Louis Bossart out:
3674a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
3684a17c441SPierre-Louis Bossart 
3694a17c441SPierre-Louis Bossart 	return ret;
3704a17c441SPierre-Louis Bossart }
3714a17c441SPierre-Louis Bossart 
3724a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */
3734a17c441SPierre-Louis Bossart static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw)
37471bb8a1bSVinod Koul {
3752523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
37671bb8a1bSVinod Koul 	unsigned int link_id = sdw->instance;
3774a17c441SPierre-Louis Bossart 	u16 ioctl;
37871bb8a1bSVinod Koul 
37971bb8a1bSVinod Koul 	/* Switch to MIP from Glue logic */
38071bb8a1bSVinod Koul 	ioctl = intel_readw(shim,  SDW_SHIM_IOCTL(link_id));
38171bb8a1bSVinod Koul 
38271bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_DOE);
38371bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
3844a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
38571bb8a1bSVinod Koul 
38671bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_DO);
38771bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
3884a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
38971bb8a1bSVinod Koul 
39071bb8a1bSVinod Koul 	ioctl |= (SDW_SHIM_IOCTL_MIF);
39171bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
3924a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
39371bb8a1bSVinod Koul 
39471bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_BKE);
39571bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_COE);
39671bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
3974a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
3984a17c441SPierre-Louis Bossart 
3994a17c441SPierre-Louis Bossart 	/* at this point Master IP has full control of the I/Os */
4004a17c441SPierre-Louis Bossart }
4014a17c441SPierre-Louis Bossart 
4024a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */
4034a17c441SPierre-Louis Bossart static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw)
4044a17c441SPierre-Louis Bossart {
4054a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
4064a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
4074a17c441SPierre-Louis Bossart 	u16 ioctl;
4084a17c441SPierre-Louis Bossart 
4094a17c441SPierre-Louis Bossart 	/* Glue logic */
4104a17c441SPierre-Louis Bossart 	ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id));
4114a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_BKE;
4124a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_COE;
4134a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4144a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4154a17c441SPierre-Louis Bossart 
4164a17c441SPierre-Louis Bossart 	ioctl &= ~(SDW_SHIM_IOCTL_MIF);
4174a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4184a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4194a17c441SPierre-Louis Bossart 
4204a17c441SPierre-Louis Bossart 	/* at this point Integration Glue has full control of the I/Os */
4214a17c441SPierre-Louis Bossart }
4224a17c441SPierre-Louis Bossart 
4234a17c441SPierre-Louis Bossart static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop)
4244a17c441SPierre-Louis Bossart {
4254a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
4264a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
4274a17c441SPierre-Louis Bossart 	int ret = 0;
4284a17c441SPierre-Louis Bossart 	u16 ioctl = 0, act = 0;
4294a17c441SPierre-Louis Bossart 
4304a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
4314a17c441SPierre-Louis Bossart 
4324a17c441SPierre-Louis Bossart 	/* Initialize Shim */
4334a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_BKE;
4344a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4354a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4364a17c441SPierre-Louis Bossart 
4374a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_WPDD;
4384a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4394a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4404a17c441SPierre-Louis Bossart 
4414a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_DO;
4424a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4434a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4444a17c441SPierre-Louis Bossart 
4454a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_DOE;
4464a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4474a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4484a17c441SPierre-Louis Bossart 
4494a17c441SPierre-Louis Bossart 	intel_shim_glue_to_master_ip(sdw);
45071bb8a1bSVinod Koul 
451*f067c925SVinod Koul 	u16p_replace_bits(&act, 0x1, SDW_SHIM_CTMCTL_DOAIS);
45271bb8a1bSVinod Koul 	act |= SDW_SHIM_CTMCTL_DACTQE;
45371bb8a1bSVinod Koul 	act |= SDW_SHIM_CTMCTL_DODS;
45471bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act);
4554a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
45671bb8a1bSVinod Koul 
4574a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
45871bb8a1bSVinod Koul 
45971bb8a1bSVinod Koul 	return ret;
46071bb8a1bSVinod Koul }
46171bb8a1bSVinod Koul 
462ab2c9132SRander Wang static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
4634a17c441SPierre-Louis Bossart {
4644a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
4654a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
4664a17c441SPierre-Louis Bossart 	u16 wake_en, wake_sts;
4674a17c441SPierre-Louis Bossart 
4684a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
4694a17c441SPierre-Louis Bossart 	wake_en = intel_readw(shim, SDW_SHIM_WAKEEN);
4704a17c441SPierre-Louis Bossart 
4714a17c441SPierre-Louis Bossart 	if (wake_enable) {
4724a17c441SPierre-Louis Bossart 		/* Enable the wakeup */
4734a17c441SPierre-Louis Bossart 		wake_en |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
4744a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
4754a17c441SPierre-Louis Bossart 	} else {
4764a17c441SPierre-Louis Bossart 		/* Disable the wake up interrupt */
4774a17c441SPierre-Louis Bossart 		wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id);
4784a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
4794a17c441SPierre-Louis Bossart 
4804a17c441SPierre-Louis Bossart 		/* Clear wake status */
4814a17c441SPierre-Louis Bossart 		wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
4824a17c441SPierre-Louis Bossart 		wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
4834a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts);
4844a17c441SPierre-Louis Bossart 	}
4854a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
4864a17c441SPierre-Louis Bossart }
4874a17c441SPierre-Louis Bossart 
4889b3b4b3fSPierre-Louis Bossart static int intel_link_power_down(struct sdw_intel *sdw)
4894a17c441SPierre-Louis Bossart {
4905ee74eb2SPierre-Louis Bossart 	u32 link_control, spa_mask, cpa_mask;
4914a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
4924a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
4934a17c441SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
4944a17c441SPierre-Louis Bossart 	int ret = 0;
4954a17c441SPierre-Louis Bossart 
4964a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
4974a17c441SPierre-Louis Bossart 
4984a17c441SPierre-Louis Bossart 	intel_shim_master_ip_to_glue(sdw);
4994a17c441SPierre-Louis Bossart 
5004a17c441SPierre-Louis Bossart 	if (!(*shim_mask & BIT(link_id)))
5014a17c441SPierre-Louis Bossart 		dev_err(sdw->cdns.dev,
5024a17c441SPierre-Louis Bossart 			"%s: Unbalanced power-up/down calls\n", __func__);
5034a17c441SPierre-Louis Bossart 
5044a17c441SPierre-Louis Bossart 	*shim_mask &= ~BIT(link_id);
5054a17c441SPierre-Louis Bossart 
5065ee74eb2SPierre-Louis Bossart 	if (!*shim_mask) {
5075ee74eb2SPierre-Louis Bossart 
5085ee74eb2SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev, "%s: powering down all links\n", __func__);
5095ee74eb2SPierre-Louis Bossart 
5105ee74eb2SPierre-Louis Bossart 		/* Link power down sequence */
5115ee74eb2SPierre-Louis Bossart 		link_control = intel_readl(shim, SDW_SHIM_LCTL);
5125ee74eb2SPierre-Louis Bossart 
5135ee74eb2SPierre-Louis Bossart 		/* only power-down enabled links */
5143b4979caSVinod Koul 		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, ~sdw->link_res->link_mask);
5153b4979caSVinod Koul 		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
5165ee74eb2SPierre-Louis Bossart 
5175ee74eb2SPierre-Louis Bossart 		link_control &=  spa_mask;
5185ee74eb2SPierre-Louis Bossart 
5195ee74eb2SPierre-Louis Bossart 		ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
5205ee74eb2SPierre-Louis Bossart 	}
5215ee74eb2SPierre-Louis Bossart 
5225ee74eb2SPierre-Louis Bossart 	link_control = intel_readl(shim, SDW_SHIM_LCTL);
5235ee74eb2SPierre-Louis Bossart 
5244a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
5254a17c441SPierre-Louis Bossart 
5265ee74eb2SPierre-Louis Bossart 	if (ret < 0) {
5275ee74eb2SPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__);
5285ee74eb2SPierre-Louis Bossart 
5294a17c441SPierre-Louis Bossart 		return ret;
5305ee74eb2SPierre-Louis Bossart 	}
5314a17c441SPierre-Louis Bossart 
5324a17c441SPierre-Louis Bossart 	sdw->cdns.link_up = false;
5334a17c441SPierre-Louis Bossart 	return 0;
5344a17c441SPierre-Louis Bossart }
5354a17c441SPierre-Louis Bossart 
53602629e45SPierre-Louis Bossart static void intel_shim_sync_arm(struct sdw_intel *sdw)
53702629e45SPierre-Louis Bossart {
53802629e45SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
53902629e45SPierre-Louis Bossart 	u32 sync_reg;
54002629e45SPierre-Louis Bossart 
54102629e45SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
54202629e45SPierre-Louis Bossart 
54302629e45SPierre-Louis Bossart 	/* update SYNC register */
54402629e45SPierre-Louis Bossart 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
54502629e45SPierre-Louis Bossart 	sync_reg |= (SDW_SHIM_SYNC_CMDSYNC << sdw->instance);
54602629e45SPierre-Louis Bossart 	intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
54702629e45SPierre-Louis Bossart 
54802629e45SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
54902629e45SPierre-Louis Bossart }
55002629e45SPierre-Louis Bossart 
551437e3289SPierre-Louis Bossart static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw)
552437e3289SPierre-Louis Bossart {
553437e3289SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
554437e3289SPierre-Louis Bossart 	u32 sync_reg;
555437e3289SPierre-Louis Bossart 	int ret;
556437e3289SPierre-Louis Bossart 
557437e3289SPierre-Louis Bossart 	/* Read SYNC register */
558437e3289SPierre-Louis Bossart 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
559437e3289SPierre-Louis Bossart 
560437e3289SPierre-Louis Bossart 	/*
561437e3289SPierre-Louis Bossart 	 * Set SyncGO bit to synchronously trigger a bank switch for
562437e3289SPierre-Louis Bossart 	 * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all
563437e3289SPierre-Louis Bossart 	 * the Masters.
564437e3289SPierre-Louis Bossart 	 */
565437e3289SPierre-Louis Bossart 	sync_reg |= SDW_SHIM_SYNC_SYNCGO;
566437e3289SPierre-Louis Bossart 
567437e3289SPierre-Louis Bossart 	ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg,
568437e3289SPierre-Louis Bossart 			      SDW_SHIM_SYNC_SYNCGO);
569437e3289SPierre-Louis Bossart 
570437e3289SPierre-Louis Bossart 	if (ret < 0)
571437e3289SPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "SyncGO clear failed: %d\n", ret);
57271bb8a1bSVinod Koul 
57371bb8a1bSVinod Koul 	return ret;
57471bb8a1bSVinod Koul }
57571bb8a1bSVinod Koul 
576857a7c42SPierre-Louis Bossart static int intel_shim_sync_go(struct sdw_intel *sdw)
577857a7c42SPierre-Louis Bossart {
578857a7c42SPierre-Louis Bossart 	int ret;
579857a7c42SPierre-Louis Bossart 
580857a7c42SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
581857a7c42SPierre-Louis Bossart 
582857a7c42SPierre-Louis Bossart 	ret = intel_shim_sync_go_unlocked(sdw);
583857a7c42SPierre-Louis Bossart 
584857a7c42SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
585857a7c42SPierre-Louis Bossart 
586857a7c42SPierre-Louis Bossart 	return ret;
587857a7c42SPierre-Louis Bossart }
588857a7c42SPierre-Louis Bossart 
58937a2d22bSVinod Koul /*
59037a2d22bSVinod Koul  * PDI routines
59137a2d22bSVinod Koul  */
59237a2d22bSVinod Koul static void intel_pdi_init(struct sdw_intel *sdw,
59337a2d22bSVinod Koul 			   struct sdw_cdns_stream_config *config)
59437a2d22bSVinod Koul {
5952523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
59637a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
59737a2d22bSVinod Koul 	int pcm_cap, pdm_cap;
59837a2d22bSVinod Koul 
59937a2d22bSVinod Koul 	/* PCM Stream Capability */
60037a2d22bSVinod Koul 	pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id));
60137a2d22bSVinod Koul 
6023b4979caSVinod Koul 	config->pcm_bd = FIELD_GET(SDW_SHIM_PCMSCAP_BSS, pcm_cap);
6033b4979caSVinod Koul 	config->pcm_in = FIELD_GET(SDW_SHIM_PCMSCAP_ISS, pcm_cap);
6043b4979caSVinod Koul 	config->pcm_out = FIELD_GET(SDW_SHIM_PCMSCAP_OSS, pcm_cap);
60537a2d22bSVinod Koul 
606121f4361SPierre-Louis Bossart 	dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
607121f4361SPierre-Louis Bossart 		config->pcm_bd, config->pcm_in, config->pcm_out);
608121f4361SPierre-Louis Bossart 
60937a2d22bSVinod Koul 	/* PDM Stream Capability */
61037a2d22bSVinod Koul 	pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
61137a2d22bSVinod Koul 
6123b4979caSVinod Koul 	config->pdm_bd = FIELD_GET(SDW_SHIM_PDMSCAP_BSS, pdm_cap);
6133b4979caSVinod Koul 	config->pdm_in = FIELD_GET(SDW_SHIM_PDMSCAP_ISS, pdm_cap);
6143b4979caSVinod Koul 	config->pdm_out = FIELD_GET(SDW_SHIM_PDMSCAP_OSS, pdm_cap);
615121f4361SPierre-Louis Bossart 
616121f4361SPierre-Louis Bossart 	dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n",
617121f4361SPierre-Louis Bossart 		config->pdm_bd, config->pdm_in, config->pdm_out);
61837a2d22bSVinod Koul }
61937a2d22bSVinod Koul 
62037a2d22bSVinod Koul static int
62137a2d22bSVinod Koul intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)
62237a2d22bSVinod Koul {
6232523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
62437a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
62537a2d22bSVinod Koul 	int count;
62637a2d22bSVinod Koul 
62737a2d22bSVinod Koul 	if (pcm) {
62837a2d22bSVinod Koul 		count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
62918046335SPierre-Louis Bossart 
63018046335SPierre-Louis Bossart 		/*
63118046335SPierre-Louis Bossart 		 * WORKAROUND: on all existing Intel controllers, pdi
63218046335SPierre-Louis Bossart 		 * number 2 reports channel count as 1 even though it
63318046335SPierre-Louis Bossart 		 * supports 8 channels. Performing hardcoding for pdi
63418046335SPierre-Louis Bossart 		 * number 2.
63518046335SPierre-Louis Bossart 		 */
63618046335SPierre-Louis Bossart 		if (pdi_num == 2)
63718046335SPierre-Louis Bossart 			count = 7;
63818046335SPierre-Louis Bossart 
63937a2d22bSVinod Koul 	} else {
64037a2d22bSVinod Koul 		count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
6413b4979caSVinod Koul 		count = FIELD_GET(SDW_SHIM_PDMSCAP_CPSS, count);
64237a2d22bSVinod Koul 	}
64337a2d22bSVinod Koul 
64437a2d22bSVinod Koul 	/* zero based values for channel count in register */
64537a2d22bSVinod Koul 	count++;
64637a2d22bSVinod Koul 
64737a2d22bSVinod Koul 	return count;
64837a2d22bSVinod Koul }
64937a2d22bSVinod Koul 
65037a2d22bSVinod Koul static int intel_pdi_get_ch_update(struct sdw_intel *sdw,
65137a2d22bSVinod Koul 				   struct sdw_cdns_pdi *pdi,
65237a2d22bSVinod Koul 				   unsigned int num_pdi,
65337a2d22bSVinod Koul 				   unsigned int *num_ch, bool pcm)
65437a2d22bSVinod Koul {
65537a2d22bSVinod Koul 	int i, ch_count = 0;
65637a2d22bSVinod Koul 
65737a2d22bSVinod Koul 	for (i = 0; i < num_pdi; i++) {
65837a2d22bSVinod Koul 		pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm);
65937a2d22bSVinod Koul 		ch_count += pdi->ch_count;
66037a2d22bSVinod Koul 		pdi++;
66137a2d22bSVinod Koul 	}
66237a2d22bSVinod Koul 
66337a2d22bSVinod Koul 	*num_ch = ch_count;
66437a2d22bSVinod Koul 	return 0;
66537a2d22bSVinod Koul }
66637a2d22bSVinod Koul 
66737a2d22bSVinod Koul static int intel_pdi_stream_ch_update(struct sdw_intel *sdw,
66837a2d22bSVinod Koul 				      struct sdw_cdns_streams *stream, bool pcm)
66937a2d22bSVinod Koul {
67037a2d22bSVinod Koul 	intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
67137a2d22bSVinod Koul 				&stream->num_ch_bd, pcm);
67237a2d22bSVinod Koul 
67337a2d22bSVinod Koul 	intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
67437a2d22bSVinod Koul 				&stream->num_ch_in, pcm);
67537a2d22bSVinod Koul 
67637a2d22bSVinod Koul 	intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
67737a2d22bSVinod Koul 				&stream->num_ch_out, pcm);
67837a2d22bSVinod Koul 
67937a2d22bSVinod Koul 	return 0;
68037a2d22bSVinod Koul }
68137a2d22bSVinod Koul 
68237a2d22bSVinod Koul static int intel_pdi_ch_update(struct sdw_intel *sdw)
68337a2d22bSVinod Koul {
68437a2d22bSVinod Koul 	/* First update PCM streams followed by PDM streams */
68537a2d22bSVinod Koul 	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true);
68637a2d22bSVinod Koul 	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false);
68737a2d22bSVinod Koul 
68837a2d22bSVinod Koul 	return 0;
68937a2d22bSVinod Koul }
69037a2d22bSVinod Koul 
69137a2d22bSVinod Koul static void
69237a2d22bSVinod Koul intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
69337a2d22bSVinod Koul {
6942523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
69537a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
69637a2d22bSVinod Koul 	int pdi_conf = 0;
69737a2d22bSVinod Koul 
698c134f914SPierre-Louis Bossart 	/* the Bulk and PCM streams are not contiguous */
699c134f914SPierre-Louis Bossart 	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
700c134f914SPierre-Louis Bossart 	if (pdi->num >= 2)
701c134f914SPierre-Louis Bossart 		pdi->intel_alh_id += 2;
70237a2d22bSVinod Koul 
70337a2d22bSVinod Koul 	/*
70437a2d22bSVinod Koul 	 * Program stream parameters to stream SHIM register
70537a2d22bSVinod Koul 	 * This is applicable for PCM stream only.
70637a2d22bSVinod Koul 	 */
70737a2d22bSVinod Koul 	if (pdi->type != SDW_STREAM_PCM)
70837a2d22bSVinod Koul 		return;
70937a2d22bSVinod Koul 
71037a2d22bSVinod Koul 	if (pdi->dir == SDW_DATA_DIR_RX)
71137a2d22bSVinod Koul 		pdi_conf |= SDW_SHIM_PCMSYCM_DIR;
71237a2d22bSVinod Koul 	else
71337a2d22bSVinod Koul 		pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR);
71437a2d22bSVinod Koul 
715*f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->intel_alh_id, SDW_SHIM_PCMSYCM_STREAM);
716*f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->l_ch_num, SDW_SHIM_PCMSYCM_LCHN);
717*f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->h_ch_num, SDW_SHIM_PCMSYCM_HCHN);
71837a2d22bSVinod Koul 
71937a2d22bSVinod Koul 	intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf);
72037a2d22bSVinod Koul }
72137a2d22bSVinod Koul 
72237a2d22bSVinod Koul static void
72337a2d22bSVinod Koul intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
72437a2d22bSVinod Koul {
7252523486bSPierre-Louis Bossart 	void __iomem *alh = sdw->link_res->alh;
72637a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
72737a2d22bSVinod Koul 	unsigned int conf;
72837a2d22bSVinod Koul 
729c134f914SPierre-Louis Bossart 	/* the Bulk and PCM streams are not contiguous */
730c134f914SPierre-Louis Bossart 	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
731c134f914SPierre-Louis Bossart 	if (pdi->num >= 2)
732c134f914SPierre-Louis Bossart 		pdi->intel_alh_id += 2;
73337a2d22bSVinod Koul 
73437a2d22bSVinod Koul 	/* Program Stream config ALH register */
73537a2d22bSVinod Koul 	conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
73637a2d22bSVinod Koul 
737*f067c925SVinod Koul 	u32p_replace_bits(&conf, SDW_ALH_STRMZCFG_DMAT_VAL, SDW_ALH_STRMZCFG_DMAT);
738*f067c925SVinod Koul 	u32p_replace_bits(&conf, pdi->ch_count - 1, SDW_ALH_STRMZCFG_CHN);
73937a2d22bSVinod Koul 
74037a2d22bSVinod Koul 	intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);
74137a2d22bSVinod Koul }
74237a2d22bSVinod Koul 
7434b206d34SRander Wang static int intel_params_stream(struct sdw_intel *sdw,
744c46302ecSVinod Koul 			       struct snd_pcm_substream *substream,
745c46302ecSVinod Koul 			       struct snd_soc_dai *dai,
7464b206d34SRander Wang 			       struct snd_pcm_hw_params *hw_params,
7474b206d34SRander Wang 			       int link_id, int alh_stream_id)
748c46302ecSVinod Koul {
7492523486bSPierre-Louis Bossart 	struct sdw_intel_link_res *res = sdw->link_res;
7504b206d34SRander Wang 	struct sdw_intel_stream_params_data params_data;
75105c8afe4SPierre-Louis Bossart 
7524b206d34SRander Wang 	params_data.substream = substream;
7534b206d34SRander Wang 	params_data.dai = dai;
7544b206d34SRander Wang 	params_data.hw_params = hw_params;
7554b206d34SRander Wang 	params_data.link_id = link_id;
7564b206d34SRander Wang 	params_data.alh_stream_id = alh_stream_id;
757c46302ecSVinod Koul 
7584b206d34SRander Wang 	if (res->ops && res->ops->params_stream && res->dev)
7594b206d34SRander Wang 		return res->ops->params_stream(res->dev,
7604b206d34SRander Wang 					       &params_data);
761c46302ecSVinod Koul 	return -EIO;
762c46302ecSVinod Koul }
763c46302ecSVinod Koul 
764eff346f2SPierre-Louis Bossart static int intel_free_stream(struct sdw_intel *sdw,
765eff346f2SPierre-Louis Bossart 			     struct snd_pcm_substream *substream,
766eff346f2SPierre-Louis Bossart 			     struct snd_soc_dai *dai,
767eff346f2SPierre-Louis Bossart 			     int link_id)
768eff346f2SPierre-Louis Bossart {
769eff346f2SPierre-Louis Bossart 	struct sdw_intel_link_res *res = sdw->link_res;
770eff346f2SPierre-Louis Bossart 	struct sdw_intel_stream_free_data free_data;
771eff346f2SPierre-Louis Bossart 
772eff346f2SPierre-Louis Bossart 	free_data.substream = substream;
773eff346f2SPierre-Louis Bossart 	free_data.dai = dai;
774eff346f2SPierre-Louis Bossart 	free_data.link_id = link_id;
775eff346f2SPierre-Louis Bossart 
776eff346f2SPierre-Louis Bossart 	if (res->ops && res->ops->free_stream && res->dev)
777eff346f2SPierre-Louis Bossart 		return res->ops->free_stream(res->dev,
778eff346f2SPierre-Louis Bossart 					     &free_data);
779eff346f2SPierre-Louis Bossart 
780eff346f2SPierre-Louis Bossart 	return 0;
781eff346f2SPierre-Louis Bossart }
782eff346f2SPierre-Louis Bossart 
783c46302ecSVinod Koul /*
78430246e2dSShreyas NC  * bank switch routines
78530246e2dSShreyas NC  */
78630246e2dSShreyas NC 
78730246e2dSShreyas NC static int intel_pre_bank_switch(struct sdw_bus *bus)
78830246e2dSShreyas NC {
78930246e2dSShreyas NC 	struct sdw_cdns *cdns = bus_to_cdns(bus);
79030246e2dSShreyas NC 	struct sdw_intel *sdw = cdns_to_intel(cdns);
79130246e2dSShreyas NC 
79230246e2dSShreyas NC 	/* Write to register only for multi-link */
79330246e2dSShreyas NC 	if (!bus->multi_link)
79430246e2dSShreyas NC 		return 0;
79530246e2dSShreyas NC 
79602629e45SPierre-Louis Bossart 	intel_shim_sync_arm(sdw);
79730246e2dSShreyas NC 
79830246e2dSShreyas NC 	return 0;
79930246e2dSShreyas NC }
80030246e2dSShreyas NC 
80130246e2dSShreyas NC static int intel_post_bank_switch(struct sdw_bus *bus)
80230246e2dSShreyas NC {
80330246e2dSShreyas NC 	struct sdw_cdns *cdns = bus_to_cdns(bus);
80430246e2dSShreyas NC 	struct sdw_intel *sdw = cdns_to_intel(cdns);
8052523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
80630246e2dSShreyas NC 	int sync_reg, ret;
80730246e2dSShreyas NC 
80830246e2dSShreyas NC 	/* Write to register only for multi-link */
80930246e2dSShreyas NC 	if (!bus->multi_link)
81030246e2dSShreyas NC 		return 0;
81130246e2dSShreyas NC 
8124a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
8134a17c441SPierre-Louis Bossart 
81430246e2dSShreyas NC 	/* Read SYNC register */
81530246e2dSShreyas NC 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
81630246e2dSShreyas NC 
81730246e2dSShreyas NC 	/*
81830246e2dSShreyas NC 	 * post_bank_switch() ops is called from the bus in loop for
81930246e2dSShreyas NC 	 * all the Masters in the steam with the expectation that
82030246e2dSShreyas NC 	 * we trigger the bankswitch for the only first Master in the list
82130246e2dSShreyas NC 	 * and do nothing for the other Masters
82230246e2dSShreyas NC 	 *
82330246e2dSShreyas NC 	 * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.
82430246e2dSShreyas NC 	 */
8254a17c441SPierre-Louis Bossart 	if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) {
8264a17c441SPierre-Louis Bossart 		ret = 0;
8274a17c441SPierre-Louis Bossart 		goto unlock;
8284a17c441SPierre-Louis Bossart 	}
82930246e2dSShreyas NC 
830437e3289SPierre-Louis Bossart 	ret = intel_shim_sync_go_unlocked(sdw);
8314a17c441SPierre-Louis Bossart unlock:
8324a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
83330246e2dSShreyas NC 
83430246e2dSShreyas NC 	if (ret < 0)
83517ed5befSPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret);
83630246e2dSShreyas NC 
83730246e2dSShreyas NC 	return ret;
83830246e2dSShreyas NC }
83930246e2dSShreyas NC 
84030246e2dSShreyas NC /*
841c46302ecSVinod Koul  * DAI routines
842c46302ecSVinod Koul  */
843c46302ecSVinod Koul 
8445e7484d0SRander Wang static int intel_startup(struct snd_pcm_substream *substream,
8455e7484d0SRander Wang 			 struct snd_soc_dai *dai)
8465e7484d0SRander Wang {
847ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
848ebf878edSPierre-Louis Bossart 	int ret;
849ebf878edSPierre-Louis Bossart 
850ebf878edSPierre-Louis Bossart 	ret = pm_runtime_get_sync(cdns->dev);
851ebf878edSPierre-Louis Bossart 	if (ret < 0 && ret != -EACCES) {
852ebf878edSPierre-Louis Bossart 		dev_err_ratelimited(cdns->dev,
853ebf878edSPierre-Louis Bossart 				    "pm_runtime_get_sync failed in %s, ret %d\n",
854ebf878edSPierre-Louis Bossart 				    __func__, ret);
855ebf878edSPierre-Louis Bossart 		pm_runtime_put_noidle(cdns->dev);
856ebf878edSPierre-Louis Bossart 		return ret;
857ebf878edSPierre-Louis Bossart 	}
858ff16d1e5SPierre-Louis Bossart 	return 0;
8595e7484d0SRander Wang }
8605e7484d0SRander Wang 
861c46302ecSVinod Koul static int intel_hw_params(struct snd_pcm_substream *substream,
862c46302ecSVinod Koul 			   struct snd_pcm_hw_params *params,
863c46302ecSVinod Koul 			   struct snd_soc_dai *dai)
864c46302ecSVinod Koul {
865c46302ecSVinod Koul 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
866c46302ecSVinod Koul 	struct sdw_intel *sdw = cdns_to_intel(cdns);
867c46302ecSVinod Koul 	struct sdw_cdns_dma_data *dma;
86857a34790SPierre-Louis Bossart 	struct sdw_cdns_pdi *pdi;
869c46302ecSVinod Koul 	struct sdw_stream_config sconfig;
870c46302ecSVinod Koul 	struct sdw_port_config *pconfig;
87157a34790SPierre-Louis Bossart 	int ch, dir;
87257a34790SPierre-Louis Bossart 	int ret;
873c46302ecSVinod Koul 	bool pcm = true;
874c46302ecSVinod Koul 
875c46302ecSVinod Koul 	dma = snd_soc_dai_get_dma_data(dai, substream);
876c46302ecSVinod Koul 	if (!dma)
877c46302ecSVinod Koul 		return -EIO;
878c46302ecSVinod Koul 
879c46302ecSVinod Koul 	ch = params_channels(params);
880c46302ecSVinod Koul 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
881c46302ecSVinod Koul 		dir = SDW_DATA_DIR_RX;
882c46302ecSVinod Koul 	else
883c46302ecSVinod Koul 		dir = SDW_DATA_DIR_TX;
884c46302ecSVinod Koul 
88557a34790SPierre-Louis Bossart 	if (dma->stream_type == SDW_STREAM_PDM)
886c46302ecSVinod Koul 		pcm = false;
887c46302ecSVinod Koul 
88857a34790SPierre-Louis Bossart 	if (pcm)
8891b53385eSBard Liao 		pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
89057a34790SPierre-Louis Bossart 	else
8911b53385eSBard Liao 		pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id);
892c46302ecSVinod Koul 
89357a34790SPierre-Louis Bossart 	if (!pdi) {
894c46302ecSVinod Koul 		ret = -EINVAL;
89557a34790SPierre-Louis Bossart 		goto error;
896c46302ecSVinod Koul 	}
89757a34790SPierre-Louis Bossart 
89857a34790SPierre-Louis Bossart 	/* do run-time configurations for SHIM, ALH and PDI/PORT */
89957a34790SPierre-Louis Bossart 	intel_pdi_shim_configure(sdw, pdi);
90057a34790SPierre-Louis Bossart 	intel_pdi_alh_configure(sdw, pdi);
90157a34790SPierre-Louis Bossart 	sdw_cdns_config_stream(cdns, ch, dir, pdi);
90257a34790SPierre-Louis Bossart 
903a5a0239cSBard Liao 	/* store pdi and hw_params, may be needed in prepare step */
904a5a0239cSBard Liao 	dma->suspended = false;
905a5a0239cSBard Liao 	dma->pdi = pdi;
906a5a0239cSBard Liao 	dma->hw_params = params;
907c46302ecSVinod Koul 
908c46302ecSVinod Koul 	/* Inform DSP about PDI stream number */
9094b206d34SRander Wang 	ret = intel_params_stream(sdw, substream, dai, params,
9104b206d34SRander Wang 				  sdw->instance,
91157a34790SPierre-Louis Bossart 				  pdi->intel_alh_id);
912c46302ecSVinod Koul 	if (ret)
91357a34790SPierre-Louis Bossart 		goto error;
914c46302ecSVinod Koul 
915c46302ecSVinod Koul 	sconfig.direction = dir;
916c46302ecSVinod Koul 	sconfig.ch_count = ch;
917c46302ecSVinod Koul 	sconfig.frame_rate = params_rate(params);
918c46302ecSVinod Koul 	sconfig.type = dma->stream_type;
919c46302ecSVinod Koul 
920c46302ecSVinod Koul 	if (dma->stream_type == SDW_STREAM_PDM) {
921c46302ecSVinod Koul 		sconfig.frame_rate *= 50;
922c46302ecSVinod Koul 		sconfig.bps = 1;
923c46302ecSVinod Koul 	} else {
924c46302ecSVinod Koul 		sconfig.bps = snd_pcm_format_width(params_format(params));
925c46302ecSVinod Koul 	}
926c46302ecSVinod Koul 
927c46302ecSVinod Koul 	/* Port configuration */
92857a34790SPierre-Louis Bossart 	pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL);
929c46302ecSVinod Koul 	if (!pconfig) {
930c46302ecSVinod Koul 		ret =  -ENOMEM;
93157a34790SPierre-Louis Bossart 		goto error;
932c46302ecSVinod Koul 	}
933c46302ecSVinod Koul 
93457a34790SPierre-Louis Bossart 	pconfig->num = pdi->num;
93557a34790SPierre-Louis Bossart 	pconfig->ch_mask = (1 << ch) - 1;
936c46302ecSVinod Koul 
937c46302ecSVinod Koul 	ret = sdw_stream_add_master(&cdns->bus, &sconfig,
93857a34790SPierre-Louis Bossart 				    pconfig, 1, dma->stream);
93957a34790SPierre-Louis Bossart 	if (ret)
94017ed5befSPierre-Louis Bossart 		dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
941c46302ecSVinod Koul 
942c46302ecSVinod Koul 	kfree(pconfig);
94357a34790SPierre-Louis Bossart error:
944c46302ecSVinod Koul 	return ret;
945c46302ecSVinod Koul }
946c46302ecSVinod Koul 
94727b198f4SRander Wang static int intel_prepare(struct snd_pcm_substream *substream,
94827b198f4SRander Wang 			 struct snd_soc_dai *dai)
94927b198f4SRander Wang {
950a5a0239cSBard Liao 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
951a5a0239cSBard Liao 	struct sdw_intel *sdw = cdns_to_intel(cdns);
95227b198f4SRander Wang 	struct sdw_cdns_dma_data *dma;
953a5a0239cSBard Liao 	int ch, dir;
954244eb888SPierre-Louis Bossart 	int ret = 0;
95527b198f4SRander Wang 
95627b198f4SRander Wang 	dma = snd_soc_dai_get_dma_data(dai, substream);
95727b198f4SRander Wang 	if (!dma) {
95827b198f4SRander Wang 		dev_err(dai->dev, "failed to get dma data in %s",
95927b198f4SRander Wang 			__func__);
96027b198f4SRander Wang 		return -EIO;
96127b198f4SRander Wang 	}
96227b198f4SRander Wang 
963a5a0239cSBard Liao 	if (dma->suspended) {
964a5a0239cSBard Liao 		dma->suspended = false;
965a5a0239cSBard Liao 
966a5a0239cSBard Liao 		/*
967a5a0239cSBard Liao 		 * .prepare() is called after system resume, where we
968a5a0239cSBard Liao 		 * need to reinitialize the SHIM/ALH/Cadence IP.
969a5a0239cSBard Liao 		 * .prepare() is also called to deal with underflows,
970a5a0239cSBard Liao 		 * but in those cases we cannot touch ALH/SHIM
971a5a0239cSBard Liao 		 * registers
972a5a0239cSBard Liao 		 */
973a5a0239cSBard Liao 
974a5a0239cSBard Liao 		/* configure stream */
975a5a0239cSBard Liao 		ch = params_channels(dma->hw_params);
976a5a0239cSBard Liao 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
977a5a0239cSBard Liao 			dir = SDW_DATA_DIR_RX;
978a5a0239cSBard Liao 		else
979a5a0239cSBard Liao 			dir = SDW_DATA_DIR_TX;
980a5a0239cSBard Liao 
981a5a0239cSBard Liao 		intel_pdi_shim_configure(sdw, dma->pdi);
982a5a0239cSBard Liao 		intel_pdi_alh_configure(sdw, dma->pdi);
983a5a0239cSBard Liao 		sdw_cdns_config_stream(cdns, ch, dir, dma->pdi);
984a5a0239cSBard Liao 
985a5a0239cSBard Liao 		/* Inform DSP about PDI stream number */
986a5a0239cSBard Liao 		ret = intel_params_stream(sdw, substream, dai,
987a5a0239cSBard Liao 					  dma->hw_params,
988a5a0239cSBard Liao 					  sdw->instance,
989a5a0239cSBard Liao 					  dma->pdi->intel_alh_id);
990a5a0239cSBard Liao 	}
991a5a0239cSBard Liao 
992a5a0239cSBard Liao 	return ret;
99327b198f4SRander Wang }
99427b198f4SRander Wang 
995c46302ecSVinod Koul static int
996c46302ecSVinod Koul intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
997c46302ecSVinod Koul {
998c46302ecSVinod Koul 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
999eff346f2SPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
1000c46302ecSVinod Koul 	struct sdw_cdns_dma_data *dma;
1001c46302ecSVinod Koul 	int ret;
1002c46302ecSVinod Koul 
1003c46302ecSVinod Koul 	dma = snd_soc_dai_get_dma_data(dai, substream);
1004c46302ecSVinod Koul 	if (!dma)
1005c46302ecSVinod Koul 		return -EIO;
1006c46302ecSVinod Koul 
1007244eb888SPierre-Louis Bossart 	/*
1008244eb888SPierre-Louis Bossart 	 * The sdw stream state will transition to RELEASED when stream->
1009244eb888SPierre-Louis Bossart 	 * master_list is empty. So the stream state will transition to
1010244eb888SPierre-Louis Bossart 	 * DEPREPARED for the first cpu-dai and to RELEASED for the last
1011244eb888SPierre-Louis Bossart 	 * cpu-dai.
1012244eb888SPierre-Louis Bossart 	 */
1013c46302ecSVinod Koul 	ret = sdw_stream_remove_master(&cdns->bus, dma->stream);
1014eff346f2SPierre-Louis Bossart 	if (ret < 0) {
101517ed5befSPierre-Louis Bossart 		dev_err(dai->dev, "remove master from stream %s failed: %d\n",
1016c46302ecSVinod Koul 			dma->stream->name, ret);
1017c46302ecSVinod Koul 		return ret;
1018c46302ecSVinod Koul 	}
1019c46302ecSVinod Koul 
1020eff346f2SPierre-Louis Bossart 	ret = intel_free_stream(sdw, substream, dai, sdw->instance);
1021eff346f2SPierre-Louis Bossart 	if (ret < 0) {
1022eff346f2SPierre-Louis Bossart 		dev_err(dai->dev, "intel_free_stream: failed %d", ret);
1023eff346f2SPierre-Louis Bossart 		return ret;
1024eff346f2SPierre-Louis Bossart 	}
1025eff346f2SPierre-Louis Bossart 
1026a5a0239cSBard Liao 	dma->hw_params = NULL;
1027a5a0239cSBard Liao 	dma->pdi = NULL;
1028a5a0239cSBard Liao 
1029eff346f2SPierre-Louis Bossart 	return 0;
1030eff346f2SPierre-Louis Bossart }
1031eff346f2SPierre-Louis Bossart 
1032183c7687SPierre-Louis Bossart static void intel_shutdown(struct snd_pcm_substream *substream,
1033183c7687SPierre-Louis Bossart 			   struct snd_soc_dai *dai)
1034183c7687SPierre-Louis Bossart {
1035ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
1036183c7687SPierre-Louis Bossart 
1037ebf878edSPierre-Louis Bossart 	pm_runtime_mark_last_busy(cdns->dev);
1038ebf878edSPierre-Louis Bossart 	pm_runtime_put_autosuspend(cdns->dev);
1039183c7687SPierre-Louis Bossart }
1040183c7687SPierre-Louis Bossart 
1041a5a0239cSBard Liao static int intel_component_dais_suspend(struct snd_soc_component *component)
1042a5a0239cSBard Liao {
1043a5a0239cSBard Liao 	struct sdw_cdns_dma_data *dma;
1044a5a0239cSBard Liao 	struct snd_soc_dai *dai;
1045a5a0239cSBard Liao 
1046a5a0239cSBard Liao 	for_each_component_dais(component, dai) {
1047a5a0239cSBard Liao 		/*
1048a5a0239cSBard Liao 		 * we don't have a .suspend dai_ops, and we don't have access
1049a5a0239cSBard Liao 		 * to the substream, so let's mark both capture and playback
1050a5a0239cSBard Liao 		 * DMA contexts as suspended
1051a5a0239cSBard Liao 		 */
1052a5a0239cSBard Liao 		dma = dai->playback_dma_data;
1053a5a0239cSBard Liao 		if (dma)
1054a5a0239cSBard Liao 			dma->suspended = true;
1055a5a0239cSBard Liao 
1056a5a0239cSBard Liao 		dma = dai->capture_dma_data;
1057a5a0239cSBard Liao 		if (dma)
1058a5a0239cSBard Liao 			dma->suspended = true;
1059a5a0239cSBard Liao 	}
1060a5a0239cSBard Liao 
1061a5a0239cSBard Liao 	return 0;
1062a5a0239cSBard Liao }
1063a5a0239cSBard Liao 
1064c46302ecSVinod Koul static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
1065c46302ecSVinod Koul 				    void *stream, int direction)
1066c46302ecSVinod Koul {
1067c46302ecSVinod Koul 	return cdns_set_sdw_stream(dai, stream, true, direction);
1068c46302ecSVinod Koul }
1069c46302ecSVinod Koul 
1070c46302ecSVinod Koul static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai,
1071c46302ecSVinod Koul 				    void *stream, int direction)
1072c46302ecSVinod Koul {
1073c46302ecSVinod Koul 	return cdns_set_sdw_stream(dai, stream, false, direction);
1074c46302ecSVinod Koul }
1075c46302ecSVinod Koul 
107609553140SPierre-Louis Bossart static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
107709553140SPierre-Louis Bossart 				  int direction)
107809553140SPierre-Louis Bossart {
107909553140SPierre-Louis Bossart 	struct sdw_cdns_dma_data *dma;
108009553140SPierre-Louis Bossart 
108109553140SPierre-Louis Bossart 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
108209553140SPierre-Louis Bossart 		dma = dai->playback_dma_data;
108309553140SPierre-Louis Bossart 	else
108409553140SPierre-Louis Bossart 		dma = dai->capture_dma_data;
108509553140SPierre-Louis Bossart 
108609553140SPierre-Louis Bossart 	if (!dma)
108706dcb4e4SPierre-Louis Bossart 		return ERR_PTR(-EINVAL);
108809553140SPierre-Louis Bossart 
108909553140SPierre-Louis Bossart 	return dma->stream;
109009553140SPierre-Louis Bossart }
109109553140SPierre-Louis Bossart 
1092b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
10935e7484d0SRander Wang 	.startup = intel_startup,
1094c46302ecSVinod Koul 	.hw_params = intel_hw_params,
109527b198f4SRander Wang 	.prepare = intel_prepare,
1096c46302ecSVinod Koul 	.hw_free = intel_hw_free,
1097183c7687SPierre-Louis Bossart 	.shutdown = intel_shutdown,
1098c46302ecSVinod Koul 	.set_sdw_stream = intel_pcm_set_sdw_stream,
109909553140SPierre-Louis Bossart 	.get_sdw_stream = intel_get_sdw_stream,
1100c46302ecSVinod Koul };
1101c46302ecSVinod Koul 
1102b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pdm_dai_ops = {
11035e7484d0SRander Wang 	.startup = intel_startup,
1104c46302ecSVinod Koul 	.hw_params = intel_hw_params,
110527b198f4SRander Wang 	.prepare = intel_prepare,
1106c46302ecSVinod Koul 	.hw_free = intel_hw_free,
1107183c7687SPierre-Louis Bossart 	.shutdown = intel_shutdown,
1108c46302ecSVinod Koul 	.set_sdw_stream = intel_pdm_set_sdw_stream,
110909553140SPierre-Louis Bossart 	.get_sdw_stream = intel_get_sdw_stream,
1110c46302ecSVinod Koul };
1111c46302ecSVinod Koul 
1112c46302ecSVinod Koul static const struct snd_soc_component_driver dai_component = {
1113c46302ecSVinod Koul 	.name           = "soundwire",
1114a5a0239cSBard Liao 	.suspend	= intel_component_dais_suspend
1115c46302ecSVinod Koul };
1116c46302ecSVinod Koul 
1117c46302ecSVinod Koul static int intel_create_dai(struct sdw_cdns *cdns,
1118c46302ecSVinod Koul 			    struct snd_soc_dai_driver *dais,
1119c46302ecSVinod Koul 			    enum intel_pdi_type type,
1120c46302ecSVinod Koul 			    u32 num, u32 off, u32 max_ch, bool pcm)
1121c46302ecSVinod Koul {
1122c46302ecSVinod Koul 	int i;
1123c46302ecSVinod Koul 
1124c46302ecSVinod Koul 	if (num == 0)
1125c46302ecSVinod Koul 		return 0;
1126c46302ecSVinod Koul 
1127c46302ecSVinod Koul 	 /* TODO: Read supported rates/formats from hardware */
1128c46302ecSVinod Koul 	for (i = off; i < (off + num); i++) {
1129bf6d6e68SPierre-Louis Bossart 		dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
1130bf6d6e68SPierre-Louis Bossart 					      "SDW%d Pin%d",
1131c46302ecSVinod Koul 					      cdns->instance, i);
1132c46302ecSVinod Koul 		if (!dais[i].name)
1133c46302ecSVinod Koul 			return -ENOMEM;
1134c46302ecSVinod Koul 
1135c46302ecSVinod Koul 		if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
1136c46302ecSVinod Koul 			dais[i].playback.channels_min = 1;
1137c46302ecSVinod Koul 			dais[i].playback.channels_max = max_ch;
1138c46302ecSVinod Koul 			dais[i].playback.rates = SNDRV_PCM_RATE_48000;
1139c46302ecSVinod Koul 			dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
1140c46302ecSVinod Koul 		}
1141c46302ecSVinod Koul 
1142c46302ecSVinod Koul 		if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
114339194128SSrinivas Kandagatla 			dais[i].capture.channels_min = 1;
114439194128SSrinivas Kandagatla 			dais[i].capture.channels_max = max_ch;
1145c46302ecSVinod Koul 			dais[i].capture.rates = SNDRV_PCM_RATE_48000;
1146c46302ecSVinod Koul 			dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
1147c46302ecSVinod Koul 		}
1148c46302ecSVinod Koul 
1149c46302ecSVinod Koul 		if (pcm)
1150c46302ecSVinod Koul 			dais[i].ops = &intel_pcm_dai_ops;
1151c46302ecSVinod Koul 		else
1152c46302ecSVinod Koul 			dais[i].ops = &intel_pdm_dai_ops;
1153c46302ecSVinod Koul 	}
1154c46302ecSVinod Koul 
1155c46302ecSVinod Koul 	return 0;
1156c46302ecSVinod Koul }
1157c46302ecSVinod Koul 
1158c46302ecSVinod Koul static int intel_register_dai(struct sdw_intel *sdw)
1159c46302ecSVinod Koul {
1160c46302ecSVinod Koul 	struct sdw_cdns *cdns = &sdw->cdns;
1161c46302ecSVinod Koul 	struct sdw_cdns_streams *stream;
1162c46302ecSVinod Koul 	struct snd_soc_dai_driver *dais;
1163c46302ecSVinod Koul 	int num_dai, ret, off = 0;
1164c46302ecSVinod Koul 
1165c46302ecSVinod Koul 	/* DAIs are created based on total number of PDIs supported */
1166c46302ecSVinod Koul 	num_dai = cdns->pcm.num_pdi + cdns->pdm.num_pdi;
1167c46302ecSVinod Koul 
1168c46302ecSVinod Koul 	dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
1169c46302ecSVinod Koul 	if (!dais)
1170c46302ecSVinod Koul 		return -ENOMEM;
1171c46302ecSVinod Koul 
1172c46302ecSVinod Koul 	/* Create PCM DAIs */
1173c46302ecSVinod Koul 	stream = &cdns->pcm;
1174c46302ecSVinod Koul 
1175cf924962SBard Liao 	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
11761215daeeSVinod Koul 			       off, stream->num_ch_in, true);
1177c46302ecSVinod Koul 	if (ret)
1178c46302ecSVinod Koul 		return ret;
1179c46302ecSVinod Koul 
1180c46302ecSVinod Koul 	off += cdns->pcm.num_in;
11811215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
11821215daeeSVinod Koul 			       off, stream->num_ch_out, true);
1183c46302ecSVinod Koul 	if (ret)
1184c46302ecSVinod Koul 		return ret;
1185c46302ecSVinod Koul 
1186c46302ecSVinod Koul 	off += cdns->pcm.num_out;
11871215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
11881215daeeSVinod Koul 			       off, stream->num_ch_bd, true);
1189c46302ecSVinod Koul 	if (ret)
1190c46302ecSVinod Koul 		return ret;
1191c46302ecSVinod Koul 
1192c46302ecSVinod Koul 	/* Create PDM DAIs */
1193c46302ecSVinod Koul 	stream = &cdns->pdm;
1194c46302ecSVinod Koul 	off += cdns->pcm.num_bd;
11951215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pdm.num_in,
11961215daeeSVinod Koul 			       off, stream->num_ch_in, false);
1197c46302ecSVinod Koul 	if (ret)
1198c46302ecSVinod Koul 		return ret;
1199c46302ecSVinod Koul 
1200c46302ecSVinod Koul 	off += cdns->pdm.num_in;
12011215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pdm.num_out,
12021215daeeSVinod Koul 			       off, stream->num_ch_out, false);
1203c46302ecSVinod Koul 	if (ret)
1204c46302ecSVinod Koul 		return ret;
1205c46302ecSVinod Koul 
1206cf924962SBard Liao 	off += cdns->pdm.num_out;
12071215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pdm.num_bd,
12081215daeeSVinod Koul 			       off, stream->num_ch_bd, false);
1209c46302ecSVinod Koul 	if (ret)
1210c46302ecSVinod Koul 		return ret;
1211c46302ecSVinod Koul 
1212c46302ecSVinod Koul 	return snd_soc_register_component(cdns->dev, &dai_component,
1213c46302ecSVinod Koul 					  dais, num_dai);
1214c46302ecSVinod Koul }
1215c46302ecSVinod Koul 
1216085f4aceSPierre-Louis Bossart static int sdw_master_read_intel_prop(struct sdw_bus *bus)
1217085f4aceSPierre-Louis Bossart {
1218085f4aceSPierre-Louis Bossart 	struct sdw_master_prop *prop = &bus->prop;
1219085f4aceSPierre-Louis Bossart 	struct fwnode_handle *link;
1220085f4aceSPierre-Louis Bossart 	char name[32];
1221395713d8SPierre-Louis Bossart 	u32 quirk_mask;
1222085f4aceSPierre-Louis Bossart 
1223085f4aceSPierre-Louis Bossart 	/* Find master handle */
1224085f4aceSPierre-Louis Bossart 	snprintf(name, sizeof(name),
1225085f4aceSPierre-Louis Bossart 		 "mipi-sdw-link-%d-subproperties", bus->link_id);
1226085f4aceSPierre-Louis Bossart 
1227085f4aceSPierre-Louis Bossart 	link = device_get_named_child_node(bus->dev, name);
1228085f4aceSPierre-Louis Bossart 	if (!link) {
1229085f4aceSPierre-Louis Bossart 		dev_err(bus->dev, "Master node %s not found\n", name);
1230085f4aceSPierre-Louis Bossart 		return -EIO;
1231085f4aceSPierre-Louis Bossart 	}
1232085f4aceSPierre-Louis Bossart 
1233085f4aceSPierre-Louis Bossart 	fwnode_property_read_u32(link,
1234085f4aceSPierre-Louis Bossart 				 "intel-sdw-ip-clock",
1235085f4aceSPierre-Louis Bossart 				 &prop->mclk_freq);
1236395713d8SPierre-Louis Bossart 
1237a19efb52SBard Liao 	/* the values reported by BIOS are the 2x clock, not the bus clock */
1238a19efb52SBard Liao 	prop->mclk_freq /= 2;
1239a19efb52SBard Liao 
1240395713d8SPierre-Louis Bossart 	fwnode_property_read_u32(link,
1241395713d8SPierre-Louis Bossart 				 "intel-quirk-mask",
1242395713d8SPierre-Louis Bossart 				 &quirk_mask);
1243395713d8SPierre-Louis Bossart 
1244395713d8SPierre-Louis Bossart 	if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
1245395713d8SPierre-Louis Bossart 		prop->hw_disabled = true;
1246395713d8SPierre-Louis Bossart 
1247085f4aceSPierre-Louis Bossart 	return 0;
1248085f4aceSPierre-Louis Bossart }
1249085f4aceSPierre-Louis Bossart 
125071bb8a1bSVinod Koul static int intel_prop_read(struct sdw_bus *bus)
125171bb8a1bSVinod Koul {
125271bb8a1bSVinod Koul 	/* Initialize with default handler to read all DisCo properties */
125371bb8a1bSVinod Koul 	sdw_master_read_prop(bus);
125471bb8a1bSVinod Koul 
1255085f4aceSPierre-Louis Bossart 	/* read Intel-specific properties */
1256085f4aceSPierre-Louis Bossart 	sdw_master_read_intel_prop(bus);
1257085f4aceSPierre-Louis Bossart 
125871bb8a1bSVinod Koul 	return 0;
125971bb8a1bSVinod Koul }
126071bb8a1bSVinod Koul 
1261c91605f4SShreyas NC static struct sdw_master_ops sdw_intel_ops = {
1262c91605f4SShreyas NC 	.read_prop = sdw_master_read_prop,
1263c91605f4SShreyas NC 	.xfer_msg = cdns_xfer_msg,
1264c91605f4SShreyas NC 	.xfer_msg_defer = cdns_xfer_msg_defer,
1265c91605f4SShreyas NC 	.reset_page_addr = cdns_reset_page_addr,
126607abeff1SVinod Koul 	.set_bus_conf = cdns_bus_conf,
126730246e2dSShreyas NC 	.pre_bank_switch = intel_pre_bank_switch,
126830246e2dSShreyas NC 	.post_bank_switch = intel_post_bank_switch,
1269c91605f4SShreyas NC };
1270c91605f4SShreyas NC 
1271dfbe642dSPierre-Louis Bossart static int intel_init(struct sdw_intel *sdw)
1272dfbe642dSPierre-Louis Bossart {
12734a17c441SPierre-Louis Bossart 	bool clock_stop;
12744a17c441SPierre-Louis Bossart 
1275dfbe642dSPierre-Louis Bossart 	/* Initialize shim and controller */
1276dfbe642dSPierre-Louis Bossart 	intel_link_power_up(sdw);
12774a17c441SPierre-Louis Bossart 
12784a17c441SPierre-Louis Bossart 	clock_stop = sdw_cdns_is_clock_stop(&sdw->cdns);
12794a17c441SPierre-Louis Bossart 
12804a17c441SPierre-Louis Bossart 	intel_shim_init(sdw, clock_stop);
12814a17c441SPierre-Louis Bossart 
12824a17c441SPierre-Louis Bossart 	return 0;
1283dfbe642dSPierre-Louis Bossart }
1284dfbe642dSPierre-Louis Bossart 
128571bb8a1bSVinod Koul /*
128671bb8a1bSVinod Koul  * probe and init
128771bb8a1bSVinod Koul  */
1288b6109dd6SPierre-Louis Bossart static int intel_master_probe(struct platform_device *pdev)
128971bb8a1bSVinod Koul {
1290b6109dd6SPierre-Louis Bossart 	struct device *dev = &pdev->dev;
129171bb8a1bSVinod Koul 	struct sdw_intel *sdw;
129283e129afSPierre-Louis Bossart 	struct sdw_cdns *cdns;
1293b6109dd6SPierre-Louis Bossart 	struct sdw_bus *bus;
129471bb8a1bSVinod Koul 	int ret;
129571bb8a1bSVinod Koul 
1296b6109dd6SPierre-Louis Bossart 	sdw = devm_kzalloc(dev, sizeof(*sdw), GFP_KERNEL);
129771bb8a1bSVinod Koul 	if (!sdw)
129871bb8a1bSVinod Koul 		return -ENOMEM;
129971bb8a1bSVinod Koul 
130083e129afSPierre-Louis Bossart 	cdns = &sdw->cdns;
130183e129afSPierre-Louis Bossart 	bus = &cdns->bus;
130271bb8a1bSVinod Koul 
130371bb8a1bSVinod Koul 	sdw->instance = pdev->id;
1304b6109dd6SPierre-Louis Bossart 	sdw->link_res = dev_get_platdata(dev);
130583e129afSPierre-Louis Bossart 	cdns->dev = dev;
130683e129afSPierre-Louis Bossart 	cdns->registers = sdw->link_res->registers;
130783e129afSPierre-Louis Bossart 	cdns->instance = sdw->instance;
130883e129afSPierre-Louis Bossart 	cdns->msg_count = 0;
130983e129afSPierre-Louis Bossart 
1310b6109dd6SPierre-Louis Bossart 	bus->link_id = pdev->id;
131171bb8a1bSVinod Koul 
131283e129afSPierre-Louis Bossart 	sdw_cdns_probe(cdns);
131371bb8a1bSVinod Koul 
131471bb8a1bSVinod Koul 	/* Set property read ops */
1315c91605f4SShreyas NC 	sdw_intel_ops.read_prop = intel_prop_read;
1316b6109dd6SPierre-Louis Bossart 	bus->ops = &sdw_intel_ops;
131771bb8a1bSVinod Koul 
1318b6109dd6SPierre-Louis Bossart 	/* set driver data, accessed by snd_soc_dai_get_drvdata() */
131983e129afSPierre-Louis Bossart 	dev_set_drvdata(dev, cdns);
132071bb8a1bSVinod Koul 
13219026118fSBard Liao 	/* use generic bandwidth allocation algorithm */
13229026118fSBard Liao 	sdw->cdns.bus.compute_params = sdw_compute_params;
13239026118fSBard Liao 
1324b6109dd6SPierre-Louis Bossart 	ret = sdw_bus_master_add(bus, dev, dev->fwnode);
132571bb8a1bSVinod Koul 	if (ret) {
1326b6109dd6SPierre-Louis Bossart 		dev_err(dev, "sdw_bus_master_add fail: %d\n", ret);
13279e3d47fbSPierre-Louis Bossart 		return ret;
132871bb8a1bSVinod Koul 	}
132971bb8a1bSVinod Koul 
13306d2c6669SPierre-Louis Bossart 	if (bus->prop.hw_disabled)
1331b6109dd6SPierre-Louis Bossart 		dev_info(dev,
1332b6109dd6SPierre-Louis Bossart 			 "SoundWire master %d is disabled, will be ignored\n",
1333b6109dd6SPierre-Louis Bossart 			 bus->link_id);
13340ef2986eSPierre-Louis Bossart 	/*
13350ef2986eSPierre-Louis Bossart 	 * Ignore BIOS err_threshold, it's a really bad idea when dealing
13360ef2986eSPierre-Louis Bossart 	 * with multiple hardware synchronized links
13370ef2986eSPierre-Louis Bossart 	 */
13380ef2986eSPierre-Louis Bossart 	bus->prop.err_threshold = 0;
13396d2c6669SPierre-Louis Bossart 
13406d2c6669SPierre-Louis Bossart 	return 0;
13416d2c6669SPierre-Louis Bossart }
13426d2c6669SPierre-Louis Bossart 
13436d2c6669SPierre-Louis Bossart int intel_master_startup(struct platform_device *pdev)
13446d2c6669SPierre-Louis Bossart {
13456d2c6669SPierre-Louis Bossart 	struct sdw_cdns_stream_config config;
13466d2c6669SPierre-Louis Bossart 	struct device *dev = &pdev->dev;
13476d2c6669SPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
13486d2c6669SPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
13496d2c6669SPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1350ebf878edSPierre-Louis Bossart 	int link_flags;
1351857a7c42SPierre-Louis Bossart 	bool multi_link;
1352caf68819SPierre-Louis Bossart 	u32 clock_stop_quirks;
13536d2c6669SPierre-Louis Bossart 	int ret;
13546d2c6669SPierre-Louis Bossart 
13556d2c6669SPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
13566d2c6669SPierre-Louis Bossart 		dev_info(dev,
13576d2c6669SPierre-Louis Bossart 			 "SoundWire master %d is disabled, ignoring\n",
13586d2c6669SPierre-Louis Bossart 			 sdw->instance);
1359395713d8SPierre-Louis Bossart 		return 0;
1360395713d8SPierre-Louis Bossart 	}
1361395713d8SPierre-Louis Bossart 
1362857a7c42SPierre-Louis Bossart 	link_flags = md_flags >> (bus->link_id * 8);
1363857a7c42SPierre-Louis Bossart 	multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
1364857a7c42SPierre-Louis Bossart 	if (!multi_link) {
1365857a7c42SPierre-Louis Bossart 		dev_dbg(dev, "Multi-link is disabled\n");
1366857a7c42SPierre-Louis Bossart 		bus->multi_link = false;
1367857a7c42SPierre-Louis Bossart 	} else {
136894eed661SPierre-Louis Bossart 		/*
136994eed661SPierre-Louis Bossart 		 * hardware-based synchronization is required regardless
137094eed661SPierre-Louis Bossart 		 * of the number of segments used by a stream: SSP-based
137194eed661SPierre-Louis Bossart 		 * synchronization is gated by gsync when the multi-master
137294eed661SPierre-Louis Bossart 		 * mode is set.
137394eed661SPierre-Louis Bossart 		 */
1374857a7c42SPierre-Louis Bossart 		bus->multi_link = true;
137594eed661SPierre-Louis Bossart 		bus->hw_sync_min_links = 1;
1376857a7c42SPierre-Louis Bossart 	}
1377857a7c42SPierre-Louis Bossart 
1378857a7c42SPierre-Louis Bossart 	/* Initialize shim, controller */
1379dfbe642dSPierre-Louis Bossart 	ret = intel_init(sdw);
138071bb8a1bSVinod Koul 	if (ret)
138171bb8a1bSVinod Koul 		goto err_init;
138271bb8a1bSVinod Koul 
138337a2d22bSVinod Koul 	/* Read the PDI config and initialize cadence PDI */
138437a2d22bSVinod Koul 	intel_pdi_init(sdw, &config);
138583e129afSPierre-Louis Bossart 	ret = sdw_cdns_pdi_init(cdns, config);
138671bb8a1bSVinod Koul 	if (ret)
138771bb8a1bSVinod Koul 		goto err_init;
138871bb8a1bSVinod Koul 
138937a2d22bSVinod Koul 	intel_pdi_ch_update(sdw);
139037a2d22bSVinod Koul 
139183e129afSPierre-Louis Bossart 	ret = sdw_cdns_enable_interrupt(cdns, true);
139271bb8a1bSVinod Koul 	if (ret < 0) {
1393b6109dd6SPierre-Louis Bossart 		dev_err(dev, "cannot enable interrupts\n");
139471bb8a1bSVinod Koul 		goto err_init;
139571bb8a1bSVinod Koul 	}
139671bb8a1bSVinod Koul 
1397857a7c42SPierre-Louis Bossart 	/*
1398857a7c42SPierre-Louis Bossart 	 * follow recommended programming flows to avoid timeouts when
1399857a7c42SPierre-Louis Bossart 	 * gsync is enabled
1400857a7c42SPierre-Louis Bossart 	 */
1401857a7c42SPierre-Louis Bossart 	if (multi_link)
1402857a7c42SPierre-Louis Bossart 		intel_shim_sync_arm(sdw);
1403857a7c42SPierre-Louis Bossart 
1404857a7c42SPierre-Louis Bossart 	ret = sdw_cdns_init(cdns);
1405857a7c42SPierre-Louis Bossart 	if (ret < 0) {
1406857a7c42SPierre-Louis Bossart 		dev_err(dev, "unable to initialize Cadence IP\n");
1407857a7c42SPierre-Louis Bossart 		goto err_interrupt;
1408857a7c42SPierre-Louis Bossart 	}
1409857a7c42SPierre-Louis Bossart 
141083e129afSPierre-Louis Bossart 	ret = sdw_cdns_exit_reset(cdns);
141149ea07d3SPierre-Louis Bossart 	if (ret < 0) {
1412b6109dd6SPierre-Louis Bossart 		dev_err(dev, "unable to exit bus reset sequence\n");
14139e3d47fbSPierre-Louis Bossart 		goto err_interrupt;
141449ea07d3SPierre-Louis Bossart 	}
141549ea07d3SPierre-Louis Bossart 
1416857a7c42SPierre-Louis Bossart 	if (multi_link) {
1417857a7c42SPierre-Louis Bossart 		ret = intel_shim_sync_go(sdw);
1418857a7c42SPierre-Louis Bossart 		if (ret < 0) {
1419857a7c42SPierre-Louis Bossart 			dev_err(dev, "sync go failed: %d\n", ret);
1420857a7c42SPierre-Louis Bossart 			goto err_interrupt;
1421857a7c42SPierre-Louis Bossart 		}
1422857a7c42SPierre-Louis Bossart 	}
1423857a7c42SPierre-Louis Bossart 
1424c46302ecSVinod Koul 	/* Register DAIs */
1425c46302ecSVinod Koul 	ret = intel_register_dai(sdw);
1426c46302ecSVinod Koul 	if (ret) {
1427b6109dd6SPierre-Louis Bossart 		dev_err(dev, "DAI registration failed: %d\n", ret);
1428b6109dd6SPierre-Louis Bossart 		snd_soc_unregister_component(dev);
14299e3d47fbSPierre-Louis Bossart 		goto err_interrupt;
1430c46302ecSVinod Koul 	}
1431c46302ecSVinod Koul 
143279ee6631SPierre-Louis Bossart 	intel_debugfs_init(sdw);
143379ee6631SPierre-Louis Bossart 
1434ebf878edSPierre-Louis Bossart 	/* Enable runtime PM */
1435ebf878edSPierre-Louis Bossart 	if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) {
1436ebf878edSPierre-Louis Bossart 		pm_runtime_set_autosuspend_delay(dev,
1437ebf878edSPierre-Louis Bossart 						 INTEL_MASTER_SUSPEND_DELAY_MS);
1438ebf878edSPierre-Louis Bossart 		pm_runtime_use_autosuspend(dev);
1439ebf878edSPierre-Louis Bossart 		pm_runtime_mark_last_busy(dev);
1440ebf878edSPierre-Louis Bossart 
1441ebf878edSPierre-Louis Bossart 		pm_runtime_set_active(dev);
1442ebf878edSPierre-Louis Bossart 		pm_runtime_enable(dev);
1443ebf878edSPierre-Louis Bossart 	}
1444ebf878edSPierre-Louis Bossart 
1445caf68819SPierre-Louis Bossart 	clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1446caf68819SPierre-Louis Bossart 	if (clock_stop_quirks & SDW_INTEL_CLK_STOP_NOT_ALLOWED) {
1447caf68819SPierre-Louis Bossart 		/*
1448caf68819SPierre-Louis Bossart 		 * To keep the clock running we need to prevent
1449caf68819SPierre-Louis Bossart 		 * pm_runtime suspend from happening by increasing the
1450caf68819SPierre-Louis Bossart 		 * reference count.
1451caf68819SPierre-Louis Bossart 		 * This quirk is specified by the parent PCI device in
1452caf68819SPierre-Louis Bossart 		 * case of specific latency requirements. It will have
1453caf68819SPierre-Louis Bossart 		 * no effect if pm_runtime is disabled by the user via
1454caf68819SPierre-Louis Bossart 		 * a module parameter for testing purposes.
1455caf68819SPierre-Louis Bossart 		 */
1456caf68819SPierre-Louis Bossart 		pm_runtime_get_noresume(dev);
1457caf68819SPierre-Louis Bossart 	}
1458caf68819SPierre-Louis Bossart 
1459a2d9c161SPierre-Louis Bossart 	/*
1460a2d9c161SPierre-Louis Bossart 	 * The runtime PM status of Slave devices is "Unsupported"
1461a2d9c161SPierre-Louis Bossart 	 * until they report as ATTACHED. If they don't, e.g. because
1462a2d9c161SPierre-Louis Bossart 	 * there are no Slave devices populated or if the power-on is
1463a2d9c161SPierre-Louis Bossart 	 * delayed or dependent on a power switch, the Master will
1464a2d9c161SPierre-Louis Bossart 	 * remain active and prevent its parent from suspending.
1465a2d9c161SPierre-Louis Bossart 	 *
1466a2d9c161SPierre-Louis Bossart 	 * Conditionally force the pm_runtime core to re-evaluate the
1467a2d9c161SPierre-Louis Bossart 	 * Master status in the absence of any Slave activity. A quirk
1468a2d9c161SPierre-Louis Bossart 	 * is provided to e.g. deal with Slaves that may be powered on
1469a2d9c161SPierre-Louis Bossart 	 * with a delay. A more complete solution would require the
1470a2d9c161SPierre-Louis Bossart 	 * definition of Master properties.
1471a2d9c161SPierre-Louis Bossart 	 */
1472a2d9c161SPierre-Louis Bossart 	if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
1473a2d9c161SPierre-Louis Bossart 		pm_runtime_idle(dev);
1474a2d9c161SPierre-Louis Bossart 
147571bb8a1bSVinod Koul 	return 0;
147671bb8a1bSVinod Koul 
14779e3d47fbSPierre-Louis Bossart err_interrupt:
147883e129afSPierre-Louis Bossart 	sdw_cdns_enable_interrupt(cdns, false);
147971bb8a1bSVinod Koul err_init:
148071bb8a1bSVinod Koul 	return ret;
148171bb8a1bSVinod Koul }
148271bb8a1bSVinod Koul 
1483b6109dd6SPierre-Louis Bossart static int intel_master_remove(struct platform_device *pdev)
148471bb8a1bSVinod Koul {
1485b6109dd6SPierre-Louis Bossart 	struct device *dev = &pdev->dev;
148683e129afSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
148783e129afSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
148883e129afSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1489b6109dd6SPierre-Louis Bossart 
1490caf68819SPierre-Louis Bossart 	/*
1491caf68819SPierre-Louis Bossart 	 * Since pm_runtime is already disabled, we don't decrease
1492caf68819SPierre-Louis Bossart 	 * the refcount when the clock_stop_quirk is
1493caf68819SPierre-Louis Bossart 	 * SDW_INTEL_CLK_STOP_NOT_ALLOWED
1494caf68819SPierre-Louis Bossart 	 */
1495b6109dd6SPierre-Louis Bossart 	if (!bus->prop.hw_disabled) {
149679ee6631SPierre-Louis Bossart 		intel_debugfs_exit(sdw);
149783e129afSPierre-Louis Bossart 		sdw_cdns_enable_interrupt(cdns, false);
1498b6109dd6SPierre-Louis Bossart 		snd_soc_unregister_component(dev);
1499395713d8SPierre-Louis Bossart 	}
1500b6109dd6SPierre-Louis Bossart 	sdw_bus_master_delete(bus);
150171bb8a1bSVinod Koul 
150271bb8a1bSVinod Koul 	return 0;
150371bb8a1bSVinod Koul }
150471bb8a1bSVinod Koul 
1505ab2c9132SRander Wang int intel_master_process_wakeen_event(struct platform_device *pdev)
1506ab2c9132SRander Wang {
1507ab2c9132SRander Wang 	struct device *dev = &pdev->dev;
150871bb8a1bSVinod Koul 	struct sdw_intel *sdw;
1509ab2c9132SRander Wang 	struct sdw_bus *bus;
1510ab2c9132SRander Wang 	void __iomem *shim;
1511ab2c9132SRander Wang 	u16 wake_sts;
151271bb8a1bSVinod Koul 
151371bb8a1bSVinod Koul 	sdw = platform_get_drvdata(pdev);
1514ab2c9132SRander Wang 	bus = &sdw->cdns.bus;
151571bb8a1bSVinod Koul 
1516ab2c9132SRander Wang 	if (bus->prop.hw_disabled) {
1517ab2c9132SRander Wang 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", bus->link_id);
1518ab2c9132SRander Wang 		return 0;
151971bb8a1bSVinod Koul 	}
1520ab2c9132SRander Wang 
1521ab2c9132SRander Wang 	shim = sdw->link_res->shim;
1522ab2c9132SRander Wang 	wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
1523ab2c9132SRander Wang 
1524ab2c9132SRander Wang 	if (!(wake_sts & BIT(sdw->instance)))
1525ab2c9132SRander Wang 		return 0;
1526ab2c9132SRander Wang 
1527ab2c9132SRander Wang 	/* disable WAKEEN interrupt ASAP to prevent interrupt flood */
1528ab2c9132SRander Wang 	intel_shim_wake(sdw, false);
1529ab2c9132SRander Wang 
1530ab2c9132SRander Wang 	/*
1531ab2c9132SRander Wang 	 * resume the Master, which will generate a bus reset and result in
1532ab2c9132SRander Wang 	 * Slaves re-attaching and be re-enumerated. The SoundWire physical
1533ab2c9132SRander Wang 	 * device which generated the wake will trigger an interrupt, which
1534ab2c9132SRander Wang 	 * will in turn cause the corresponding Linux Slave device to be
1535ab2c9132SRander Wang 	 * resumed and the Slave codec driver to check the status.
1536ab2c9132SRander Wang 	 */
1537ab2c9132SRander Wang 	pm_request_resume(dev);
153871bb8a1bSVinod Koul 
153971bb8a1bSVinod Koul 	return 0;
154071bb8a1bSVinod Koul }
154171bb8a1bSVinod Koul 
15429b3b4b3fSPierre-Louis Bossart /*
15439b3b4b3fSPierre-Louis Bossart  * PM calls
15449b3b4b3fSPierre-Louis Bossart  */
15459b3b4b3fSPierre-Louis Bossart 
15469b3b4b3fSPierre-Louis Bossart #ifdef CONFIG_PM
15479b3b4b3fSPierre-Louis Bossart 
1548f046b233SBard Liao static int __maybe_unused intel_suspend(struct device *dev)
15499b3b4b3fSPierre-Louis Bossart {
15509b3b4b3fSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
15519b3b4b3fSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
15529b3b4b3fSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1553e4be9facSPierre-Louis Bossart 	u32 clock_stop_quirks;
15549b3b4b3fSPierre-Louis Bossart 	int ret;
15559b3b4b3fSPierre-Louis Bossart 
15569b3b4b3fSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
15579b3b4b3fSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
15589b3b4b3fSPierre-Louis Bossart 			bus->link_id);
15599b3b4b3fSPierre-Louis Bossart 		return 0;
15609b3b4b3fSPierre-Louis Bossart 	}
15619b3b4b3fSPierre-Louis Bossart 
1562b61b8b37SPierre-Louis Bossart 	if (pm_runtime_suspended(dev)) {
1563b61b8b37SPierre-Louis Bossart 		dev_dbg(dev, "%s: pm_runtime status: suspended\n", __func__);
1564b61b8b37SPierre-Louis Bossart 
1565e4be9facSPierre-Louis Bossart 		clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1566e4be9facSPierre-Louis Bossart 
1567e4be9facSPierre-Louis Bossart 		if ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET ||
1568e4be9facSPierre-Louis Bossart 		     !clock_stop_quirks) &&
1569e4be9facSPierre-Louis Bossart 		    !pm_runtime_suspended(dev->parent)) {
1570e4be9facSPierre-Louis Bossart 
1571e4be9facSPierre-Louis Bossart 			/*
1572e4be9facSPierre-Louis Bossart 			 * if we've enabled clock stop, and the parent
1573e4be9facSPierre-Louis Bossart 			 * is still active, disable shim wake. The
1574e4be9facSPierre-Louis Bossart 			 * SHIM registers are not accessible if the
1575e4be9facSPierre-Louis Bossart 			 * parent is already pm_runtime suspended so
1576e4be9facSPierre-Louis Bossart 			 * it's too late to change that configuration
1577e4be9facSPierre-Louis Bossart 			 */
1578e4be9facSPierre-Louis Bossart 
1579e4be9facSPierre-Louis Bossart 			intel_shim_wake(sdw, false);
1580e4be9facSPierre-Louis Bossart 		}
1581e4be9facSPierre-Louis Bossart 
1582b61b8b37SPierre-Louis Bossart 		return 0;
1583b61b8b37SPierre-Louis Bossart 	}
1584b61b8b37SPierre-Louis Bossart 
15859b3b4b3fSPierre-Louis Bossart 	ret = sdw_cdns_enable_interrupt(cdns, false);
15869b3b4b3fSPierre-Louis Bossart 	if (ret < 0) {
15879b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "cannot disable interrupts on suspend\n");
15889b3b4b3fSPierre-Louis Bossart 		return ret;
15899b3b4b3fSPierre-Louis Bossart 	}
15909b3b4b3fSPierre-Louis Bossart 
15919b3b4b3fSPierre-Louis Bossart 	ret = intel_link_power_down(sdw);
15929b3b4b3fSPierre-Louis Bossart 	if (ret) {
15939b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "Link power down failed: %d", ret);
15949b3b4b3fSPierre-Louis Bossart 		return ret;
15959b3b4b3fSPierre-Louis Bossart 	}
15969b3b4b3fSPierre-Louis Bossart 
15979b3b4b3fSPierre-Louis Bossart 	intel_shim_wake(sdw, false);
15989b3b4b3fSPierre-Louis Bossart 
15999b3b4b3fSPierre-Louis Bossart 	return 0;
16009b3b4b3fSPierre-Louis Bossart }
16019b3b4b3fSPierre-Louis Bossart 
1602ebf878edSPierre-Louis Bossart static int intel_suspend_runtime(struct device *dev)
1603ebf878edSPierre-Louis Bossart {
1604ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
1605ebf878edSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
1606ebf878edSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1607a320f41eSPierre-Louis Bossart 	u32 clock_stop_quirks;
1608ebf878edSPierre-Louis Bossart 	int ret;
1609ebf878edSPierre-Louis Bossart 
1610ebf878edSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
1611ebf878edSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1612ebf878edSPierre-Louis Bossart 			bus->link_id);
1613ebf878edSPierre-Louis Bossart 		return 0;
1614ebf878edSPierre-Louis Bossart 	}
1615ebf878edSPierre-Louis Bossart 
1616a320f41eSPierre-Louis Bossart 	clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1617a320f41eSPierre-Louis Bossart 
1618a320f41eSPierre-Louis Bossart 	if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
1619a320f41eSPierre-Louis Bossart 
1620ebf878edSPierre-Louis Bossart 		ret = sdw_cdns_enable_interrupt(cdns, false);
1621ebf878edSPierre-Louis Bossart 		if (ret < 0) {
1622ebf878edSPierre-Louis Bossart 			dev_err(dev, "cannot disable interrupts on suspend\n");
1623ebf878edSPierre-Louis Bossart 			return ret;
1624ebf878edSPierre-Louis Bossart 		}
1625ebf878edSPierre-Louis Bossart 
1626ebf878edSPierre-Louis Bossart 		ret = intel_link_power_down(sdw);
1627ebf878edSPierre-Louis Bossart 		if (ret) {
1628ebf878edSPierre-Louis Bossart 			dev_err(dev, "Link power down failed: %d", ret);
1629ebf878edSPierre-Louis Bossart 			return ret;
1630ebf878edSPierre-Louis Bossart 		}
1631ebf878edSPierre-Louis Bossart 
1632ebf878edSPierre-Louis Bossart 		intel_shim_wake(sdw, false);
1633ebf878edSPierre-Louis Bossart 
163461fb830bSPierre-Louis Bossart 	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET ||
163561fb830bSPierre-Louis Bossart 		   !clock_stop_quirks) {
16366626a616SRander Wang 		ret = sdw_cdns_clock_stop(cdns, true);
16376626a616SRander Wang 		if (ret < 0) {
16386626a616SRander Wang 			dev_err(dev, "cannot enable clock stop on suspend\n");
16396626a616SRander Wang 			return ret;
16406626a616SRander Wang 		}
16416626a616SRander Wang 
16426626a616SRander Wang 		ret = sdw_cdns_enable_interrupt(cdns, false);
16436626a616SRander Wang 		if (ret < 0) {
16446626a616SRander Wang 			dev_err(dev, "cannot disable interrupts on suspend\n");
16456626a616SRander Wang 			return ret;
16466626a616SRander Wang 		}
16476626a616SRander Wang 
16486626a616SRander Wang 		ret = intel_link_power_down(sdw);
16496626a616SRander Wang 		if (ret) {
16506626a616SRander Wang 			dev_err(dev, "Link power down failed: %d", ret);
16516626a616SRander Wang 			return ret;
16526626a616SRander Wang 		}
16536626a616SRander Wang 
16546626a616SRander Wang 		intel_shim_wake(sdw, true);
1655a320f41eSPierre-Louis Bossart 	} else {
1656a320f41eSPierre-Louis Bossart 		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
1657a320f41eSPierre-Louis Bossart 			__func__, clock_stop_quirks);
1658a320f41eSPierre-Louis Bossart 		ret = -EINVAL;
1659a320f41eSPierre-Louis Bossart 	}
1660a320f41eSPierre-Louis Bossart 
1661a320f41eSPierre-Louis Bossart 	return ret;
1662ebf878edSPierre-Louis Bossart }
1663ebf878edSPierre-Louis Bossart 
1664f046b233SBard Liao static int __maybe_unused intel_resume(struct device *dev)
16659b3b4b3fSPierre-Louis Bossart {
16669b3b4b3fSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
16679b3b4b3fSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
16689b3b4b3fSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1669a2d9c161SPierre-Louis Bossart 	int link_flags;
1670857a7c42SPierre-Louis Bossart 	bool multi_link;
16719b3b4b3fSPierre-Louis Bossart 	int ret;
16729b3b4b3fSPierre-Louis Bossart 
16739b3b4b3fSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
16749b3b4b3fSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
16759b3b4b3fSPierre-Louis Bossart 			bus->link_id);
16769b3b4b3fSPierre-Louis Bossart 		return 0;
16779b3b4b3fSPierre-Louis Bossart 	}
16789b3b4b3fSPierre-Louis Bossart 
1679857a7c42SPierre-Louis Bossart 	link_flags = md_flags >> (bus->link_id * 8);
1680857a7c42SPierre-Louis Bossart 	multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
1681857a7c42SPierre-Louis Bossart 
1682b61b8b37SPierre-Louis Bossart 	if (pm_runtime_suspended(dev)) {
1683b61b8b37SPierre-Louis Bossart 		dev_dbg(dev, "%s: pm_runtime status was suspended, forcing active\n", __func__);
1684b61b8b37SPierre-Louis Bossart 
1685b61b8b37SPierre-Louis Bossart 		/* follow required sequence from runtime_pm.rst */
1686b61b8b37SPierre-Louis Bossart 		pm_runtime_disable(dev);
1687b61b8b37SPierre-Louis Bossart 		pm_runtime_set_active(dev);
1688b61b8b37SPierre-Louis Bossart 		pm_runtime_mark_last_busy(dev);
1689b61b8b37SPierre-Louis Bossart 		pm_runtime_enable(dev);
1690a2d9c161SPierre-Louis Bossart 
1691a2d9c161SPierre-Louis Bossart 		link_flags = md_flags >> (bus->link_id * 8);
1692857a7c42SPierre-Louis Bossart 
1693a2d9c161SPierre-Louis Bossart 		if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
1694a2d9c161SPierre-Louis Bossart 			pm_runtime_idle(dev);
1695b61b8b37SPierre-Louis Bossart 	}
1696b61b8b37SPierre-Louis Bossart 
16979b3b4b3fSPierre-Louis Bossart 	ret = intel_init(sdw);
16989b3b4b3fSPierre-Louis Bossart 	if (ret) {
16999b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "%s failed: %d", __func__, ret);
17009b3b4b3fSPierre-Louis Bossart 		return ret;
17019b3b4b3fSPierre-Louis Bossart 	}
17029b3b4b3fSPierre-Louis Bossart 
170399b6a30fSPierre-Louis Bossart 	/*
170499b6a30fSPierre-Louis Bossart 	 * make sure all Slaves are tagged as UNATTACHED and provide
170599b6a30fSPierre-Louis Bossart 	 * reason for reinitialization
170699b6a30fSPierre-Louis Bossart 	 */
170799b6a30fSPierre-Louis Bossart 	sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
170899b6a30fSPierre-Louis Bossart 
17099b3b4b3fSPierre-Louis Bossart 	ret = sdw_cdns_enable_interrupt(cdns, true);
17109b3b4b3fSPierre-Louis Bossart 	if (ret < 0) {
17119b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "cannot enable interrupts during resume\n");
17129b3b4b3fSPierre-Louis Bossart 		return ret;
17139b3b4b3fSPierre-Louis Bossart 	}
17149b3b4b3fSPierre-Louis Bossart 
1715857a7c42SPierre-Louis Bossart 	/*
1716857a7c42SPierre-Louis Bossart 	 * follow recommended programming flows to avoid timeouts when
1717857a7c42SPierre-Louis Bossart 	 * gsync is enabled
1718857a7c42SPierre-Louis Bossart 	 */
1719857a7c42SPierre-Louis Bossart 	if (multi_link)
1720857a7c42SPierre-Louis Bossart 		intel_shim_sync_arm(sdw);
1721857a7c42SPierre-Louis Bossart 
1722857a7c42SPierre-Louis Bossart 	ret = sdw_cdns_init(&sdw->cdns);
1723857a7c42SPierre-Louis Bossart 	if (ret < 0) {
1724857a7c42SPierre-Louis Bossart 		dev_err(dev, "unable to initialize Cadence IP during resume\n");
1725857a7c42SPierre-Louis Bossart 		return ret;
1726857a7c42SPierre-Louis Bossart 	}
1727857a7c42SPierre-Louis Bossart 
17289b3b4b3fSPierre-Louis Bossart 	ret = sdw_cdns_exit_reset(cdns);
17299b3b4b3fSPierre-Louis Bossart 	if (ret < 0) {
17309b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "unable to exit bus reset sequence during resume\n");
17319b3b4b3fSPierre-Louis Bossart 		return ret;
17329b3b4b3fSPierre-Louis Bossart 	}
17339b3b4b3fSPierre-Louis Bossart 
1734857a7c42SPierre-Louis Bossart 	if (multi_link) {
1735857a7c42SPierre-Louis Bossart 		ret = intel_shim_sync_go(sdw);
1736857a7c42SPierre-Louis Bossart 		if (ret < 0) {
1737857a7c42SPierre-Louis Bossart 			dev_err(dev, "sync go failed during resume\n");
1738857a7c42SPierre-Louis Bossart 			return ret;
1739857a7c42SPierre-Louis Bossart 		}
1740857a7c42SPierre-Louis Bossart 	}
1741857a7c42SPierre-Louis Bossart 
1742cb1e6d59SPierre-Louis Bossart 	/*
1743cb1e6d59SPierre-Louis Bossart 	 * after system resume, the pm_runtime suspend() may kick in
1744cb1e6d59SPierre-Louis Bossart 	 * during the enumeration, before any children device force the
1745cb1e6d59SPierre-Louis Bossart 	 * master device to remain active.  Using pm_runtime_get()
1746cb1e6d59SPierre-Louis Bossart 	 * routines is not really possible, since it'd prevent the
1747cb1e6d59SPierre-Louis Bossart 	 * master from suspending.
1748cb1e6d59SPierre-Louis Bossart 	 * A reasonable compromise is to update the pm_runtime
1749cb1e6d59SPierre-Louis Bossart 	 * counters and delay the pm_runtime suspend by several
1750cb1e6d59SPierre-Louis Bossart 	 * seconds, by when all enumeration should be complete.
1751cb1e6d59SPierre-Louis Bossart 	 */
1752cb1e6d59SPierre-Louis Bossart 	pm_runtime_mark_last_busy(dev);
1753cb1e6d59SPierre-Louis Bossart 
17549b3b4b3fSPierre-Louis Bossart 	return ret;
17559b3b4b3fSPierre-Louis Bossart }
17569b3b4b3fSPierre-Louis Bossart 
1757ebf878edSPierre-Louis Bossart static int intel_resume_runtime(struct device *dev)
1758ebf878edSPierre-Louis Bossart {
1759ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
1760ebf878edSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
1761ebf878edSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1762a320f41eSPierre-Louis Bossart 	u32 clock_stop_quirks;
176308abad9fSRander Wang 	bool clock_stop0;
1764857a7c42SPierre-Louis Bossart 	int link_flags;
1765857a7c42SPierre-Louis Bossart 	bool multi_link;
176608abad9fSRander Wang 	int status;
1767ebf878edSPierre-Louis Bossart 	int ret;
1768ebf878edSPierre-Louis Bossart 
1769ebf878edSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
1770ebf878edSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1771ebf878edSPierre-Louis Bossart 			bus->link_id);
1772ebf878edSPierre-Louis Bossart 		return 0;
1773ebf878edSPierre-Louis Bossart 	}
1774ebf878edSPierre-Louis Bossart 
1775857a7c42SPierre-Louis Bossart 	link_flags = md_flags >> (bus->link_id * 8);
1776857a7c42SPierre-Louis Bossart 	multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
1777857a7c42SPierre-Louis Bossart 
1778a320f41eSPierre-Louis Bossart 	clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1779a320f41eSPierre-Louis Bossart 
1780a320f41eSPierre-Louis Bossart 	if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
1781ebf878edSPierre-Louis Bossart 		ret = intel_init(sdw);
1782ebf878edSPierre-Louis Bossart 		if (ret) {
1783ebf878edSPierre-Louis Bossart 			dev_err(dev, "%s failed: %d", __func__, ret);
1784ebf878edSPierre-Louis Bossart 			return ret;
1785ebf878edSPierre-Louis Bossart 		}
1786ebf878edSPierre-Louis Bossart 
178799b6a30fSPierre-Louis Bossart 		/*
178899b6a30fSPierre-Louis Bossart 		 * make sure all Slaves are tagged as UNATTACHED and provide
178999b6a30fSPierre-Louis Bossart 		 * reason for reinitialization
179099b6a30fSPierre-Louis Bossart 		 */
179199b6a30fSPierre-Louis Bossart 		sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
179299b6a30fSPierre-Louis Bossart 
1793ebf878edSPierre-Louis Bossart 		ret = sdw_cdns_enable_interrupt(cdns, true);
1794ebf878edSPierre-Louis Bossart 		if (ret < 0) {
1795ebf878edSPierre-Louis Bossart 			dev_err(dev, "cannot enable interrupts during resume\n");
1796ebf878edSPierre-Louis Bossart 			return ret;
1797ebf878edSPierre-Louis Bossart 		}
1798ebf878edSPierre-Louis Bossart 
1799857a7c42SPierre-Louis Bossart 		/*
1800857a7c42SPierre-Louis Bossart 		 * follow recommended programming flows to avoid
1801857a7c42SPierre-Louis Bossart 		 * timeouts when gsync is enabled
1802857a7c42SPierre-Louis Bossart 		 */
1803857a7c42SPierre-Louis Bossart 		if (multi_link)
1804857a7c42SPierre-Louis Bossart 			intel_shim_sync_arm(sdw);
1805857a7c42SPierre-Louis Bossart 
1806857a7c42SPierre-Louis Bossart 		ret = sdw_cdns_init(&sdw->cdns);
1807857a7c42SPierre-Louis Bossart 		if (ret < 0) {
1808857a7c42SPierre-Louis Bossart 			dev_err(dev, "unable to initialize Cadence IP during resume\n");
1809857a7c42SPierre-Louis Bossart 			return ret;
1810857a7c42SPierre-Louis Bossart 		}
1811857a7c42SPierre-Louis Bossart 
1812ebf878edSPierre-Louis Bossart 		ret = sdw_cdns_exit_reset(cdns);
1813ebf878edSPierre-Louis Bossart 		if (ret < 0) {
1814ebf878edSPierre-Louis Bossart 			dev_err(dev, "unable to exit bus reset sequence during resume\n");
1815ebf878edSPierre-Louis Bossart 			return ret;
1816ebf878edSPierre-Louis Bossart 		}
1817857a7c42SPierre-Louis Bossart 
1818857a7c42SPierre-Louis Bossart 		if (multi_link) {
1819857a7c42SPierre-Louis Bossart 			ret = intel_shim_sync_go(sdw);
1820857a7c42SPierre-Louis Bossart 			if (ret < 0) {
1821857a7c42SPierre-Louis Bossart 				dev_err(dev, "sync go failed during resume\n");
1822857a7c42SPierre-Louis Bossart 				return ret;
1823857a7c42SPierre-Louis Bossart 			}
1824857a7c42SPierre-Louis Bossart 		}
18256626a616SRander Wang 	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
18266626a616SRander Wang 		ret = intel_init(sdw);
18276626a616SRander Wang 		if (ret) {
18286626a616SRander Wang 			dev_err(dev, "%s failed: %d", __func__, ret);
18296626a616SRander Wang 			return ret;
18306626a616SRander Wang 		}
18316626a616SRander Wang 
18326626a616SRander Wang 		/*
183308abad9fSRander Wang 		 * An exception condition occurs for the CLK_STOP_BUS_RESET
183408abad9fSRander Wang 		 * case if one or more masters remain active. In this condition,
183508abad9fSRander Wang 		 * all the masters are powered on for they are in the same power
183608abad9fSRander Wang 		 * domain. Master can preserve its context for clock stop0, so
183708abad9fSRander Wang 		 * there is no need to clear slave status and reset bus.
183808abad9fSRander Wang 		 */
183908abad9fSRander Wang 		clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
184008abad9fSRander Wang 
1841857a7c42SPierre-Louis Bossart 		if (!clock_stop0) {
1842857a7c42SPierre-Louis Bossart 
1843857a7c42SPierre-Louis Bossart 			/*
18446626a616SRander Wang 			 * make sure all Slaves are tagged as UNATTACHED and
18456626a616SRander Wang 			 * provide reason for reinitialization
18466626a616SRander Wang 			 */
1847857a7c42SPierre-Louis Bossart 
184808abad9fSRander Wang 			status = SDW_UNATTACH_REQUEST_MASTER_RESET;
184908abad9fSRander Wang 			sdw_clear_slave_status(bus, status);
18506626a616SRander Wang 
18516626a616SRander Wang 			ret = sdw_cdns_enable_interrupt(cdns, true);
18526626a616SRander Wang 			if (ret < 0) {
18536626a616SRander Wang 				dev_err(dev, "cannot enable interrupts during resume\n");
18546626a616SRander Wang 				return ret;
18556626a616SRander Wang 			}
18566626a616SRander Wang 
1857d78071b4SPierre-Louis Bossart 			/*
1858d78071b4SPierre-Louis Bossart 			 * follow recommended programming flows to avoid
1859d78071b4SPierre-Louis Bossart 			 * timeouts when gsync is enabled
1860d78071b4SPierre-Louis Bossart 			 */
1861d78071b4SPierre-Louis Bossart 			if (multi_link)
1862d78071b4SPierre-Louis Bossart 				intel_shim_sync_arm(sdw);
1863d78071b4SPierre-Louis Bossart 
1864d78071b4SPierre-Louis Bossart 			/*
1865d78071b4SPierre-Louis Bossart 			 * Re-initialize the IP since it was powered-off
1866d78071b4SPierre-Louis Bossart 			 */
1867d78071b4SPierre-Louis Bossart 			sdw_cdns_init(&sdw->cdns);
1868d78071b4SPierre-Louis Bossart 
1869d78071b4SPierre-Louis Bossart 		} else {
1870d78071b4SPierre-Louis Bossart 			ret = sdw_cdns_enable_interrupt(cdns, true);
1871d78071b4SPierre-Louis Bossart 			if (ret < 0) {
1872d78071b4SPierre-Louis Bossart 				dev_err(dev, "cannot enable interrupts during resume\n");
1873d78071b4SPierre-Louis Bossart 				return ret;
1874d78071b4SPierre-Louis Bossart 			}
1875d78071b4SPierre-Louis Bossart 		}
1876d78071b4SPierre-Louis Bossart 
187708abad9fSRander Wang 		ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
18786626a616SRander Wang 		if (ret < 0) {
18796626a616SRander Wang 			dev_err(dev, "unable to restart clock during resume\n");
18806626a616SRander Wang 			return ret;
18816626a616SRander Wang 		}
1882d78071b4SPierre-Louis Bossart 
1883d78071b4SPierre-Louis Bossart 		if (!clock_stop0) {
1884d78071b4SPierre-Louis Bossart 			ret = sdw_cdns_exit_reset(cdns);
1885d78071b4SPierre-Louis Bossart 			if (ret < 0) {
1886d78071b4SPierre-Louis Bossart 				dev_err(dev, "unable to exit bus reset sequence during resume\n");
1887d78071b4SPierre-Louis Bossart 				return ret;
1888d78071b4SPierre-Louis Bossart 			}
1889d78071b4SPierre-Louis Bossart 
1890d78071b4SPierre-Louis Bossart 			if (multi_link) {
1891d78071b4SPierre-Louis Bossart 				ret = intel_shim_sync_go(sdw);
1892d78071b4SPierre-Louis Bossart 				if (ret < 0) {
1893d78071b4SPierre-Louis Bossart 					dev_err(sdw->cdns.dev, "sync go failed during resume\n");
1894d78071b4SPierre-Louis Bossart 					return ret;
1895d78071b4SPierre-Louis Bossart 				}
1896d78071b4SPierre-Louis Bossart 			}
1897d78071b4SPierre-Louis Bossart 		}
189861fb830bSPierre-Louis Bossart 	} else if (!clock_stop_quirks) {
1899f748f34eSPierre-Louis Bossart 
1900f748f34eSPierre-Louis Bossart 		clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
1901f748f34eSPierre-Louis Bossart 		if (!clock_stop0)
1902f748f34eSPierre-Louis Bossart 			dev_err(dev, "%s invalid configuration, clock was not stopped", __func__);
1903f748f34eSPierre-Louis Bossart 
190461fb830bSPierre-Louis Bossart 		ret = intel_init(sdw);
190561fb830bSPierre-Louis Bossart 		if (ret) {
190661fb830bSPierre-Louis Bossart 			dev_err(dev, "%s failed: %d", __func__, ret);
190761fb830bSPierre-Louis Bossart 			return ret;
190861fb830bSPierre-Louis Bossart 		}
190961fb830bSPierre-Louis Bossart 
191061fb830bSPierre-Louis Bossart 		ret = sdw_cdns_enable_interrupt(cdns, true);
191161fb830bSPierre-Louis Bossart 		if (ret < 0) {
191261fb830bSPierre-Louis Bossart 			dev_err(dev, "cannot enable interrupts during resume\n");
191361fb830bSPierre-Louis Bossart 			return ret;
191461fb830bSPierre-Louis Bossart 		}
191561fb830bSPierre-Louis Bossart 
191661fb830bSPierre-Louis Bossart 		ret = sdw_cdns_clock_restart(cdns, false);
191761fb830bSPierre-Louis Bossart 		if (ret < 0) {
191861fb830bSPierre-Louis Bossart 			dev_err(dev, "unable to resume master during resume\n");
191961fb830bSPierre-Louis Bossart 			return ret;
192061fb830bSPierre-Louis Bossart 		}
1921a320f41eSPierre-Louis Bossart 	} else {
1922a320f41eSPierre-Louis Bossart 		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
1923a320f41eSPierre-Louis Bossart 			__func__, clock_stop_quirks);
1924a320f41eSPierre-Louis Bossart 		ret = -EINVAL;
1925a320f41eSPierre-Louis Bossart 	}
1926ebf878edSPierre-Louis Bossart 
1927ebf878edSPierre-Louis Bossart 	return ret;
1928ebf878edSPierre-Louis Bossart }
1929ebf878edSPierre-Louis Bossart 
19309b3b4b3fSPierre-Louis Bossart #endif
19319b3b4b3fSPierre-Louis Bossart 
19329b3b4b3fSPierre-Louis Bossart static const struct dev_pm_ops intel_pm = {
19339b3b4b3fSPierre-Louis Bossart 	SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
1934ebf878edSPierre-Louis Bossart 	SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL)
19359b3b4b3fSPierre-Louis Bossart };
19369b3b4b3fSPierre-Louis Bossart 
193771bb8a1bSVinod Koul static struct platform_driver sdw_intel_drv = {
1938b6109dd6SPierre-Louis Bossart 	.probe = intel_master_probe,
1939b6109dd6SPierre-Louis Bossart 	.remove = intel_master_remove,
194071bb8a1bSVinod Koul 	.driver = {
19416d2c6669SPierre-Louis Bossart 		.name = "intel-sdw",
19429b3b4b3fSPierre-Louis Bossart 		.pm = &intel_pm,
19439b3b4b3fSPierre-Louis Bossart 	}
194471bb8a1bSVinod Koul };
194571bb8a1bSVinod Koul 
194671bb8a1bSVinod Koul module_platform_driver(sdw_intel_drv);
194771bb8a1bSVinod Koul 
194871bb8a1bSVinod Koul MODULE_LICENSE("Dual BSD/GPL");
19496d2c6669SPierre-Louis Bossart MODULE_ALIAS("platform:intel-sdw");
195071bb8a1bSVinod Koul MODULE_DESCRIPTION("Intel Soundwire Master Driver");
1951