xref: /linux/drivers/soundwire/intel.c (revision 17e0da0b8979a53977f684813f5c9db817d170e2)
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 
2650f9138e7SPierre-Louis Bossart static int intel_set_m_datamode(void *data, u64 value)
2660f9138e7SPierre-Louis Bossart {
2670f9138e7SPierre-Louis Bossart 	struct sdw_intel *sdw = data;
2680f9138e7SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
2690f9138e7SPierre-Louis Bossart 
2700f9138e7SPierre-Louis Bossart 	if (value > SDW_PORT_DATA_MODE_STATIC_1)
2710f9138e7SPierre-Louis Bossart 		return -EINVAL;
2720f9138e7SPierre-Louis Bossart 
2730f9138e7SPierre-Louis Bossart 	/* Userspace changed the hardware state behind the kernel's back */
2740f9138e7SPierre-Louis Bossart 	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
2750f9138e7SPierre-Louis Bossart 
2760f9138e7SPierre-Louis Bossart 	bus->params.m_data_mode = value;
2770f9138e7SPierre-Louis Bossart 
2780f9138e7SPierre-Louis Bossart 	return 0;
2790f9138e7SPierre-Louis Bossart }
2800f9138e7SPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(intel_set_m_datamode_fops, NULL,
2810f9138e7SPierre-Louis Bossart 			 intel_set_m_datamode, "%llu\n");
2820f9138e7SPierre-Louis Bossart 
2830f9138e7SPierre-Louis Bossart static int intel_set_s_datamode(void *data, u64 value)
2840f9138e7SPierre-Louis Bossart {
2850f9138e7SPierre-Louis Bossart 	struct sdw_intel *sdw = data;
2860f9138e7SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
2870f9138e7SPierre-Louis Bossart 
2880f9138e7SPierre-Louis Bossart 	if (value > SDW_PORT_DATA_MODE_STATIC_1)
2890f9138e7SPierre-Louis Bossart 		return -EINVAL;
2900f9138e7SPierre-Louis Bossart 
2910f9138e7SPierre-Louis Bossart 	/* Userspace changed the hardware state behind the kernel's back */
2920f9138e7SPierre-Louis Bossart 	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
2930f9138e7SPierre-Louis Bossart 
2940f9138e7SPierre-Louis Bossart 	bus->params.s_data_mode = value;
2950f9138e7SPierre-Louis Bossart 
2960f9138e7SPierre-Louis Bossart 	return 0;
2970f9138e7SPierre-Louis Bossart }
2980f9138e7SPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(intel_set_s_datamode_fops, NULL,
2990f9138e7SPierre-Louis Bossart 			 intel_set_s_datamode, "%llu\n");
3000f9138e7SPierre-Louis Bossart 
30179ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw)
30279ee6631SPierre-Louis Bossart {
30379ee6631SPierre-Louis Bossart 	struct dentry *root = sdw->cdns.bus.debugfs;
30479ee6631SPierre-Louis Bossart 
30579ee6631SPierre-Louis Bossart 	if (!root)
30679ee6631SPierre-Louis Bossart 		return;
30779ee6631SPierre-Louis Bossart 
30879ee6631SPierre-Louis Bossart 	sdw->debugfs = debugfs_create_dir("intel-sdw", root);
30979ee6631SPierre-Louis Bossart 
31079ee6631SPierre-Louis Bossart 	debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw,
31179ee6631SPierre-Louis Bossart 			    &intel_reg_fops);
31279ee6631SPierre-Louis Bossart 
3130f9138e7SPierre-Louis Bossart 	debugfs_create_file("intel-m-datamode", 0200, sdw->debugfs, sdw,
3140f9138e7SPierre-Louis Bossart 			    &intel_set_m_datamode_fops);
3150f9138e7SPierre-Louis Bossart 
3160f9138e7SPierre-Louis Bossart 	debugfs_create_file("intel-s-datamode", 0200, sdw->debugfs, sdw,
3170f9138e7SPierre-Louis Bossart 			    &intel_set_s_datamode_fops);
3180f9138e7SPierre-Louis Bossart 
31979ee6631SPierre-Louis Bossart 	sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs);
32079ee6631SPierre-Louis Bossart }
32179ee6631SPierre-Louis Bossart 
32279ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw)
32379ee6631SPierre-Louis Bossart {
32479ee6631SPierre-Louis Bossart 	debugfs_remove_recursive(sdw->debugfs);
32579ee6631SPierre-Louis Bossart }
32679ee6631SPierre-Louis Bossart #else
32779ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw) {}
32879ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw) {}
32979ee6631SPierre-Louis Bossart #endif /* CONFIG_DEBUG_FS */
33079ee6631SPierre-Louis Bossart 
33179ee6631SPierre-Louis Bossart /*
33271bb8a1bSVinod Koul  * shim ops
33371bb8a1bSVinod Koul  */
33471bb8a1bSVinod Koul 
33571bb8a1bSVinod Koul static int intel_link_power_up(struct sdw_intel *sdw)
33671bb8a1bSVinod Koul {
33771bb8a1bSVinod Koul 	unsigned int link_id = sdw->instance;
3382523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
3394a17c441SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
3404a17c441SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
3414a17c441SPierre-Louis Bossart 	struct sdw_master_prop *prop = &bus->prop;
3425ee74eb2SPierre-Louis Bossart 	u32 spa_mask, cpa_mask;
3435ee74eb2SPierre-Louis Bossart 	u32 link_control;
3444a17c441SPierre-Louis Bossart 	int ret = 0;
3454a17c441SPierre-Louis Bossart 	u32 syncprd;
3464a17c441SPierre-Louis Bossart 	u32 sync_reg;
3474a17c441SPierre-Louis Bossart 
3484a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
3494a17c441SPierre-Louis Bossart 
3504a17c441SPierre-Louis Bossart 	/*
3514a17c441SPierre-Louis Bossart 	 * The hardware relies on an internal counter, typically 4kHz,
3524a17c441SPierre-Louis Bossart 	 * to generate the SoundWire SSP - which defines a 'safe'
3534a17c441SPierre-Louis Bossart 	 * synchronization point between commands and audio transport
3544a17c441SPierre-Louis Bossart 	 * and allows for multi link synchronization. The SYNCPRD value
3554a17c441SPierre-Louis Bossart 	 * is only dependent on the oscillator clock provided to
3564a17c441SPierre-Louis Bossart 	 * the IP, so adjust based on _DSD properties reported in DSDT
3574a17c441SPierre-Louis Bossart 	 * tables. The values reported are based on either 24MHz
3584a17c441SPierre-Louis Bossart 	 * (CNL/CML) or 38.4 MHz (ICL/TGL+).
3594a17c441SPierre-Louis Bossart 	 */
3604a17c441SPierre-Louis Bossart 	if (prop->mclk_freq % 6000000)
3614a17c441SPierre-Louis Bossart 		syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
3624a17c441SPierre-Louis Bossart 	else
3634a17c441SPierre-Louis Bossart 		syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
3644a17c441SPierre-Louis Bossart 
3654a17c441SPierre-Louis Bossart 	if (!*shim_mask) {
3665ee74eb2SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev, "%s: powering up all links\n", __func__);
3675ee74eb2SPierre-Louis Bossart 
3684a17c441SPierre-Louis Bossart 		/* we first need to program the SyncPRD/CPU registers */
3694a17c441SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev,
3704a17c441SPierre-Louis Bossart 			"%s: first link up, programming SYNCPRD\n", __func__);
3714a17c441SPierre-Louis Bossart 
3724a17c441SPierre-Louis Bossart 		/* set SyncPRD period */
3734a17c441SPierre-Louis Bossart 		sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
374f067c925SVinod Koul 		u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD);
3754a17c441SPierre-Louis Bossart 
3764a17c441SPierre-Louis Bossart 		/* Set SyncCPU bit */
3774a17c441SPierre-Louis Bossart 		sync_reg |= SDW_SHIM_SYNC_SYNCCPU;
3784a17c441SPierre-Louis Bossart 		intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
37971bb8a1bSVinod Koul 
38071bb8a1bSVinod Koul 		/* Link power up sequence */
38171bb8a1bSVinod Koul 		link_control = intel_readl(shim, SDW_SHIM_LCTL);
3825ee74eb2SPierre-Louis Bossart 
3835ee74eb2SPierre-Louis Bossart 		/* only power-up enabled links */
3843b4979caSVinod Koul 		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask);
3853b4979caSVinod Koul 		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
3865ee74eb2SPierre-Louis Bossart 
38771bb8a1bSVinod Koul 		link_control |=  spa_mask;
38871bb8a1bSVinod Koul 
38971bb8a1bSVinod Koul 		ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
3904a17c441SPierre-Louis Bossart 		if (ret < 0) {
3914a17c441SPierre-Louis Bossart 			dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret);
3924a17c441SPierre-Louis Bossart 			goto out;
39371bb8a1bSVinod Koul 		}
39471bb8a1bSVinod Koul 
3954a17c441SPierre-Louis Bossart 		/* SyncCPU will change once link is active */
3964a17c441SPierre-Louis Bossart 		ret = intel_wait_bit(shim, SDW_SHIM_SYNC,
3974a17c441SPierre-Louis Bossart 				     SDW_SHIM_SYNC_SYNCCPU, 0);
3984a17c441SPierre-Louis Bossart 		if (ret < 0) {
3994a17c441SPierre-Louis Bossart 			dev_err(sdw->cdns.dev,
4004a17c441SPierre-Louis Bossart 				"Failed to set SHIM_SYNC: %d\n", ret);
4014a17c441SPierre-Louis Bossart 			goto out;
4024a17c441SPierre-Louis Bossart 		}
4034a17c441SPierre-Louis Bossart 	}
4044a17c441SPierre-Louis Bossart 
4054a17c441SPierre-Louis Bossart 	*shim_mask |= BIT(link_id);
4064a17c441SPierre-Louis Bossart 
4074a17c441SPierre-Louis Bossart 	sdw->cdns.link_up = true;
4084a17c441SPierre-Louis Bossart out:
4094a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
4104a17c441SPierre-Louis Bossart 
4114a17c441SPierre-Louis Bossart 	return ret;
4124a17c441SPierre-Louis Bossart }
4134a17c441SPierre-Louis Bossart 
4144a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */
4154a17c441SPierre-Louis Bossart static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw)
41671bb8a1bSVinod Koul {
4172523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
41871bb8a1bSVinod Koul 	unsigned int link_id = sdw->instance;
4194a17c441SPierre-Louis Bossart 	u16 ioctl;
42071bb8a1bSVinod Koul 
42171bb8a1bSVinod Koul 	/* Switch to MIP from Glue logic */
42271bb8a1bSVinod Koul 	ioctl = intel_readw(shim,  SDW_SHIM_IOCTL(link_id));
42371bb8a1bSVinod Koul 
42471bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_DOE);
42571bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4264a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
42771bb8a1bSVinod Koul 
42871bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_DO);
42971bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4304a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
43171bb8a1bSVinod Koul 
43271bb8a1bSVinod Koul 	ioctl |= (SDW_SHIM_IOCTL_MIF);
43371bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4344a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
43571bb8a1bSVinod Koul 
43671bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_BKE);
43771bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_COE);
43871bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4394a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4404a17c441SPierre-Louis Bossart 
4414a17c441SPierre-Louis Bossart 	/* at this point Master IP has full control of the I/Os */
4424a17c441SPierre-Louis Bossart }
4434a17c441SPierre-Louis Bossart 
4444a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */
4454a17c441SPierre-Louis Bossart static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw)
4464a17c441SPierre-Louis Bossart {
4474a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
4484a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
4494a17c441SPierre-Louis Bossart 	u16 ioctl;
4504a17c441SPierre-Louis Bossart 
4514a17c441SPierre-Louis Bossart 	/* Glue logic */
4524a17c441SPierre-Louis Bossart 	ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id));
4534a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_BKE;
4544a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_COE;
4554a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4564a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4574a17c441SPierre-Louis Bossart 
4584a17c441SPierre-Louis Bossart 	ioctl &= ~(SDW_SHIM_IOCTL_MIF);
4594a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4604a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4614a17c441SPierre-Louis Bossart 
4624a17c441SPierre-Louis Bossart 	/* at this point Integration Glue has full control of the I/Os */
4634a17c441SPierre-Louis Bossart }
4644a17c441SPierre-Louis Bossart 
4654a17c441SPierre-Louis Bossart static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop)
4664a17c441SPierre-Louis Bossart {
4674a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
4684a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
4694a17c441SPierre-Louis Bossart 	int ret = 0;
4704a17c441SPierre-Louis Bossart 	u16 ioctl = 0, act = 0;
4714a17c441SPierre-Louis Bossart 
4724a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
4734a17c441SPierre-Louis Bossart 
4744a17c441SPierre-Louis Bossart 	/* Initialize Shim */
4754a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_BKE;
4764a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4774a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4784a17c441SPierre-Louis Bossart 
4794a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_WPDD;
4804a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4814a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4824a17c441SPierre-Louis Bossart 
4834a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_DO;
4844a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4854a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4864a17c441SPierre-Louis Bossart 
4874a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_DOE;
4884a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
4894a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
4904a17c441SPierre-Louis Bossart 
4914a17c441SPierre-Louis Bossart 	intel_shim_glue_to_master_ip(sdw);
49271bb8a1bSVinod Koul 
493f067c925SVinod Koul 	u16p_replace_bits(&act, 0x1, SDW_SHIM_CTMCTL_DOAIS);
49471bb8a1bSVinod Koul 	act |= SDW_SHIM_CTMCTL_DACTQE;
49571bb8a1bSVinod Koul 	act |= SDW_SHIM_CTMCTL_DODS;
49671bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act);
4974a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
49871bb8a1bSVinod Koul 
4994a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
50071bb8a1bSVinod Koul 
50171bb8a1bSVinod Koul 	return ret;
50271bb8a1bSVinod Koul }
50371bb8a1bSVinod Koul 
504ab2c9132SRander Wang static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
5054a17c441SPierre-Louis Bossart {
5064a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
5074a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
5084a17c441SPierre-Louis Bossart 	u16 wake_en, wake_sts;
5094a17c441SPierre-Louis Bossart 
5104a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
5114a17c441SPierre-Louis Bossart 	wake_en = intel_readw(shim, SDW_SHIM_WAKEEN);
5124a17c441SPierre-Louis Bossart 
5134a17c441SPierre-Louis Bossart 	if (wake_enable) {
5144a17c441SPierre-Louis Bossart 		/* Enable the wakeup */
5154a17c441SPierre-Louis Bossart 		wake_en |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
5164a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
5174a17c441SPierre-Louis Bossart 	} else {
5184a17c441SPierre-Louis Bossart 		/* Disable the wake up interrupt */
5194a17c441SPierre-Louis Bossart 		wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id);
5204a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
5214a17c441SPierre-Louis Bossart 
5224a17c441SPierre-Louis Bossart 		/* Clear wake status */
5234a17c441SPierre-Louis Bossart 		wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
5244a17c441SPierre-Louis Bossart 		wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
5254a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts);
5264a17c441SPierre-Louis Bossart 	}
5274a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
5284a17c441SPierre-Louis Bossart }
5294a17c441SPierre-Louis Bossart 
5309b3b4b3fSPierre-Louis Bossart static int intel_link_power_down(struct sdw_intel *sdw)
5314a17c441SPierre-Louis Bossart {
5325ee74eb2SPierre-Louis Bossart 	u32 link_control, spa_mask, cpa_mask;
5334a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
5344a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
5354a17c441SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
5364a17c441SPierre-Louis Bossart 	int ret = 0;
5374a17c441SPierre-Louis Bossart 
5384a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
5394a17c441SPierre-Louis Bossart 
5404a17c441SPierre-Louis Bossart 	intel_shim_master_ip_to_glue(sdw);
5414a17c441SPierre-Louis Bossart 
5424a17c441SPierre-Louis Bossart 	if (!(*shim_mask & BIT(link_id)))
5434a17c441SPierre-Louis Bossart 		dev_err(sdw->cdns.dev,
5444a17c441SPierre-Louis Bossart 			"%s: Unbalanced power-up/down calls\n", __func__);
5454a17c441SPierre-Louis Bossart 
5464a17c441SPierre-Louis Bossart 	*shim_mask &= ~BIT(link_id);
5474a17c441SPierre-Louis Bossart 
5485ee74eb2SPierre-Louis Bossart 	if (!*shim_mask) {
5495ee74eb2SPierre-Louis Bossart 
5505ee74eb2SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev, "%s: powering down all links\n", __func__);
5515ee74eb2SPierre-Louis Bossart 
5525ee74eb2SPierre-Louis Bossart 		/* Link power down sequence */
5535ee74eb2SPierre-Louis Bossart 		link_control = intel_readl(shim, SDW_SHIM_LCTL);
5545ee74eb2SPierre-Louis Bossart 
5555ee74eb2SPierre-Louis Bossart 		/* only power-down enabled links */
5563b4979caSVinod Koul 		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, ~sdw->link_res->link_mask);
5573b4979caSVinod Koul 		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
5585ee74eb2SPierre-Louis Bossart 
5595ee74eb2SPierre-Louis Bossart 		link_control &=  spa_mask;
5605ee74eb2SPierre-Louis Bossart 
5615ee74eb2SPierre-Louis Bossart 		ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
5625ee74eb2SPierre-Louis Bossart 	}
5635ee74eb2SPierre-Louis Bossart 
5645ee74eb2SPierre-Louis Bossart 	link_control = intel_readl(shim, SDW_SHIM_LCTL);
5655ee74eb2SPierre-Louis Bossart 
5664a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
5674a17c441SPierre-Louis Bossart 
5685ee74eb2SPierre-Louis Bossart 	if (ret < 0) {
5695ee74eb2SPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__);
5705ee74eb2SPierre-Louis Bossart 
5714a17c441SPierre-Louis Bossart 		return ret;
5725ee74eb2SPierre-Louis Bossart 	}
5734a17c441SPierre-Louis Bossart 
5744a17c441SPierre-Louis Bossart 	sdw->cdns.link_up = false;
5754a17c441SPierre-Louis Bossart 	return 0;
5764a17c441SPierre-Louis Bossart }
5774a17c441SPierre-Louis Bossart 
57802629e45SPierre-Louis Bossart static void intel_shim_sync_arm(struct sdw_intel *sdw)
57902629e45SPierre-Louis Bossart {
58002629e45SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
58102629e45SPierre-Louis Bossart 	u32 sync_reg;
58202629e45SPierre-Louis Bossart 
58302629e45SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
58402629e45SPierre-Louis Bossart 
58502629e45SPierre-Louis Bossart 	/* update SYNC register */
58602629e45SPierre-Louis Bossart 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
58702629e45SPierre-Louis Bossart 	sync_reg |= (SDW_SHIM_SYNC_CMDSYNC << sdw->instance);
58802629e45SPierre-Louis Bossart 	intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
58902629e45SPierre-Louis Bossart 
59002629e45SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
59102629e45SPierre-Louis Bossart }
59202629e45SPierre-Louis Bossart 
593437e3289SPierre-Louis Bossart static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw)
594437e3289SPierre-Louis Bossart {
595437e3289SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
596437e3289SPierre-Louis Bossart 	u32 sync_reg;
597437e3289SPierre-Louis Bossart 	int ret;
598437e3289SPierre-Louis Bossart 
599437e3289SPierre-Louis Bossart 	/* Read SYNC register */
600437e3289SPierre-Louis Bossart 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
601437e3289SPierre-Louis Bossart 
602437e3289SPierre-Louis Bossart 	/*
603437e3289SPierre-Louis Bossart 	 * Set SyncGO bit to synchronously trigger a bank switch for
604437e3289SPierre-Louis Bossart 	 * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all
605437e3289SPierre-Louis Bossart 	 * the Masters.
606437e3289SPierre-Louis Bossart 	 */
607437e3289SPierre-Louis Bossart 	sync_reg |= SDW_SHIM_SYNC_SYNCGO;
608437e3289SPierre-Louis Bossart 
609437e3289SPierre-Louis Bossart 	ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg,
610437e3289SPierre-Louis Bossart 			      SDW_SHIM_SYNC_SYNCGO);
611437e3289SPierre-Louis Bossart 
612437e3289SPierre-Louis Bossart 	if (ret < 0)
613437e3289SPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "SyncGO clear failed: %d\n", ret);
61471bb8a1bSVinod Koul 
61571bb8a1bSVinod Koul 	return ret;
61671bb8a1bSVinod Koul }
61771bb8a1bSVinod Koul 
618857a7c42SPierre-Louis Bossart static int intel_shim_sync_go(struct sdw_intel *sdw)
619857a7c42SPierre-Louis Bossart {
620857a7c42SPierre-Louis Bossart 	int ret;
621857a7c42SPierre-Louis Bossart 
622857a7c42SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
623857a7c42SPierre-Louis Bossart 
624857a7c42SPierre-Louis Bossart 	ret = intel_shim_sync_go_unlocked(sdw);
625857a7c42SPierre-Louis Bossart 
626857a7c42SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
627857a7c42SPierre-Louis Bossart 
628857a7c42SPierre-Louis Bossart 	return ret;
629857a7c42SPierre-Louis Bossart }
630857a7c42SPierre-Louis Bossart 
63137a2d22bSVinod Koul /*
63237a2d22bSVinod Koul  * PDI routines
63337a2d22bSVinod Koul  */
63437a2d22bSVinod Koul static void intel_pdi_init(struct sdw_intel *sdw,
63537a2d22bSVinod Koul 			   struct sdw_cdns_stream_config *config)
63637a2d22bSVinod Koul {
6372523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
63837a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
63937a2d22bSVinod Koul 	int pcm_cap, pdm_cap;
64037a2d22bSVinod Koul 
64137a2d22bSVinod Koul 	/* PCM Stream Capability */
64237a2d22bSVinod Koul 	pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id));
64337a2d22bSVinod Koul 
6443b4979caSVinod Koul 	config->pcm_bd = FIELD_GET(SDW_SHIM_PCMSCAP_BSS, pcm_cap);
6453b4979caSVinod Koul 	config->pcm_in = FIELD_GET(SDW_SHIM_PCMSCAP_ISS, pcm_cap);
6463b4979caSVinod Koul 	config->pcm_out = FIELD_GET(SDW_SHIM_PCMSCAP_OSS, pcm_cap);
64737a2d22bSVinod Koul 
648121f4361SPierre-Louis Bossart 	dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
649121f4361SPierre-Louis Bossart 		config->pcm_bd, config->pcm_in, config->pcm_out);
650121f4361SPierre-Louis Bossart 
65137a2d22bSVinod Koul 	/* PDM Stream Capability */
65237a2d22bSVinod Koul 	pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
65337a2d22bSVinod Koul 
6543b4979caSVinod Koul 	config->pdm_bd = FIELD_GET(SDW_SHIM_PDMSCAP_BSS, pdm_cap);
6553b4979caSVinod Koul 	config->pdm_in = FIELD_GET(SDW_SHIM_PDMSCAP_ISS, pdm_cap);
6563b4979caSVinod Koul 	config->pdm_out = FIELD_GET(SDW_SHIM_PDMSCAP_OSS, pdm_cap);
657121f4361SPierre-Louis Bossart 
658121f4361SPierre-Louis Bossart 	dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n",
659121f4361SPierre-Louis Bossart 		config->pdm_bd, config->pdm_in, config->pdm_out);
66037a2d22bSVinod Koul }
66137a2d22bSVinod Koul 
66237a2d22bSVinod Koul static int
66337a2d22bSVinod Koul intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)
66437a2d22bSVinod Koul {
6652523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
66637a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
66737a2d22bSVinod Koul 	int count;
66837a2d22bSVinod Koul 
66937a2d22bSVinod Koul 	if (pcm) {
67037a2d22bSVinod Koul 		count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
67118046335SPierre-Louis Bossart 
67218046335SPierre-Louis Bossart 		/*
67318046335SPierre-Louis Bossart 		 * WORKAROUND: on all existing Intel controllers, pdi
67418046335SPierre-Louis Bossart 		 * number 2 reports channel count as 1 even though it
67518046335SPierre-Louis Bossart 		 * supports 8 channels. Performing hardcoding for pdi
67618046335SPierre-Louis Bossart 		 * number 2.
67718046335SPierre-Louis Bossart 		 */
67818046335SPierre-Louis Bossart 		if (pdi_num == 2)
67918046335SPierre-Louis Bossart 			count = 7;
68018046335SPierre-Louis Bossart 
68137a2d22bSVinod Koul 	} else {
68237a2d22bSVinod Koul 		count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
6833b4979caSVinod Koul 		count = FIELD_GET(SDW_SHIM_PDMSCAP_CPSS, count);
68437a2d22bSVinod Koul 	}
68537a2d22bSVinod Koul 
68637a2d22bSVinod Koul 	/* zero based values for channel count in register */
68737a2d22bSVinod Koul 	count++;
68837a2d22bSVinod Koul 
68937a2d22bSVinod Koul 	return count;
69037a2d22bSVinod Koul }
69137a2d22bSVinod Koul 
69237a2d22bSVinod Koul static int intel_pdi_get_ch_update(struct sdw_intel *sdw,
69337a2d22bSVinod Koul 				   struct sdw_cdns_pdi *pdi,
69437a2d22bSVinod Koul 				   unsigned int num_pdi,
69537a2d22bSVinod Koul 				   unsigned int *num_ch, bool pcm)
69637a2d22bSVinod Koul {
69737a2d22bSVinod Koul 	int i, ch_count = 0;
69837a2d22bSVinod Koul 
69937a2d22bSVinod Koul 	for (i = 0; i < num_pdi; i++) {
70037a2d22bSVinod Koul 		pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm);
70137a2d22bSVinod Koul 		ch_count += pdi->ch_count;
70237a2d22bSVinod Koul 		pdi++;
70337a2d22bSVinod Koul 	}
70437a2d22bSVinod Koul 
70537a2d22bSVinod Koul 	*num_ch = ch_count;
70637a2d22bSVinod Koul 	return 0;
70737a2d22bSVinod Koul }
70837a2d22bSVinod Koul 
70937a2d22bSVinod Koul static int intel_pdi_stream_ch_update(struct sdw_intel *sdw,
71037a2d22bSVinod Koul 				      struct sdw_cdns_streams *stream, bool pcm)
71137a2d22bSVinod Koul {
71237a2d22bSVinod Koul 	intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
71337a2d22bSVinod Koul 				&stream->num_ch_bd, pcm);
71437a2d22bSVinod Koul 
71537a2d22bSVinod Koul 	intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
71637a2d22bSVinod Koul 				&stream->num_ch_in, pcm);
71737a2d22bSVinod Koul 
71837a2d22bSVinod Koul 	intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
71937a2d22bSVinod Koul 				&stream->num_ch_out, pcm);
72037a2d22bSVinod Koul 
72137a2d22bSVinod Koul 	return 0;
72237a2d22bSVinod Koul }
72337a2d22bSVinod Koul 
72437a2d22bSVinod Koul static int intel_pdi_ch_update(struct sdw_intel *sdw)
72537a2d22bSVinod Koul {
72637a2d22bSVinod Koul 	/* First update PCM streams followed by PDM streams */
72737a2d22bSVinod Koul 	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true);
72837a2d22bSVinod Koul 	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false);
72937a2d22bSVinod Koul 
73037a2d22bSVinod Koul 	return 0;
73137a2d22bSVinod Koul }
73237a2d22bSVinod Koul 
73337a2d22bSVinod Koul static void
73437a2d22bSVinod Koul intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
73537a2d22bSVinod Koul {
7362523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
73737a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
73837a2d22bSVinod Koul 	int pdi_conf = 0;
73937a2d22bSVinod Koul 
740c134f914SPierre-Louis Bossart 	/* the Bulk and PCM streams are not contiguous */
741c134f914SPierre-Louis Bossart 	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
742c134f914SPierre-Louis Bossart 	if (pdi->num >= 2)
743c134f914SPierre-Louis Bossart 		pdi->intel_alh_id += 2;
74437a2d22bSVinod Koul 
74537a2d22bSVinod Koul 	/*
74637a2d22bSVinod Koul 	 * Program stream parameters to stream SHIM register
74737a2d22bSVinod Koul 	 * This is applicable for PCM stream only.
74837a2d22bSVinod Koul 	 */
74937a2d22bSVinod Koul 	if (pdi->type != SDW_STREAM_PCM)
75037a2d22bSVinod Koul 		return;
75137a2d22bSVinod Koul 
75237a2d22bSVinod Koul 	if (pdi->dir == SDW_DATA_DIR_RX)
75337a2d22bSVinod Koul 		pdi_conf |= SDW_SHIM_PCMSYCM_DIR;
75437a2d22bSVinod Koul 	else
75537a2d22bSVinod Koul 		pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR);
75637a2d22bSVinod Koul 
757f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->intel_alh_id, SDW_SHIM_PCMSYCM_STREAM);
758f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->l_ch_num, SDW_SHIM_PCMSYCM_LCHN);
759f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->h_ch_num, SDW_SHIM_PCMSYCM_HCHN);
76037a2d22bSVinod Koul 
76137a2d22bSVinod Koul 	intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf);
76237a2d22bSVinod Koul }
76337a2d22bSVinod Koul 
76437a2d22bSVinod Koul static void
76537a2d22bSVinod Koul intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
76637a2d22bSVinod Koul {
7672523486bSPierre-Louis Bossart 	void __iomem *alh = sdw->link_res->alh;
76837a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
76937a2d22bSVinod Koul 	unsigned int conf;
77037a2d22bSVinod Koul 
771c134f914SPierre-Louis Bossart 	/* the Bulk and PCM streams are not contiguous */
772c134f914SPierre-Louis Bossart 	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
773c134f914SPierre-Louis Bossart 	if (pdi->num >= 2)
774c134f914SPierre-Louis Bossart 		pdi->intel_alh_id += 2;
77537a2d22bSVinod Koul 
77637a2d22bSVinod Koul 	/* Program Stream config ALH register */
77737a2d22bSVinod Koul 	conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
77837a2d22bSVinod Koul 
779f067c925SVinod Koul 	u32p_replace_bits(&conf, SDW_ALH_STRMZCFG_DMAT_VAL, SDW_ALH_STRMZCFG_DMAT);
780f067c925SVinod Koul 	u32p_replace_bits(&conf, pdi->ch_count - 1, SDW_ALH_STRMZCFG_CHN);
78137a2d22bSVinod Koul 
78237a2d22bSVinod Koul 	intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);
78337a2d22bSVinod Koul }
78437a2d22bSVinod Koul 
7854b206d34SRander Wang static int intel_params_stream(struct sdw_intel *sdw,
786c46302ecSVinod Koul 			       struct snd_pcm_substream *substream,
787c46302ecSVinod Koul 			       struct snd_soc_dai *dai,
7884b206d34SRander Wang 			       struct snd_pcm_hw_params *hw_params,
7894b206d34SRander Wang 			       int link_id, int alh_stream_id)
790c46302ecSVinod Koul {
7912523486bSPierre-Louis Bossart 	struct sdw_intel_link_res *res = sdw->link_res;
7924b206d34SRander Wang 	struct sdw_intel_stream_params_data params_data;
79305c8afe4SPierre-Louis Bossart 
7944b206d34SRander Wang 	params_data.substream = substream;
7954b206d34SRander Wang 	params_data.dai = dai;
7964b206d34SRander Wang 	params_data.hw_params = hw_params;
7974b206d34SRander Wang 	params_data.link_id = link_id;
7984b206d34SRander Wang 	params_data.alh_stream_id = alh_stream_id;
799c46302ecSVinod Koul 
8004b206d34SRander Wang 	if (res->ops && res->ops->params_stream && res->dev)
8014b206d34SRander Wang 		return res->ops->params_stream(res->dev,
8024b206d34SRander Wang 					       &params_data);
803c46302ecSVinod Koul 	return -EIO;
804c46302ecSVinod Koul }
805c46302ecSVinod Koul 
806eff346f2SPierre-Louis Bossart static int intel_free_stream(struct sdw_intel *sdw,
807eff346f2SPierre-Louis Bossart 			     struct snd_pcm_substream *substream,
808eff346f2SPierre-Louis Bossart 			     struct snd_soc_dai *dai,
809eff346f2SPierre-Louis Bossart 			     int link_id)
810eff346f2SPierre-Louis Bossart {
811eff346f2SPierre-Louis Bossart 	struct sdw_intel_link_res *res = sdw->link_res;
812eff346f2SPierre-Louis Bossart 	struct sdw_intel_stream_free_data free_data;
813eff346f2SPierre-Louis Bossart 
814eff346f2SPierre-Louis Bossart 	free_data.substream = substream;
815eff346f2SPierre-Louis Bossart 	free_data.dai = dai;
816eff346f2SPierre-Louis Bossart 	free_data.link_id = link_id;
817eff346f2SPierre-Louis Bossart 
818eff346f2SPierre-Louis Bossart 	if (res->ops && res->ops->free_stream && res->dev)
819eff346f2SPierre-Louis Bossart 		return res->ops->free_stream(res->dev,
820eff346f2SPierre-Louis Bossart 					     &free_data);
821eff346f2SPierre-Louis Bossart 
822eff346f2SPierre-Louis Bossart 	return 0;
823eff346f2SPierre-Louis Bossart }
824eff346f2SPierre-Louis Bossart 
825c46302ecSVinod Koul /*
82630246e2dSShreyas NC  * bank switch routines
82730246e2dSShreyas NC  */
82830246e2dSShreyas NC 
82930246e2dSShreyas NC static int intel_pre_bank_switch(struct sdw_bus *bus)
83030246e2dSShreyas NC {
83130246e2dSShreyas NC 	struct sdw_cdns *cdns = bus_to_cdns(bus);
83230246e2dSShreyas NC 	struct sdw_intel *sdw = cdns_to_intel(cdns);
83330246e2dSShreyas NC 
83430246e2dSShreyas NC 	/* Write to register only for multi-link */
83530246e2dSShreyas NC 	if (!bus->multi_link)
83630246e2dSShreyas NC 		return 0;
83730246e2dSShreyas NC 
83802629e45SPierre-Louis Bossart 	intel_shim_sync_arm(sdw);
83930246e2dSShreyas NC 
84030246e2dSShreyas NC 	return 0;
84130246e2dSShreyas NC }
84230246e2dSShreyas NC 
84330246e2dSShreyas NC static int intel_post_bank_switch(struct sdw_bus *bus)
84430246e2dSShreyas NC {
84530246e2dSShreyas NC 	struct sdw_cdns *cdns = bus_to_cdns(bus);
84630246e2dSShreyas NC 	struct sdw_intel *sdw = cdns_to_intel(cdns);
8472523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
84830246e2dSShreyas NC 	int sync_reg, ret;
84930246e2dSShreyas NC 
85030246e2dSShreyas NC 	/* Write to register only for multi-link */
85130246e2dSShreyas NC 	if (!bus->multi_link)
85230246e2dSShreyas NC 		return 0;
85330246e2dSShreyas NC 
8544a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
8554a17c441SPierre-Louis Bossart 
85630246e2dSShreyas NC 	/* Read SYNC register */
85730246e2dSShreyas NC 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
85830246e2dSShreyas NC 
85930246e2dSShreyas NC 	/*
86030246e2dSShreyas NC 	 * post_bank_switch() ops is called from the bus in loop for
86130246e2dSShreyas NC 	 * all the Masters in the steam with the expectation that
86230246e2dSShreyas NC 	 * we trigger the bankswitch for the only first Master in the list
86330246e2dSShreyas NC 	 * and do nothing for the other Masters
86430246e2dSShreyas NC 	 *
86530246e2dSShreyas NC 	 * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.
86630246e2dSShreyas NC 	 */
8674a17c441SPierre-Louis Bossart 	if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) {
8684a17c441SPierre-Louis Bossart 		ret = 0;
8694a17c441SPierre-Louis Bossart 		goto unlock;
8704a17c441SPierre-Louis Bossart 	}
87130246e2dSShreyas NC 
872437e3289SPierre-Louis Bossart 	ret = intel_shim_sync_go_unlocked(sdw);
8734a17c441SPierre-Louis Bossart unlock:
8744a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
87530246e2dSShreyas NC 
87630246e2dSShreyas NC 	if (ret < 0)
87717ed5befSPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret);
87830246e2dSShreyas NC 
87930246e2dSShreyas NC 	return ret;
88030246e2dSShreyas NC }
88130246e2dSShreyas NC 
88230246e2dSShreyas NC /*
883c46302ecSVinod Koul  * DAI routines
884c46302ecSVinod Koul  */
885c46302ecSVinod Koul 
8865e7484d0SRander Wang static int intel_startup(struct snd_pcm_substream *substream,
8875e7484d0SRander Wang 			 struct snd_soc_dai *dai)
8885e7484d0SRander Wang {
889ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
890ebf878edSPierre-Louis Bossart 	int ret;
891ebf878edSPierre-Louis Bossart 
892ebf878edSPierre-Louis Bossart 	ret = pm_runtime_get_sync(cdns->dev);
893ebf878edSPierre-Louis Bossart 	if (ret < 0 && ret != -EACCES) {
894ebf878edSPierre-Louis Bossart 		dev_err_ratelimited(cdns->dev,
895ebf878edSPierre-Louis Bossart 				    "pm_runtime_get_sync failed in %s, ret %d\n",
896ebf878edSPierre-Louis Bossart 				    __func__, ret);
897ebf878edSPierre-Louis Bossart 		pm_runtime_put_noidle(cdns->dev);
898ebf878edSPierre-Louis Bossart 		return ret;
899ebf878edSPierre-Louis Bossart 	}
900ff16d1e5SPierre-Louis Bossart 	return 0;
9015e7484d0SRander Wang }
9025e7484d0SRander Wang 
903c46302ecSVinod Koul static int intel_hw_params(struct snd_pcm_substream *substream,
904c46302ecSVinod Koul 			   struct snd_pcm_hw_params *params,
905c46302ecSVinod Koul 			   struct snd_soc_dai *dai)
906c46302ecSVinod Koul {
907c46302ecSVinod Koul 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
908c46302ecSVinod Koul 	struct sdw_intel *sdw = cdns_to_intel(cdns);
909c46302ecSVinod Koul 	struct sdw_cdns_dma_data *dma;
91057a34790SPierre-Louis Bossart 	struct sdw_cdns_pdi *pdi;
911c46302ecSVinod Koul 	struct sdw_stream_config sconfig;
912c46302ecSVinod Koul 	struct sdw_port_config *pconfig;
91357a34790SPierre-Louis Bossart 	int ch, dir;
91457a34790SPierre-Louis Bossart 	int ret;
915c46302ecSVinod Koul 	bool pcm = true;
916c46302ecSVinod Koul 
917c46302ecSVinod Koul 	dma = snd_soc_dai_get_dma_data(dai, substream);
918c46302ecSVinod Koul 	if (!dma)
919c46302ecSVinod Koul 		return -EIO;
920c46302ecSVinod Koul 
921c46302ecSVinod Koul 	ch = params_channels(params);
922c46302ecSVinod Koul 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
923c46302ecSVinod Koul 		dir = SDW_DATA_DIR_RX;
924c46302ecSVinod Koul 	else
925c46302ecSVinod Koul 		dir = SDW_DATA_DIR_TX;
926c46302ecSVinod Koul 
92757a34790SPierre-Louis Bossart 	if (dma->stream_type == SDW_STREAM_PDM)
928c46302ecSVinod Koul 		pcm = false;
929c46302ecSVinod Koul 
93057a34790SPierre-Louis Bossart 	if (pcm)
9311b53385eSBard Liao 		pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
93257a34790SPierre-Louis Bossart 	else
9331b53385eSBard Liao 		pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id);
934c46302ecSVinod Koul 
93557a34790SPierre-Louis Bossart 	if (!pdi) {
936c46302ecSVinod Koul 		ret = -EINVAL;
93757a34790SPierre-Louis Bossart 		goto error;
938c46302ecSVinod Koul 	}
93957a34790SPierre-Louis Bossart 
94057a34790SPierre-Louis Bossart 	/* do run-time configurations for SHIM, ALH and PDI/PORT */
94157a34790SPierre-Louis Bossart 	intel_pdi_shim_configure(sdw, pdi);
94257a34790SPierre-Louis Bossart 	intel_pdi_alh_configure(sdw, pdi);
94357a34790SPierre-Louis Bossart 	sdw_cdns_config_stream(cdns, ch, dir, pdi);
94457a34790SPierre-Louis Bossart 
945a5a0239cSBard Liao 	/* store pdi and hw_params, may be needed in prepare step */
946a5a0239cSBard Liao 	dma->suspended = false;
947a5a0239cSBard Liao 	dma->pdi = pdi;
948a5a0239cSBard Liao 	dma->hw_params = params;
949c46302ecSVinod Koul 
950c46302ecSVinod Koul 	/* Inform DSP about PDI stream number */
9514b206d34SRander Wang 	ret = intel_params_stream(sdw, substream, dai, params,
9524b206d34SRander Wang 				  sdw->instance,
95357a34790SPierre-Louis Bossart 				  pdi->intel_alh_id);
954c46302ecSVinod Koul 	if (ret)
95557a34790SPierre-Louis Bossart 		goto error;
956c46302ecSVinod Koul 
957c46302ecSVinod Koul 	sconfig.direction = dir;
958c46302ecSVinod Koul 	sconfig.ch_count = ch;
959c46302ecSVinod Koul 	sconfig.frame_rate = params_rate(params);
960c46302ecSVinod Koul 	sconfig.type = dma->stream_type;
961c46302ecSVinod Koul 
962c46302ecSVinod Koul 	if (dma->stream_type == SDW_STREAM_PDM) {
963c46302ecSVinod Koul 		sconfig.frame_rate *= 50;
964c46302ecSVinod Koul 		sconfig.bps = 1;
965c46302ecSVinod Koul 	} else {
966c46302ecSVinod Koul 		sconfig.bps = snd_pcm_format_width(params_format(params));
967c46302ecSVinod Koul 	}
968c46302ecSVinod Koul 
969c46302ecSVinod Koul 	/* Port configuration */
97057a34790SPierre-Louis Bossart 	pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL);
971c46302ecSVinod Koul 	if (!pconfig) {
972c46302ecSVinod Koul 		ret =  -ENOMEM;
97357a34790SPierre-Louis Bossart 		goto error;
974c46302ecSVinod Koul 	}
975c46302ecSVinod Koul 
97657a34790SPierre-Louis Bossart 	pconfig->num = pdi->num;
97757a34790SPierre-Louis Bossart 	pconfig->ch_mask = (1 << ch) - 1;
978c46302ecSVinod Koul 
979c46302ecSVinod Koul 	ret = sdw_stream_add_master(&cdns->bus, &sconfig,
98057a34790SPierre-Louis Bossart 				    pconfig, 1, dma->stream);
98157a34790SPierre-Louis Bossart 	if (ret)
98217ed5befSPierre-Louis Bossart 		dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
983c46302ecSVinod Koul 
984c46302ecSVinod Koul 	kfree(pconfig);
98557a34790SPierre-Louis Bossart error:
986c46302ecSVinod Koul 	return ret;
987c46302ecSVinod Koul }
988c46302ecSVinod Koul 
98927b198f4SRander Wang static int intel_prepare(struct snd_pcm_substream *substream,
99027b198f4SRander Wang 			 struct snd_soc_dai *dai)
99127b198f4SRander Wang {
992a5a0239cSBard Liao 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
993a5a0239cSBard Liao 	struct sdw_intel *sdw = cdns_to_intel(cdns);
99427b198f4SRander Wang 	struct sdw_cdns_dma_data *dma;
995a5a0239cSBard Liao 	int ch, dir;
996244eb888SPierre-Louis Bossart 	int ret = 0;
99727b198f4SRander Wang 
99827b198f4SRander Wang 	dma = snd_soc_dai_get_dma_data(dai, substream);
99927b198f4SRander Wang 	if (!dma) {
100027b198f4SRander Wang 		dev_err(dai->dev, "failed to get dma data in %s",
100127b198f4SRander Wang 			__func__);
100227b198f4SRander Wang 		return -EIO;
100327b198f4SRander Wang 	}
100427b198f4SRander Wang 
1005a5a0239cSBard Liao 	if (dma->suspended) {
1006a5a0239cSBard Liao 		dma->suspended = false;
1007a5a0239cSBard Liao 
1008a5a0239cSBard Liao 		/*
1009a5a0239cSBard Liao 		 * .prepare() is called after system resume, where we
1010a5a0239cSBard Liao 		 * need to reinitialize the SHIM/ALH/Cadence IP.
1011a5a0239cSBard Liao 		 * .prepare() is also called to deal with underflows,
1012a5a0239cSBard Liao 		 * but in those cases we cannot touch ALH/SHIM
1013a5a0239cSBard Liao 		 * registers
1014a5a0239cSBard Liao 		 */
1015a5a0239cSBard Liao 
1016a5a0239cSBard Liao 		/* configure stream */
1017a5a0239cSBard Liao 		ch = params_channels(dma->hw_params);
1018a5a0239cSBard Liao 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1019a5a0239cSBard Liao 			dir = SDW_DATA_DIR_RX;
1020a5a0239cSBard Liao 		else
1021a5a0239cSBard Liao 			dir = SDW_DATA_DIR_TX;
1022a5a0239cSBard Liao 
1023a5a0239cSBard Liao 		intel_pdi_shim_configure(sdw, dma->pdi);
1024a5a0239cSBard Liao 		intel_pdi_alh_configure(sdw, dma->pdi);
1025a5a0239cSBard Liao 		sdw_cdns_config_stream(cdns, ch, dir, dma->pdi);
1026a5a0239cSBard Liao 
1027a5a0239cSBard Liao 		/* Inform DSP about PDI stream number */
1028a5a0239cSBard Liao 		ret = intel_params_stream(sdw, substream, dai,
1029a5a0239cSBard Liao 					  dma->hw_params,
1030a5a0239cSBard Liao 					  sdw->instance,
1031a5a0239cSBard Liao 					  dma->pdi->intel_alh_id);
1032a5a0239cSBard Liao 	}
1033a5a0239cSBard Liao 
1034a5a0239cSBard Liao 	return ret;
103527b198f4SRander Wang }
103627b198f4SRander Wang 
1037c46302ecSVinod Koul static int
1038c46302ecSVinod Koul intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
1039c46302ecSVinod Koul {
1040c46302ecSVinod Koul 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
1041eff346f2SPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
1042c46302ecSVinod Koul 	struct sdw_cdns_dma_data *dma;
1043c46302ecSVinod Koul 	int ret;
1044c46302ecSVinod Koul 
1045c46302ecSVinod Koul 	dma = snd_soc_dai_get_dma_data(dai, substream);
1046c46302ecSVinod Koul 	if (!dma)
1047c46302ecSVinod Koul 		return -EIO;
1048c46302ecSVinod Koul 
1049244eb888SPierre-Louis Bossart 	/*
1050244eb888SPierre-Louis Bossart 	 * The sdw stream state will transition to RELEASED when stream->
1051244eb888SPierre-Louis Bossart 	 * master_list is empty. So the stream state will transition to
1052244eb888SPierre-Louis Bossart 	 * DEPREPARED for the first cpu-dai and to RELEASED for the last
1053244eb888SPierre-Louis Bossart 	 * cpu-dai.
1054244eb888SPierre-Louis Bossart 	 */
1055c46302ecSVinod Koul 	ret = sdw_stream_remove_master(&cdns->bus, dma->stream);
1056eff346f2SPierre-Louis Bossart 	if (ret < 0) {
105717ed5befSPierre-Louis Bossart 		dev_err(dai->dev, "remove master from stream %s failed: %d\n",
1058c46302ecSVinod Koul 			dma->stream->name, ret);
1059c46302ecSVinod Koul 		return ret;
1060c46302ecSVinod Koul 	}
1061c46302ecSVinod Koul 
1062eff346f2SPierre-Louis Bossart 	ret = intel_free_stream(sdw, substream, dai, sdw->instance);
1063eff346f2SPierre-Louis Bossart 	if (ret < 0) {
1064eff346f2SPierre-Louis Bossart 		dev_err(dai->dev, "intel_free_stream: failed %d", ret);
1065eff346f2SPierre-Louis Bossart 		return ret;
1066eff346f2SPierre-Louis Bossart 	}
1067eff346f2SPierre-Louis Bossart 
1068a5a0239cSBard Liao 	dma->hw_params = NULL;
1069a5a0239cSBard Liao 	dma->pdi = NULL;
1070a5a0239cSBard Liao 
1071eff346f2SPierre-Louis Bossart 	return 0;
1072eff346f2SPierre-Louis Bossart }
1073eff346f2SPierre-Louis Bossart 
1074183c7687SPierre-Louis Bossart static void intel_shutdown(struct snd_pcm_substream *substream,
1075183c7687SPierre-Louis Bossart 			   struct snd_soc_dai *dai)
1076183c7687SPierre-Louis Bossart {
1077ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
1078183c7687SPierre-Louis Bossart 
1079ebf878edSPierre-Louis Bossart 	pm_runtime_mark_last_busy(cdns->dev);
1080ebf878edSPierre-Louis Bossart 	pm_runtime_put_autosuspend(cdns->dev);
1081183c7687SPierre-Louis Bossart }
1082183c7687SPierre-Louis Bossart 
1083a5a0239cSBard Liao static int intel_component_dais_suspend(struct snd_soc_component *component)
1084a5a0239cSBard Liao {
1085a5a0239cSBard Liao 	struct sdw_cdns_dma_data *dma;
1086a5a0239cSBard Liao 	struct snd_soc_dai *dai;
1087a5a0239cSBard Liao 
1088a5a0239cSBard Liao 	for_each_component_dais(component, dai) {
1089a5a0239cSBard Liao 		/*
1090a5a0239cSBard Liao 		 * we don't have a .suspend dai_ops, and we don't have access
1091a5a0239cSBard Liao 		 * to the substream, so let's mark both capture and playback
1092a5a0239cSBard Liao 		 * DMA contexts as suspended
1093a5a0239cSBard Liao 		 */
1094a5a0239cSBard Liao 		dma = dai->playback_dma_data;
1095a5a0239cSBard Liao 		if (dma)
1096a5a0239cSBard Liao 			dma->suspended = true;
1097a5a0239cSBard Liao 
1098a5a0239cSBard Liao 		dma = dai->capture_dma_data;
1099a5a0239cSBard Liao 		if (dma)
1100a5a0239cSBard Liao 			dma->suspended = true;
1101a5a0239cSBard Liao 	}
1102a5a0239cSBard Liao 
1103a5a0239cSBard Liao 	return 0;
1104a5a0239cSBard Liao }
1105a5a0239cSBard Liao 
1106c46302ecSVinod Koul static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
1107c46302ecSVinod Koul 				    void *stream, int direction)
1108c46302ecSVinod Koul {
1109c46302ecSVinod Koul 	return cdns_set_sdw_stream(dai, stream, true, direction);
1110c46302ecSVinod Koul }
1111c46302ecSVinod Koul 
1112c46302ecSVinod Koul static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai,
1113c46302ecSVinod Koul 				    void *stream, int direction)
1114c46302ecSVinod Koul {
1115c46302ecSVinod Koul 	return cdns_set_sdw_stream(dai, stream, false, direction);
1116c46302ecSVinod Koul }
1117c46302ecSVinod Koul 
111809553140SPierre-Louis Bossart static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
111909553140SPierre-Louis Bossart 				  int direction)
112009553140SPierre-Louis Bossart {
112109553140SPierre-Louis Bossart 	struct sdw_cdns_dma_data *dma;
112209553140SPierre-Louis Bossart 
112309553140SPierre-Louis Bossart 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
112409553140SPierre-Louis Bossart 		dma = dai->playback_dma_data;
112509553140SPierre-Louis Bossart 	else
112609553140SPierre-Louis Bossart 		dma = dai->capture_dma_data;
112709553140SPierre-Louis Bossart 
112809553140SPierre-Louis Bossart 	if (!dma)
112906dcb4e4SPierre-Louis Bossart 		return ERR_PTR(-EINVAL);
113009553140SPierre-Louis Bossart 
113109553140SPierre-Louis Bossart 	return dma->stream;
113209553140SPierre-Louis Bossart }
113309553140SPierre-Louis Bossart 
1134b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
11355e7484d0SRander Wang 	.startup = intel_startup,
1136c46302ecSVinod Koul 	.hw_params = intel_hw_params,
113727b198f4SRander Wang 	.prepare = intel_prepare,
1138c46302ecSVinod Koul 	.hw_free = intel_hw_free,
1139183c7687SPierre-Louis Bossart 	.shutdown = intel_shutdown,
1140c46302ecSVinod Koul 	.set_sdw_stream = intel_pcm_set_sdw_stream,
114109553140SPierre-Louis Bossart 	.get_sdw_stream = intel_get_sdw_stream,
1142c46302ecSVinod Koul };
1143c46302ecSVinod Koul 
1144b1635596SJulia Lawall static const struct snd_soc_dai_ops intel_pdm_dai_ops = {
11455e7484d0SRander Wang 	.startup = intel_startup,
1146c46302ecSVinod Koul 	.hw_params = intel_hw_params,
114727b198f4SRander Wang 	.prepare = intel_prepare,
1148c46302ecSVinod Koul 	.hw_free = intel_hw_free,
1149183c7687SPierre-Louis Bossart 	.shutdown = intel_shutdown,
1150c46302ecSVinod Koul 	.set_sdw_stream = intel_pdm_set_sdw_stream,
115109553140SPierre-Louis Bossart 	.get_sdw_stream = intel_get_sdw_stream,
1152c46302ecSVinod Koul };
1153c46302ecSVinod Koul 
1154c46302ecSVinod Koul static const struct snd_soc_component_driver dai_component = {
1155c46302ecSVinod Koul 	.name           = "soundwire",
1156a5a0239cSBard Liao 	.suspend	= intel_component_dais_suspend
1157c46302ecSVinod Koul };
1158c46302ecSVinod Koul 
1159c46302ecSVinod Koul static int intel_create_dai(struct sdw_cdns *cdns,
1160c46302ecSVinod Koul 			    struct snd_soc_dai_driver *dais,
1161c46302ecSVinod Koul 			    enum intel_pdi_type type,
1162c46302ecSVinod Koul 			    u32 num, u32 off, u32 max_ch, bool pcm)
1163c46302ecSVinod Koul {
1164c46302ecSVinod Koul 	int i;
1165c46302ecSVinod Koul 
1166c46302ecSVinod Koul 	if (num == 0)
1167c46302ecSVinod Koul 		return 0;
1168c46302ecSVinod Koul 
1169c46302ecSVinod Koul 	 /* TODO: Read supported rates/formats from hardware */
1170c46302ecSVinod Koul 	for (i = off; i < (off + num); i++) {
1171bf6d6e68SPierre-Louis Bossart 		dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
1172bf6d6e68SPierre-Louis Bossart 					      "SDW%d Pin%d",
1173c46302ecSVinod Koul 					      cdns->instance, i);
1174c46302ecSVinod Koul 		if (!dais[i].name)
1175c46302ecSVinod Koul 			return -ENOMEM;
1176c46302ecSVinod Koul 
1177c46302ecSVinod Koul 		if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
1178c46302ecSVinod Koul 			dais[i].playback.channels_min = 1;
1179c46302ecSVinod Koul 			dais[i].playback.channels_max = max_ch;
1180c46302ecSVinod Koul 			dais[i].playback.rates = SNDRV_PCM_RATE_48000;
1181c46302ecSVinod Koul 			dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
1182c46302ecSVinod Koul 		}
1183c46302ecSVinod Koul 
1184c46302ecSVinod Koul 		if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
118539194128SSrinivas Kandagatla 			dais[i].capture.channels_min = 1;
118639194128SSrinivas Kandagatla 			dais[i].capture.channels_max = max_ch;
1187c46302ecSVinod Koul 			dais[i].capture.rates = SNDRV_PCM_RATE_48000;
1188c46302ecSVinod Koul 			dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
1189c46302ecSVinod Koul 		}
1190c46302ecSVinod Koul 
1191c46302ecSVinod Koul 		if (pcm)
1192c46302ecSVinod Koul 			dais[i].ops = &intel_pcm_dai_ops;
1193c46302ecSVinod Koul 		else
1194c46302ecSVinod Koul 			dais[i].ops = &intel_pdm_dai_ops;
1195c46302ecSVinod Koul 	}
1196c46302ecSVinod Koul 
1197c46302ecSVinod Koul 	return 0;
1198c46302ecSVinod Koul }
1199c46302ecSVinod Koul 
1200c46302ecSVinod Koul static int intel_register_dai(struct sdw_intel *sdw)
1201c46302ecSVinod Koul {
1202c46302ecSVinod Koul 	struct sdw_cdns *cdns = &sdw->cdns;
1203c46302ecSVinod Koul 	struct sdw_cdns_streams *stream;
1204c46302ecSVinod Koul 	struct snd_soc_dai_driver *dais;
1205c46302ecSVinod Koul 	int num_dai, ret, off = 0;
1206c46302ecSVinod Koul 
1207c46302ecSVinod Koul 	/* DAIs are created based on total number of PDIs supported */
1208c46302ecSVinod Koul 	num_dai = cdns->pcm.num_pdi + cdns->pdm.num_pdi;
1209c46302ecSVinod Koul 
1210c46302ecSVinod Koul 	dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
1211c46302ecSVinod Koul 	if (!dais)
1212c46302ecSVinod Koul 		return -ENOMEM;
1213c46302ecSVinod Koul 
1214c46302ecSVinod Koul 	/* Create PCM DAIs */
1215c46302ecSVinod Koul 	stream = &cdns->pcm;
1216c46302ecSVinod Koul 
1217cf924962SBard Liao 	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
12181215daeeSVinod Koul 			       off, stream->num_ch_in, true);
1219c46302ecSVinod Koul 	if (ret)
1220c46302ecSVinod Koul 		return ret;
1221c46302ecSVinod Koul 
1222c46302ecSVinod Koul 	off += cdns->pcm.num_in;
12231215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
12241215daeeSVinod Koul 			       off, stream->num_ch_out, true);
1225c46302ecSVinod Koul 	if (ret)
1226c46302ecSVinod Koul 		return ret;
1227c46302ecSVinod Koul 
1228c46302ecSVinod Koul 	off += cdns->pcm.num_out;
12291215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
12301215daeeSVinod Koul 			       off, stream->num_ch_bd, true);
1231c46302ecSVinod Koul 	if (ret)
1232c46302ecSVinod Koul 		return ret;
1233c46302ecSVinod Koul 
1234c46302ecSVinod Koul 	/* Create PDM DAIs */
1235c46302ecSVinod Koul 	stream = &cdns->pdm;
1236c46302ecSVinod Koul 	off += cdns->pcm.num_bd;
12371215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pdm.num_in,
12381215daeeSVinod Koul 			       off, stream->num_ch_in, false);
1239c46302ecSVinod Koul 	if (ret)
1240c46302ecSVinod Koul 		return ret;
1241c46302ecSVinod Koul 
1242c46302ecSVinod Koul 	off += cdns->pdm.num_in;
12431215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pdm.num_out,
12441215daeeSVinod Koul 			       off, stream->num_ch_out, false);
1245c46302ecSVinod Koul 	if (ret)
1246c46302ecSVinod Koul 		return ret;
1247c46302ecSVinod Koul 
1248cf924962SBard Liao 	off += cdns->pdm.num_out;
12491215daeeSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pdm.num_bd,
12501215daeeSVinod Koul 			       off, stream->num_ch_bd, false);
1251c46302ecSVinod Koul 	if (ret)
1252c46302ecSVinod Koul 		return ret;
1253c46302ecSVinod Koul 
1254c46302ecSVinod Koul 	return snd_soc_register_component(cdns->dev, &dai_component,
1255c46302ecSVinod Koul 					  dais, num_dai);
1256c46302ecSVinod Koul }
1257c46302ecSVinod Koul 
1258085f4aceSPierre-Louis Bossart static int sdw_master_read_intel_prop(struct sdw_bus *bus)
1259085f4aceSPierre-Louis Bossart {
1260085f4aceSPierre-Louis Bossart 	struct sdw_master_prop *prop = &bus->prop;
1261085f4aceSPierre-Louis Bossart 	struct fwnode_handle *link;
1262085f4aceSPierre-Louis Bossart 	char name[32];
1263395713d8SPierre-Louis Bossart 	u32 quirk_mask;
1264085f4aceSPierre-Louis Bossart 
1265085f4aceSPierre-Louis Bossart 	/* Find master handle */
1266085f4aceSPierre-Louis Bossart 	snprintf(name, sizeof(name),
1267085f4aceSPierre-Louis Bossart 		 "mipi-sdw-link-%d-subproperties", bus->link_id);
1268085f4aceSPierre-Louis Bossart 
1269085f4aceSPierre-Louis Bossart 	link = device_get_named_child_node(bus->dev, name);
1270085f4aceSPierre-Louis Bossart 	if (!link) {
1271085f4aceSPierre-Louis Bossart 		dev_err(bus->dev, "Master node %s not found\n", name);
1272085f4aceSPierre-Louis Bossart 		return -EIO;
1273085f4aceSPierre-Louis Bossart 	}
1274085f4aceSPierre-Louis Bossart 
1275085f4aceSPierre-Louis Bossart 	fwnode_property_read_u32(link,
1276085f4aceSPierre-Louis Bossart 				 "intel-sdw-ip-clock",
1277085f4aceSPierre-Louis Bossart 				 &prop->mclk_freq);
1278395713d8SPierre-Louis Bossart 
1279a19efb52SBard Liao 	/* the values reported by BIOS are the 2x clock, not the bus clock */
1280a19efb52SBard Liao 	prop->mclk_freq /= 2;
1281a19efb52SBard Liao 
1282395713d8SPierre-Louis Bossart 	fwnode_property_read_u32(link,
1283395713d8SPierre-Louis Bossart 				 "intel-quirk-mask",
1284395713d8SPierre-Louis Bossart 				 &quirk_mask);
1285395713d8SPierre-Louis Bossart 
1286395713d8SPierre-Louis Bossart 	if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
1287395713d8SPierre-Louis Bossart 		prop->hw_disabled = true;
1288395713d8SPierre-Louis Bossart 
1289085f4aceSPierre-Louis Bossart 	return 0;
1290085f4aceSPierre-Louis Bossart }
1291085f4aceSPierre-Louis Bossart 
129271bb8a1bSVinod Koul static int intel_prop_read(struct sdw_bus *bus)
129371bb8a1bSVinod Koul {
129471bb8a1bSVinod Koul 	/* Initialize with default handler to read all DisCo properties */
129571bb8a1bSVinod Koul 	sdw_master_read_prop(bus);
129671bb8a1bSVinod Koul 
1297085f4aceSPierre-Louis Bossart 	/* read Intel-specific properties */
1298085f4aceSPierre-Louis Bossart 	sdw_master_read_intel_prop(bus);
1299085f4aceSPierre-Louis Bossart 
130071bb8a1bSVinod Koul 	return 0;
130171bb8a1bSVinod Koul }
130271bb8a1bSVinod Koul 
1303c91605f4SShreyas NC static struct sdw_master_ops sdw_intel_ops = {
1304c91605f4SShreyas NC 	.read_prop = sdw_master_read_prop,
1305c91605f4SShreyas NC 	.xfer_msg = cdns_xfer_msg,
1306c91605f4SShreyas NC 	.xfer_msg_defer = cdns_xfer_msg_defer,
1307c91605f4SShreyas NC 	.reset_page_addr = cdns_reset_page_addr,
130807abeff1SVinod Koul 	.set_bus_conf = cdns_bus_conf,
130930246e2dSShreyas NC 	.pre_bank_switch = intel_pre_bank_switch,
131030246e2dSShreyas NC 	.post_bank_switch = intel_post_bank_switch,
1311c91605f4SShreyas NC };
1312c91605f4SShreyas NC 
1313dfbe642dSPierre-Louis Bossart static int intel_init(struct sdw_intel *sdw)
1314dfbe642dSPierre-Louis Bossart {
13154a17c441SPierre-Louis Bossart 	bool clock_stop;
13164a17c441SPierre-Louis Bossart 
1317dfbe642dSPierre-Louis Bossart 	/* Initialize shim and controller */
1318dfbe642dSPierre-Louis Bossart 	intel_link_power_up(sdw);
13194a17c441SPierre-Louis Bossart 
13204a17c441SPierre-Louis Bossart 	clock_stop = sdw_cdns_is_clock_stop(&sdw->cdns);
13214a17c441SPierre-Louis Bossart 
13224a17c441SPierre-Louis Bossart 	intel_shim_init(sdw, clock_stop);
13234a17c441SPierre-Louis Bossart 
13244a17c441SPierre-Louis Bossart 	return 0;
1325dfbe642dSPierre-Louis Bossart }
1326dfbe642dSPierre-Louis Bossart 
132771bb8a1bSVinod Koul /*
132871bb8a1bSVinod Koul  * probe and init
132971bb8a1bSVinod Koul  */
1330b6109dd6SPierre-Louis Bossart static int intel_master_probe(struct platform_device *pdev)
133171bb8a1bSVinod Koul {
1332b6109dd6SPierre-Louis Bossart 	struct device *dev = &pdev->dev;
133371bb8a1bSVinod Koul 	struct sdw_intel *sdw;
133483e129afSPierre-Louis Bossart 	struct sdw_cdns *cdns;
1335b6109dd6SPierre-Louis Bossart 	struct sdw_bus *bus;
133671bb8a1bSVinod Koul 	int ret;
133771bb8a1bSVinod Koul 
1338b6109dd6SPierre-Louis Bossart 	sdw = devm_kzalloc(dev, sizeof(*sdw), GFP_KERNEL);
133971bb8a1bSVinod Koul 	if (!sdw)
134071bb8a1bSVinod Koul 		return -ENOMEM;
134171bb8a1bSVinod Koul 
134283e129afSPierre-Louis Bossart 	cdns = &sdw->cdns;
134383e129afSPierre-Louis Bossart 	bus = &cdns->bus;
134471bb8a1bSVinod Koul 
134571bb8a1bSVinod Koul 	sdw->instance = pdev->id;
1346b6109dd6SPierre-Louis Bossart 	sdw->link_res = dev_get_platdata(dev);
134783e129afSPierre-Louis Bossart 	cdns->dev = dev;
134883e129afSPierre-Louis Bossart 	cdns->registers = sdw->link_res->registers;
134983e129afSPierre-Louis Bossart 	cdns->instance = sdw->instance;
135083e129afSPierre-Louis Bossart 	cdns->msg_count = 0;
135183e129afSPierre-Louis Bossart 
1352b6109dd6SPierre-Louis Bossart 	bus->link_id = pdev->id;
135371bb8a1bSVinod Koul 
135483e129afSPierre-Louis Bossart 	sdw_cdns_probe(cdns);
135571bb8a1bSVinod Koul 
135671bb8a1bSVinod Koul 	/* Set property read ops */
1357c91605f4SShreyas NC 	sdw_intel_ops.read_prop = intel_prop_read;
1358b6109dd6SPierre-Louis Bossart 	bus->ops = &sdw_intel_ops;
135971bb8a1bSVinod Koul 
1360b6109dd6SPierre-Louis Bossart 	/* set driver data, accessed by snd_soc_dai_get_drvdata() */
136183e129afSPierre-Louis Bossart 	dev_set_drvdata(dev, cdns);
136271bb8a1bSVinod Koul 
13639026118fSBard Liao 	/* use generic bandwidth allocation algorithm */
13649026118fSBard Liao 	sdw->cdns.bus.compute_params = sdw_compute_params;
13659026118fSBard Liao 
1366b6109dd6SPierre-Louis Bossart 	ret = sdw_bus_master_add(bus, dev, dev->fwnode);
136771bb8a1bSVinod Koul 	if (ret) {
1368b6109dd6SPierre-Louis Bossart 		dev_err(dev, "sdw_bus_master_add fail: %d\n", ret);
13699e3d47fbSPierre-Louis Bossart 		return ret;
137071bb8a1bSVinod Koul 	}
137171bb8a1bSVinod Koul 
13726d2c6669SPierre-Louis Bossart 	if (bus->prop.hw_disabled)
1373b6109dd6SPierre-Louis Bossart 		dev_info(dev,
1374b6109dd6SPierre-Louis Bossart 			 "SoundWire master %d is disabled, will be ignored\n",
1375b6109dd6SPierre-Louis Bossart 			 bus->link_id);
13760ef2986eSPierre-Louis Bossart 	/*
13770ef2986eSPierre-Louis Bossart 	 * Ignore BIOS err_threshold, it's a really bad idea when dealing
13780ef2986eSPierre-Louis Bossart 	 * with multiple hardware synchronized links
13790ef2986eSPierre-Louis Bossart 	 */
13800ef2986eSPierre-Louis Bossart 	bus->prop.err_threshold = 0;
13816d2c6669SPierre-Louis Bossart 
13826d2c6669SPierre-Louis Bossart 	return 0;
13836d2c6669SPierre-Louis Bossart }
13846d2c6669SPierre-Louis Bossart 
13856d2c6669SPierre-Louis Bossart int intel_master_startup(struct platform_device *pdev)
13866d2c6669SPierre-Louis Bossart {
13876d2c6669SPierre-Louis Bossart 	struct sdw_cdns_stream_config config;
13886d2c6669SPierre-Louis Bossart 	struct device *dev = &pdev->dev;
13896d2c6669SPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
13906d2c6669SPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
13916d2c6669SPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1392ebf878edSPierre-Louis Bossart 	int link_flags;
1393857a7c42SPierre-Louis Bossart 	bool multi_link;
1394caf68819SPierre-Louis Bossart 	u32 clock_stop_quirks;
13956d2c6669SPierre-Louis Bossart 	int ret;
13966d2c6669SPierre-Louis Bossart 
13976d2c6669SPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
13986d2c6669SPierre-Louis Bossart 		dev_info(dev,
13996d2c6669SPierre-Louis Bossart 			 "SoundWire master %d is disabled, ignoring\n",
14006d2c6669SPierre-Louis Bossart 			 sdw->instance);
1401395713d8SPierre-Louis Bossart 		return 0;
1402395713d8SPierre-Louis Bossart 	}
1403395713d8SPierre-Louis Bossart 
1404857a7c42SPierre-Louis Bossart 	link_flags = md_flags >> (bus->link_id * 8);
1405857a7c42SPierre-Louis Bossart 	multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
1406857a7c42SPierre-Louis Bossart 	if (!multi_link) {
1407857a7c42SPierre-Louis Bossart 		dev_dbg(dev, "Multi-link is disabled\n");
1408857a7c42SPierre-Louis Bossart 		bus->multi_link = false;
1409857a7c42SPierre-Louis Bossart 	} else {
141094eed661SPierre-Louis Bossart 		/*
141194eed661SPierre-Louis Bossart 		 * hardware-based synchronization is required regardless
141294eed661SPierre-Louis Bossart 		 * of the number of segments used by a stream: SSP-based
141394eed661SPierre-Louis Bossart 		 * synchronization is gated by gsync when the multi-master
141494eed661SPierre-Louis Bossart 		 * mode is set.
141594eed661SPierre-Louis Bossart 		 */
1416857a7c42SPierre-Louis Bossart 		bus->multi_link = true;
141794eed661SPierre-Louis Bossart 		bus->hw_sync_min_links = 1;
1418857a7c42SPierre-Louis Bossart 	}
1419857a7c42SPierre-Louis Bossart 
1420857a7c42SPierre-Louis Bossart 	/* Initialize shim, controller */
1421dfbe642dSPierre-Louis Bossart 	ret = intel_init(sdw);
142271bb8a1bSVinod Koul 	if (ret)
142371bb8a1bSVinod Koul 		goto err_init;
142471bb8a1bSVinod Koul 
142537a2d22bSVinod Koul 	/* Read the PDI config and initialize cadence PDI */
142637a2d22bSVinod Koul 	intel_pdi_init(sdw, &config);
142783e129afSPierre-Louis Bossart 	ret = sdw_cdns_pdi_init(cdns, config);
142871bb8a1bSVinod Koul 	if (ret)
142971bb8a1bSVinod Koul 		goto err_init;
143071bb8a1bSVinod Koul 
143137a2d22bSVinod Koul 	intel_pdi_ch_update(sdw);
143237a2d22bSVinod Koul 
143383e129afSPierre-Louis Bossart 	ret = sdw_cdns_enable_interrupt(cdns, true);
143471bb8a1bSVinod Koul 	if (ret < 0) {
1435b6109dd6SPierre-Louis Bossart 		dev_err(dev, "cannot enable interrupts\n");
143671bb8a1bSVinod Koul 		goto err_init;
143771bb8a1bSVinod Koul 	}
143871bb8a1bSVinod Koul 
1439857a7c42SPierre-Louis Bossart 	/*
1440857a7c42SPierre-Louis Bossart 	 * follow recommended programming flows to avoid timeouts when
1441857a7c42SPierre-Louis Bossart 	 * gsync is enabled
1442857a7c42SPierre-Louis Bossart 	 */
1443857a7c42SPierre-Louis Bossart 	if (multi_link)
1444857a7c42SPierre-Louis Bossart 		intel_shim_sync_arm(sdw);
1445857a7c42SPierre-Louis Bossart 
1446857a7c42SPierre-Louis Bossart 	ret = sdw_cdns_init(cdns);
1447857a7c42SPierre-Louis Bossart 	if (ret < 0) {
1448857a7c42SPierre-Louis Bossart 		dev_err(dev, "unable to initialize Cadence IP\n");
1449857a7c42SPierre-Louis Bossart 		goto err_interrupt;
1450857a7c42SPierre-Louis Bossart 	}
1451857a7c42SPierre-Louis Bossart 
145283e129afSPierre-Louis Bossart 	ret = sdw_cdns_exit_reset(cdns);
145349ea07d3SPierre-Louis Bossart 	if (ret < 0) {
1454b6109dd6SPierre-Louis Bossart 		dev_err(dev, "unable to exit bus reset sequence\n");
14559e3d47fbSPierre-Louis Bossart 		goto err_interrupt;
145649ea07d3SPierre-Louis Bossart 	}
145749ea07d3SPierre-Louis Bossart 
1458857a7c42SPierre-Louis Bossart 	if (multi_link) {
1459857a7c42SPierre-Louis Bossart 		ret = intel_shim_sync_go(sdw);
1460857a7c42SPierre-Louis Bossart 		if (ret < 0) {
1461857a7c42SPierre-Louis Bossart 			dev_err(dev, "sync go failed: %d\n", ret);
1462857a7c42SPierre-Louis Bossart 			goto err_interrupt;
1463857a7c42SPierre-Louis Bossart 		}
1464857a7c42SPierre-Louis Bossart 	}
1465857a7c42SPierre-Louis Bossart 
1466c46302ecSVinod Koul 	/* Register DAIs */
1467c46302ecSVinod Koul 	ret = intel_register_dai(sdw);
1468c46302ecSVinod Koul 	if (ret) {
1469b6109dd6SPierre-Louis Bossart 		dev_err(dev, "DAI registration failed: %d\n", ret);
1470b6109dd6SPierre-Louis Bossart 		snd_soc_unregister_component(dev);
14719e3d47fbSPierre-Louis Bossart 		goto err_interrupt;
1472c46302ecSVinod Koul 	}
1473c46302ecSVinod Koul 
147479ee6631SPierre-Louis Bossart 	intel_debugfs_init(sdw);
147579ee6631SPierre-Louis Bossart 
1476ebf878edSPierre-Louis Bossart 	/* Enable runtime PM */
1477ebf878edSPierre-Louis Bossart 	if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) {
1478ebf878edSPierre-Louis Bossart 		pm_runtime_set_autosuspend_delay(dev,
1479ebf878edSPierre-Louis Bossart 						 INTEL_MASTER_SUSPEND_DELAY_MS);
1480ebf878edSPierre-Louis Bossart 		pm_runtime_use_autosuspend(dev);
1481ebf878edSPierre-Louis Bossart 		pm_runtime_mark_last_busy(dev);
1482ebf878edSPierre-Louis Bossart 
1483ebf878edSPierre-Louis Bossart 		pm_runtime_set_active(dev);
1484ebf878edSPierre-Louis Bossart 		pm_runtime_enable(dev);
1485ebf878edSPierre-Louis Bossart 	}
1486ebf878edSPierre-Louis Bossart 
1487caf68819SPierre-Louis Bossart 	clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1488caf68819SPierre-Louis Bossart 	if (clock_stop_quirks & SDW_INTEL_CLK_STOP_NOT_ALLOWED) {
1489caf68819SPierre-Louis Bossart 		/*
1490caf68819SPierre-Louis Bossart 		 * To keep the clock running we need to prevent
1491caf68819SPierre-Louis Bossart 		 * pm_runtime suspend from happening by increasing the
1492caf68819SPierre-Louis Bossart 		 * reference count.
1493caf68819SPierre-Louis Bossart 		 * This quirk is specified by the parent PCI device in
1494caf68819SPierre-Louis Bossart 		 * case of specific latency requirements. It will have
1495caf68819SPierre-Louis Bossart 		 * no effect if pm_runtime is disabled by the user via
1496caf68819SPierre-Louis Bossart 		 * a module parameter for testing purposes.
1497caf68819SPierre-Louis Bossart 		 */
1498caf68819SPierre-Louis Bossart 		pm_runtime_get_noresume(dev);
1499caf68819SPierre-Louis Bossart 	}
1500caf68819SPierre-Louis Bossart 
1501a2d9c161SPierre-Louis Bossart 	/*
1502a2d9c161SPierre-Louis Bossart 	 * The runtime PM status of Slave devices is "Unsupported"
1503a2d9c161SPierre-Louis Bossart 	 * until they report as ATTACHED. If they don't, e.g. because
1504a2d9c161SPierre-Louis Bossart 	 * there are no Slave devices populated or if the power-on is
1505a2d9c161SPierre-Louis Bossart 	 * delayed or dependent on a power switch, the Master will
1506a2d9c161SPierre-Louis Bossart 	 * remain active and prevent its parent from suspending.
1507a2d9c161SPierre-Louis Bossart 	 *
1508a2d9c161SPierre-Louis Bossart 	 * Conditionally force the pm_runtime core to re-evaluate the
1509a2d9c161SPierre-Louis Bossart 	 * Master status in the absence of any Slave activity. A quirk
1510a2d9c161SPierre-Louis Bossart 	 * is provided to e.g. deal with Slaves that may be powered on
1511a2d9c161SPierre-Louis Bossart 	 * with a delay. A more complete solution would require the
1512a2d9c161SPierre-Louis Bossart 	 * definition of Master properties.
1513a2d9c161SPierre-Louis Bossart 	 */
1514a2d9c161SPierre-Louis Bossart 	if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
1515a2d9c161SPierre-Louis Bossart 		pm_runtime_idle(dev);
1516a2d9c161SPierre-Louis Bossart 
151771bb8a1bSVinod Koul 	return 0;
151871bb8a1bSVinod Koul 
15199e3d47fbSPierre-Louis Bossart err_interrupt:
152083e129afSPierre-Louis Bossart 	sdw_cdns_enable_interrupt(cdns, false);
152171bb8a1bSVinod Koul err_init:
152271bb8a1bSVinod Koul 	return ret;
152371bb8a1bSVinod Koul }
152471bb8a1bSVinod Koul 
1525b6109dd6SPierre-Louis Bossart static int intel_master_remove(struct platform_device *pdev)
152671bb8a1bSVinod Koul {
1527b6109dd6SPierre-Louis Bossart 	struct device *dev = &pdev->dev;
152883e129afSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
152983e129afSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
153083e129afSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1531b6109dd6SPierre-Louis Bossart 
1532caf68819SPierre-Louis Bossart 	/*
1533caf68819SPierre-Louis Bossart 	 * Since pm_runtime is already disabled, we don't decrease
1534caf68819SPierre-Louis Bossart 	 * the refcount when the clock_stop_quirk is
1535caf68819SPierre-Louis Bossart 	 * SDW_INTEL_CLK_STOP_NOT_ALLOWED
1536caf68819SPierre-Louis Bossart 	 */
1537b6109dd6SPierre-Louis Bossart 	if (!bus->prop.hw_disabled) {
153879ee6631SPierre-Louis Bossart 		intel_debugfs_exit(sdw);
153983e129afSPierre-Louis Bossart 		sdw_cdns_enable_interrupt(cdns, false);
1540b6109dd6SPierre-Louis Bossart 		snd_soc_unregister_component(dev);
1541395713d8SPierre-Louis Bossart 	}
1542b6109dd6SPierre-Louis Bossart 	sdw_bus_master_delete(bus);
154371bb8a1bSVinod Koul 
154471bb8a1bSVinod Koul 	return 0;
154571bb8a1bSVinod Koul }
154671bb8a1bSVinod Koul 
1547ab2c9132SRander Wang int intel_master_process_wakeen_event(struct platform_device *pdev)
1548ab2c9132SRander Wang {
1549ab2c9132SRander Wang 	struct device *dev = &pdev->dev;
155071bb8a1bSVinod Koul 	struct sdw_intel *sdw;
1551ab2c9132SRander Wang 	struct sdw_bus *bus;
1552ab2c9132SRander Wang 	void __iomem *shim;
1553ab2c9132SRander Wang 	u16 wake_sts;
155471bb8a1bSVinod Koul 
155571bb8a1bSVinod Koul 	sdw = platform_get_drvdata(pdev);
1556ab2c9132SRander Wang 	bus = &sdw->cdns.bus;
155771bb8a1bSVinod Koul 
1558ab2c9132SRander Wang 	if (bus->prop.hw_disabled) {
1559ab2c9132SRander Wang 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", bus->link_id);
1560ab2c9132SRander Wang 		return 0;
156171bb8a1bSVinod Koul 	}
1562ab2c9132SRander Wang 
1563ab2c9132SRander Wang 	shim = sdw->link_res->shim;
1564ab2c9132SRander Wang 	wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
1565ab2c9132SRander Wang 
1566ab2c9132SRander Wang 	if (!(wake_sts & BIT(sdw->instance)))
1567ab2c9132SRander Wang 		return 0;
1568ab2c9132SRander Wang 
1569ab2c9132SRander Wang 	/* disable WAKEEN interrupt ASAP to prevent interrupt flood */
1570ab2c9132SRander Wang 	intel_shim_wake(sdw, false);
1571ab2c9132SRander Wang 
1572ab2c9132SRander Wang 	/*
1573ab2c9132SRander Wang 	 * resume the Master, which will generate a bus reset and result in
1574ab2c9132SRander Wang 	 * Slaves re-attaching and be re-enumerated. The SoundWire physical
1575ab2c9132SRander Wang 	 * device which generated the wake will trigger an interrupt, which
1576ab2c9132SRander Wang 	 * will in turn cause the corresponding Linux Slave device to be
1577ab2c9132SRander Wang 	 * resumed and the Slave codec driver to check the status.
1578ab2c9132SRander Wang 	 */
1579ab2c9132SRander Wang 	pm_request_resume(dev);
158071bb8a1bSVinod Koul 
158171bb8a1bSVinod Koul 	return 0;
158271bb8a1bSVinod Koul }
158371bb8a1bSVinod Koul 
15849b3b4b3fSPierre-Louis Bossart /*
15859b3b4b3fSPierre-Louis Bossart  * PM calls
15869b3b4b3fSPierre-Louis Bossart  */
15879b3b4b3fSPierre-Louis Bossart 
1588f046b233SBard Liao static int __maybe_unused intel_suspend(struct device *dev)
15899b3b4b3fSPierre-Louis Bossart {
15909b3b4b3fSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
15919b3b4b3fSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
15929b3b4b3fSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1593e4be9facSPierre-Louis Bossart 	u32 clock_stop_quirks;
15949b3b4b3fSPierre-Louis Bossart 	int ret;
15959b3b4b3fSPierre-Louis Bossart 
15969b3b4b3fSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
15979b3b4b3fSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
15989b3b4b3fSPierre-Louis Bossart 			bus->link_id);
15999b3b4b3fSPierre-Louis Bossart 		return 0;
16009b3b4b3fSPierre-Louis Bossart 	}
16019b3b4b3fSPierre-Louis Bossart 
1602b61b8b37SPierre-Louis Bossart 	if (pm_runtime_suspended(dev)) {
1603b61b8b37SPierre-Louis Bossart 		dev_dbg(dev, "%s: pm_runtime status: suspended\n", __func__);
1604b61b8b37SPierre-Louis Bossart 
1605e4be9facSPierre-Louis Bossart 		clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1606e4be9facSPierre-Louis Bossart 
1607e4be9facSPierre-Louis Bossart 		if ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET ||
1608e4be9facSPierre-Louis Bossart 		     !clock_stop_quirks) &&
1609e4be9facSPierre-Louis Bossart 		    !pm_runtime_suspended(dev->parent)) {
1610e4be9facSPierre-Louis Bossart 
1611e4be9facSPierre-Louis Bossart 			/*
1612e4be9facSPierre-Louis Bossart 			 * if we've enabled clock stop, and the parent
1613e4be9facSPierre-Louis Bossart 			 * is still active, disable shim wake. The
1614e4be9facSPierre-Louis Bossart 			 * SHIM registers are not accessible if the
1615e4be9facSPierre-Louis Bossart 			 * parent is already pm_runtime suspended so
1616e4be9facSPierre-Louis Bossart 			 * it's too late to change that configuration
1617e4be9facSPierre-Louis Bossart 			 */
1618e4be9facSPierre-Louis Bossart 
1619e4be9facSPierre-Louis Bossart 			intel_shim_wake(sdw, false);
1620e4be9facSPierre-Louis Bossart 		}
1621e4be9facSPierre-Louis Bossart 
1622b61b8b37SPierre-Louis Bossart 		return 0;
1623b61b8b37SPierre-Louis Bossart 	}
1624b61b8b37SPierre-Louis Bossart 
16259b3b4b3fSPierre-Louis Bossart 	ret = sdw_cdns_enable_interrupt(cdns, false);
16269b3b4b3fSPierre-Louis Bossart 	if (ret < 0) {
16279b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "cannot disable interrupts on suspend\n");
16289b3b4b3fSPierre-Louis Bossart 		return ret;
16299b3b4b3fSPierre-Louis Bossart 	}
16309b3b4b3fSPierre-Louis Bossart 
16319b3b4b3fSPierre-Louis Bossart 	ret = intel_link_power_down(sdw);
16329b3b4b3fSPierre-Louis Bossart 	if (ret) {
16339b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "Link power down failed: %d", ret);
16349b3b4b3fSPierre-Louis Bossart 		return ret;
16359b3b4b3fSPierre-Louis Bossart 	}
16369b3b4b3fSPierre-Louis Bossart 
16379b3b4b3fSPierre-Louis Bossart 	intel_shim_wake(sdw, false);
16389b3b4b3fSPierre-Louis Bossart 
16399b3b4b3fSPierre-Louis Bossart 	return 0;
16409b3b4b3fSPierre-Louis Bossart }
16419b3b4b3fSPierre-Louis Bossart 
1642*17e0da0bSArnd Bergmann static int __maybe_unused intel_suspend_runtime(struct device *dev)
1643ebf878edSPierre-Louis Bossart {
1644ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
1645ebf878edSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
1646ebf878edSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1647a320f41eSPierre-Louis Bossart 	u32 clock_stop_quirks;
1648ebf878edSPierre-Louis Bossart 	int ret;
1649ebf878edSPierre-Louis Bossart 
1650ebf878edSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
1651ebf878edSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1652ebf878edSPierre-Louis Bossart 			bus->link_id);
1653ebf878edSPierre-Louis Bossart 		return 0;
1654ebf878edSPierre-Louis Bossart 	}
1655ebf878edSPierre-Louis Bossart 
1656a320f41eSPierre-Louis Bossart 	clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1657a320f41eSPierre-Louis Bossart 
1658a320f41eSPierre-Louis Bossart 	if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
1659a320f41eSPierre-Louis Bossart 
1660ebf878edSPierre-Louis Bossart 		ret = sdw_cdns_enable_interrupt(cdns, false);
1661ebf878edSPierre-Louis Bossart 		if (ret < 0) {
1662ebf878edSPierre-Louis Bossart 			dev_err(dev, "cannot disable interrupts on suspend\n");
1663ebf878edSPierre-Louis Bossart 			return ret;
1664ebf878edSPierre-Louis Bossart 		}
1665ebf878edSPierre-Louis Bossart 
1666ebf878edSPierre-Louis Bossart 		ret = intel_link_power_down(sdw);
1667ebf878edSPierre-Louis Bossart 		if (ret) {
1668ebf878edSPierre-Louis Bossart 			dev_err(dev, "Link power down failed: %d", ret);
1669ebf878edSPierre-Louis Bossart 			return ret;
1670ebf878edSPierre-Louis Bossart 		}
1671ebf878edSPierre-Louis Bossart 
1672ebf878edSPierre-Louis Bossart 		intel_shim_wake(sdw, false);
1673ebf878edSPierre-Louis Bossart 
167461fb830bSPierre-Louis Bossart 	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET ||
167561fb830bSPierre-Louis Bossart 		   !clock_stop_quirks) {
16766626a616SRander Wang 		ret = sdw_cdns_clock_stop(cdns, true);
16776626a616SRander Wang 		if (ret < 0) {
16786626a616SRander Wang 			dev_err(dev, "cannot enable clock stop on suspend\n");
16796626a616SRander Wang 			return ret;
16806626a616SRander Wang 		}
16816626a616SRander Wang 
16826626a616SRander Wang 		ret = sdw_cdns_enable_interrupt(cdns, false);
16836626a616SRander Wang 		if (ret < 0) {
16846626a616SRander Wang 			dev_err(dev, "cannot disable interrupts on suspend\n");
16856626a616SRander Wang 			return ret;
16866626a616SRander Wang 		}
16876626a616SRander Wang 
16886626a616SRander Wang 		ret = intel_link_power_down(sdw);
16896626a616SRander Wang 		if (ret) {
16906626a616SRander Wang 			dev_err(dev, "Link power down failed: %d", ret);
16916626a616SRander Wang 			return ret;
16926626a616SRander Wang 		}
16936626a616SRander Wang 
16946626a616SRander Wang 		intel_shim_wake(sdw, true);
1695a320f41eSPierre-Louis Bossart 	} else {
1696a320f41eSPierre-Louis Bossart 		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
1697a320f41eSPierre-Louis Bossart 			__func__, clock_stop_quirks);
1698a320f41eSPierre-Louis Bossart 		ret = -EINVAL;
1699a320f41eSPierre-Louis Bossart 	}
1700a320f41eSPierre-Louis Bossart 
1701a320f41eSPierre-Louis Bossart 	return ret;
1702ebf878edSPierre-Louis Bossart }
1703ebf878edSPierre-Louis Bossart 
1704f046b233SBard Liao static int __maybe_unused intel_resume(struct device *dev)
17059b3b4b3fSPierre-Louis Bossart {
17069b3b4b3fSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
17079b3b4b3fSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
17089b3b4b3fSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1709a2d9c161SPierre-Louis Bossart 	int link_flags;
1710857a7c42SPierre-Louis Bossart 	bool multi_link;
17119b3b4b3fSPierre-Louis Bossart 	int ret;
17129b3b4b3fSPierre-Louis Bossart 
17139b3b4b3fSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
17149b3b4b3fSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
17159b3b4b3fSPierre-Louis Bossart 			bus->link_id);
17169b3b4b3fSPierre-Louis Bossart 		return 0;
17179b3b4b3fSPierre-Louis Bossart 	}
17189b3b4b3fSPierre-Louis Bossart 
1719857a7c42SPierre-Louis Bossart 	link_flags = md_flags >> (bus->link_id * 8);
1720857a7c42SPierre-Louis Bossart 	multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
1721857a7c42SPierre-Louis Bossart 
1722b61b8b37SPierre-Louis Bossart 	if (pm_runtime_suspended(dev)) {
1723b61b8b37SPierre-Louis Bossart 		dev_dbg(dev, "%s: pm_runtime status was suspended, forcing active\n", __func__);
1724b61b8b37SPierre-Louis Bossart 
1725b61b8b37SPierre-Louis Bossart 		/* follow required sequence from runtime_pm.rst */
1726b61b8b37SPierre-Louis Bossart 		pm_runtime_disable(dev);
1727b61b8b37SPierre-Louis Bossart 		pm_runtime_set_active(dev);
1728b61b8b37SPierre-Louis Bossart 		pm_runtime_mark_last_busy(dev);
1729b61b8b37SPierre-Louis Bossart 		pm_runtime_enable(dev);
1730a2d9c161SPierre-Louis Bossart 
1731a2d9c161SPierre-Louis Bossart 		link_flags = md_flags >> (bus->link_id * 8);
1732857a7c42SPierre-Louis Bossart 
1733a2d9c161SPierre-Louis Bossart 		if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
1734a2d9c161SPierre-Louis Bossart 			pm_runtime_idle(dev);
1735b61b8b37SPierre-Louis Bossart 	}
1736b61b8b37SPierre-Louis Bossart 
17379b3b4b3fSPierre-Louis Bossart 	ret = intel_init(sdw);
17389b3b4b3fSPierre-Louis Bossart 	if (ret) {
17399b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "%s failed: %d", __func__, ret);
17409b3b4b3fSPierre-Louis Bossart 		return ret;
17419b3b4b3fSPierre-Louis Bossart 	}
17429b3b4b3fSPierre-Louis Bossart 
174399b6a30fSPierre-Louis Bossart 	/*
174499b6a30fSPierre-Louis Bossart 	 * make sure all Slaves are tagged as UNATTACHED and provide
174599b6a30fSPierre-Louis Bossart 	 * reason for reinitialization
174699b6a30fSPierre-Louis Bossart 	 */
174799b6a30fSPierre-Louis Bossart 	sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
174899b6a30fSPierre-Louis Bossart 
17499b3b4b3fSPierre-Louis Bossart 	ret = sdw_cdns_enable_interrupt(cdns, true);
17509b3b4b3fSPierre-Louis Bossart 	if (ret < 0) {
17519b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "cannot enable interrupts during resume\n");
17529b3b4b3fSPierre-Louis Bossart 		return ret;
17539b3b4b3fSPierre-Louis Bossart 	}
17549b3b4b3fSPierre-Louis Bossart 
1755857a7c42SPierre-Louis Bossart 	/*
1756857a7c42SPierre-Louis Bossart 	 * follow recommended programming flows to avoid timeouts when
1757857a7c42SPierre-Louis Bossart 	 * gsync is enabled
1758857a7c42SPierre-Louis Bossart 	 */
1759857a7c42SPierre-Louis Bossart 	if (multi_link)
1760857a7c42SPierre-Louis Bossart 		intel_shim_sync_arm(sdw);
1761857a7c42SPierre-Louis Bossart 
1762857a7c42SPierre-Louis Bossart 	ret = sdw_cdns_init(&sdw->cdns);
1763857a7c42SPierre-Louis Bossart 	if (ret < 0) {
1764857a7c42SPierre-Louis Bossart 		dev_err(dev, "unable to initialize Cadence IP during resume\n");
1765857a7c42SPierre-Louis Bossart 		return ret;
1766857a7c42SPierre-Louis Bossart 	}
1767857a7c42SPierre-Louis Bossart 
17689b3b4b3fSPierre-Louis Bossart 	ret = sdw_cdns_exit_reset(cdns);
17699b3b4b3fSPierre-Louis Bossart 	if (ret < 0) {
17709b3b4b3fSPierre-Louis Bossart 		dev_err(dev, "unable to exit bus reset sequence during resume\n");
17719b3b4b3fSPierre-Louis Bossart 		return ret;
17729b3b4b3fSPierre-Louis Bossart 	}
17739b3b4b3fSPierre-Louis Bossart 
1774857a7c42SPierre-Louis Bossart 	if (multi_link) {
1775857a7c42SPierre-Louis Bossart 		ret = intel_shim_sync_go(sdw);
1776857a7c42SPierre-Louis Bossart 		if (ret < 0) {
1777857a7c42SPierre-Louis Bossart 			dev_err(dev, "sync go failed during resume\n");
1778857a7c42SPierre-Louis Bossart 			return ret;
1779857a7c42SPierre-Louis Bossart 		}
1780857a7c42SPierre-Louis Bossart 	}
1781857a7c42SPierre-Louis Bossart 
1782cb1e6d59SPierre-Louis Bossart 	/*
1783cb1e6d59SPierre-Louis Bossart 	 * after system resume, the pm_runtime suspend() may kick in
1784cb1e6d59SPierre-Louis Bossart 	 * during the enumeration, before any children device force the
1785cb1e6d59SPierre-Louis Bossart 	 * master device to remain active.  Using pm_runtime_get()
1786cb1e6d59SPierre-Louis Bossart 	 * routines is not really possible, since it'd prevent the
1787cb1e6d59SPierre-Louis Bossart 	 * master from suspending.
1788cb1e6d59SPierre-Louis Bossart 	 * A reasonable compromise is to update the pm_runtime
1789cb1e6d59SPierre-Louis Bossart 	 * counters and delay the pm_runtime suspend by several
1790cb1e6d59SPierre-Louis Bossart 	 * seconds, by when all enumeration should be complete.
1791cb1e6d59SPierre-Louis Bossart 	 */
1792cb1e6d59SPierre-Louis Bossart 	pm_runtime_mark_last_busy(dev);
1793cb1e6d59SPierre-Louis Bossart 
17949b3b4b3fSPierre-Louis Bossart 	return ret;
17959b3b4b3fSPierre-Louis Bossart }
17969b3b4b3fSPierre-Louis Bossart 
1797*17e0da0bSArnd Bergmann static int __maybe_unused intel_resume_runtime(struct device *dev)
1798ebf878edSPierre-Louis Bossart {
1799ebf878edSPierre-Louis Bossart 	struct sdw_cdns *cdns = dev_get_drvdata(dev);
1800ebf878edSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
1801ebf878edSPierre-Louis Bossart 	struct sdw_bus *bus = &cdns->bus;
1802a320f41eSPierre-Louis Bossart 	u32 clock_stop_quirks;
180308abad9fSRander Wang 	bool clock_stop0;
1804857a7c42SPierre-Louis Bossart 	int link_flags;
1805857a7c42SPierre-Louis Bossart 	bool multi_link;
180608abad9fSRander Wang 	int status;
1807ebf878edSPierre-Louis Bossart 	int ret;
1808ebf878edSPierre-Louis Bossart 
1809ebf878edSPierre-Louis Bossart 	if (bus->prop.hw_disabled) {
1810ebf878edSPierre-Louis Bossart 		dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1811ebf878edSPierre-Louis Bossart 			bus->link_id);
1812ebf878edSPierre-Louis Bossart 		return 0;
1813ebf878edSPierre-Louis Bossart 	}
1814ebf878edSPierre-Louis Bossart 
1815857a7c42SPierre-Louis Bossart 	link_flags = md_flags >> (bus->link_id * 8);
1816857a7c42SPierre-Louis Bossart 	multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
1817857a7c42SPierre-Louis Bossart 
1818a320f41eSPierre-Louis Bossart 	clock_stop_quirks = sdw->link_res->clock_stop_quirks;
1819a320f41eSPierre-Louis Bossart 
1820a320f41eSPierre-Louis Bossart 	if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
1821ebf878edSPierre-Louis Bossart 		ret = intel_init(sdw);
1822ebf878edSPierre-Louis Bossart 		if (ret) {
1823ebf878edSPierre-Louis Bossart 			dev_err(dev, "%s failed: %d", __func__, ret);
1824ebf878edSPierre-Louis Bossart 			return ret;
1825ebf878edSPierre-Louis Bossart 		}
1826ebf878edSPierre-Louis Bossart 
182799b6a30fSPierre-Louis Bossart 		/*
182899b6a30fSPierre-Louis Bossart 		 * make sure all Slaves are tagged as UNATTACHED and provide
182999b6a30fSPierre-Louis Bossart 		 * reason for reinitialization
183099b6a30fSPierre-Louis Bossart 		 */
183199b6a30fSPierre-Louis Bossart 		sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
183299b6a30fSPierre-Louis Bossart 
1833ebf878edSPierre-Louis Bossart 		ret = sdw_cdns_enable_interrupt(cdns, true);
1834ebf878edSPierre-Louis Bossart 		if (ret < 0) {
1835ebf878edSPierre-Louis Bossart 			dev_err(dev, "cannot enable interrupts during resume\n");
1836ebf878edSPierre-Louis Bossart 			return ret;
1837ebf878edSPierre-Louis Bossart 		}
1838ebf878edSPierre-Louis Bossart 
1839857a7c42SPierre-Louis Bossart 		/*
1840857a7c42SPierre-Louis Bossart 		 * follow recommended programming flows to avoid
1841857a7c42SPierre-Louis Bossart 		 * timeouts when gsync is enabled
1842857a7c42SPierre-Louis Bossart 		 */
1843857a7c42SPierre-Louis Bossart 		if (multi_link)
1844857a7c42SPierre-Louis Bossart 			intel_shim_sync_arm(sdw);
1845857a7c42SPierre-Louis Bossart 
1846857a7c42SPierre-Louis Bossart 		ret = sdw_cdns_init(&sdw->cdns);
1847857a7c42SPierre-Louis Bossart 		if (ret < 0) {
1848857a7c42SPierre-Louis Bossart 			dev_err(dev, "unable to initialize Cadence IP during resume\n");
1849857a7c42SPierre-Louis Bossart 			return ret;
1850857a7c42SPierre-Louis Bossart 		}
1851857a7c42SPierre-Louis Bossart 
1852ebf878edSPierre-Louis Bossart 		ret = sdw_cdns_exit_reset(cdns);
1853ebf878edSPierre-Louis Bossart 		if (ret < 0) {
1854ebf878edSPierre-Louis Bossart 			dev_err(dev, "unable to exit bus reset sequence during resume\n");
1855ebf878edSPierre-Louis Bossart 			return ret;
1856ebf878edSPierre-Louis Bossart 		}
1857857a7c42SPierre-Louis Bossart 
1858857a7c42SPierre-Louis Bossart 		if (multi_link) {
1859857a7c42SPierre-Louis Bossart 			ret = intel_shim_sync_go(sdw);
1860857a7c42SPierre-Louis Bossart 			if (ret < 0) {
1861857a7c42SPierre-Louis Bossart 				dev_err(dev, "sync go failed during resume\n");
1862857a7c42SPierre-Louis Bossart 				return ret;
1863857a7c42SPierre-Louis Bossart 			}
1864857a7c42SPierre-Louis Bossart 		}
18656626a616SRander Wang 	} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
18666626a616SRander Wang 		ret = intel_init(sdw);
18676626a616SRander Wang 		if (ret) {
18686626a616SRander Wang 			dev_err(dev, "%s failed: %d", __func__, ret);
18696626a616SRander Wang 			return ret;
18706626a616SRander Wang 		}
18716626a616SRander Wang 
18726626a616SRander Wang 		/*
187308abad9fSRander Wang 		 * An exception condition occurs for the CLK_STOP_BUS_RESET
187408abad9fSRander Wang 		 * case if one or more masters remain active. In this condition,
187508abad9fSRander Wang 		 * all the masters are powered on for they are in the same power
187608abad9fSRander Wang 		 * domain. Master can preserve its context for clock stop0, so
187708abad9fSRander Wang 		 * there is no need to clear slave status and reset bus.
187808abad9fSRander Wang 		 */
187908abad9fSRander Wang 		clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
188008abad9fSRander Wang 
1881857a7c42SPierre-Louis Bossart 		if (!clock_stop0) {
1882857a7c42SPierre-Louis Bossart 
1883857a7c42SPierre-Louis Bossart 			/*
18846626a616SRander Wang 			 * make sure all Slaves are tagged as UNATTACHED and
18856626a616SRander Wang 			 * provide reason for reinitialization
18866626a616SRander Wang 			 */
1887857a7c42SPierre-Louis Bossart 
188808abad9fSRander Wang 			status = SDW_UNATTACH_REQUEST_MASTER_RESET;
188908abad9fSRander Wang 			sdw_clear_slave_status(bus, status);
18906626a616SRander Wang 
18916626a616SRander Wang 			ret = sdw_cdns_enable_interrupt(cdns, true);
18926626a616SRander Wang 			if (ret < 0) {
18936626a616SRander Wang 				dev_err(dev, "cannot enable interrupts during resume\n");
18946626a616SRander Wang 				return ret;
18956626a616SRander Wang 			}
18966626a616SRander Wang 
1897d78071b4SPierre-Louis Bossart 			/*
1898d78071b4SPierre-Louis Bossart 			 * follow recommended programming flows to avoid
1899d78071b4SPierre-Louis Bossart 			 * timeouts when gsync is enabled
1900d78071b4SPierre-Louis Bossart 			 */
1901d78071b4SPierre-Louis Bossart 			if (multi_link)
1902d78071b4SPierre-Louis Bossart 				intel_shim_sync_arm(sdw);
1903d78071b4SPierre-Louis Bossart 
1904d78071b4SPierre-Louis Bossart 			/*
1905d78071b4SPierre-Louis Bossart 			 * Re-initialize the IP since it was powered-off
1906d78071b4SPierre-Louis Bossart 			 */
1907d78071b4SPierre-Louis Bossart 			sdw_cdns_init(&sdw->cdns);
1908d78071b4SPierre-Louis Bossart 
1909d78071b4SPierre-Louis Bossart 		} else {
1910d78071b4SPierre-Louis Bossart 			ret = sdw_cdns_enable_interrupt(cdns, true);
1911d78071b4SPierre-Louis Bossart 			if (ret < 0) {
1912d78071b4SPierre-Louis Bossart 				dev_err(dev, "cannot enable interrupts during resume\n");
1913d78071b4SPierre-Louis Bossart 				return ret;
1914d78071b4SPierre-Louis Bossart 			}
1915d78071b4SPierre-Louis Bossart 		}
1916d78071b4SPierre-Louis Bossart 
191708abad9fSRander Wang 		ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
19186626a616SRander Wang 		if (ret < 0) {
19196626a616SRander Wang 			dev_err(dev, "unable to restart clock during resume\n");
19206626a616SRander Wang 			return ret;
19216626a616SRander Wang 		}
1922d78071b4SPierre-Louis Bossart 
1923d78071b4SPierre-Louis Bossart 		if (!clock_stop0) {
1924d78071b4SPierre-Louis Bossart 			ret = sdw_cdns_exit_reset(cdns);
1925d78071b4SPierre-Louis Bossart 			if (ret < 0) {
1926d78071b4SPierre-Louis Bossart 				dev_err(dev, "unable to exit bus reset sequence during resume\n");
1927d78071b4SPierre-Louis Bossart 				return ret;
1928d78071b4SPierre-Louis Bossart 			}
1929d78071b4SPierre-Louis Bossart 
1930d78071b4SPierre-Louis Bossart 			if (multi_link) {
1931d78071b4SPierre-Louis Bossart 				ret = intel_shim_sync_go(sdw);
1932d78071b4SPierre-Louis Bossart 				if (ret < 0) {
1933d78071b4SPierre-Louis Bossart 					dev_err(sdw->cdns.dev, "sync go failed during resume\n");
1934d78071b4SPierre-Louis Bossart 					return ret;
1935d78071b4SPierre-Louis Bossart 				}
1936d78071b4SPierre-Louis Bossart 			}
1937d78071b4SPierre-Louis Bossart 		}
193861fb830bSPierre-Louis Bossart 	} else if (!clock_stop_quirks) {
1939f748f34eSPierre-Louis Bossart 
1940f748f34eSPierre-Louis Bossart 		clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
1941f748f34eSPierre-Louis Bossart 		if (!clock_stop0)
1942f748f34eSPierre-Louis Bossart 			dev_err(dev, "%s invalid configuration, clock was not stopped", __func__);
1943f748f34eSPierre-Louis Bossart 
194461fb830bSPierre-Louis Bossart 		ret = intel_init(sdw);
194561fb830bSPierre-Louis Bossart 		if (ret) {
194661fb830bSPierre-Louis Bossart 			dev_err(dev, "%s failed: %d", __func__, ret);
194761fb830bSPierre-Louis Bossart 			return ret;
194861fb830bSPierre-Louis Bossart 		}
194961fb830bSPierre-Louis Bossart 
195061fb830bSPierre-Louis Bossart 		ret = sdw_cdns_enable_interrupt(cdns, true);
195161fb830bSPierre-Louis Bossart 		if (ret < 0) {
195261fb830bSPierre-Louis Bossart 			dev_err(dev, "cannot enable interrupts during resume\n");
195361fb830bSPierre-Louis Bossart 			return ret;
195461fb830bSPierre-Louis Bossart 		}
195561fb830bSPierre-Louis Bossart 
195661fb830bSPierre-Louis Bossart 		ret = sdw_cdns_clock_restart(cdns, false);
195761fb830bSPierre-Louis Bossart 		if (ret < 0) {
195861fb830bSPierre-Louis Bossart 			dev_err(dev, "unable to resume master during resume\n");
195961fb830bSPierre-Louis Bossart 			return ret;
196061fb830bSPierre-Louis Bossart 		}
1961a320f41eSPierre-Louis Bossart 	} else {
1962a320f41eSPierre-Louis Bossart 		dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
1963a320f41eSPierre-Louis Bossart 			__func__, clock_stop_quirks);
1964a320f41eSPierre-Louis Bossart 		ret = -EINVAL;
1965a320f41eSPierre-Louis Bossart 	}
1966ebf878edSPierre-Louis Bossart 
1967ebf878edSPierre-Louis Bossart 	return ret;
1968ebf878edSPierre-Louis Bossart }
1969ebf878edSPierre-Louis Bossart 
19709b3b4b3fSPierre-Louis Bossart static const struct dev_pm_ops intel_pm = {
19719b3b4b3fSPierre-Louis Bossart 	SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
1972ebf878edSPierre-Louis Bossart 	SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL)
19739b3b4b3fSPierre-Louis Bossart };
19749b3b4b3fSPierre-Louis Bossart 
197571bb8a1bSVinod Koul static struct platform_driver sdw_intel_drv = {
1976b6109dd6SPierre-Louis Bossart 	.probe = intel_master_probe,
1977b6109dd6SPierre-Louis Bossart 	.remove = intel_master_remove,
197871bb8a1bSVinod Koul 	.driver = {
19796d2c6669SPierre-Louis Bossart 		.name = "intel-sdw",
19809b3b4b3fSPierre-Louis Bossart 		.pm = &intel_pm,
19819b3b4b3fSPierre-Louis Bossart 	}
198271bb8a1bSVinod Koul };
198371bb8a1bSVinod Koul 
198471bb8a1bSVinod Koul module_platform_driver(sdw_intel_drv);
198571bb8a1bSVinod Koul 
198671bb8a1bSVinod Koul MODULE_LICENSE("Dual BSD/GPL");
19876d2c6669SPierre-Louis Bossart MODULE_ALIAS("platform:intel-sdw");
198871bb8a1bSVinod Koul MODULE_DESCRIPTION("Intel Soundwire Master Driver");
1989