xref: /linux/drivers/soundwire/intel_init.c (revision 29a269c6f54825c643a5c35762a2829ba5be67f6)
1d62a7d41SVinod Koul // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2d62a7d41SVinod Koul // Copyright(c) 2015-17 Intel Corporation.
3d62a7d41SVinod Koul 
4d62a7d41SVinod Koul /*
5d62a7d41SVinod Koul  * SDW Intel Init Routines
6d62a7d41SVinod Koul  *
7d62a7d41SVinod Koul  * Initializes and creates SDW devices based on ACPI and Hardware values
8d62a7d41SVinod Koul  */
9d62a7d41SVinod Koul 
10d62a7d41SVinod Koul #include <linux/acpi.h>
114abbd783SPaul Gortmaker #include <linux/export.h>
124a98a6b2SBard Liao #include <linux/interrupt.h>
133fc40449SVinod Koul #include <linux/io.h>
144abbd783SPaul Gortmaker #include <linux/module.h>
15*29a269c6SPierre-Louis Bossart #include <linux/auxiliary_bus.h>
16ebf878edSPierre-Louis Bossart #include <linux/pm_runtime.h>
17d62a7d41SVinod Koul #include <linux/soundwire/sdw_intel.h>
18b6109dd6SPierre-Louis Bossart #include "cadence_master.h"
19d62a7d41SVinod Koul #include "intel.h"
20d62a7d41SVinod Koul 
21d62a7d41SVinod Koul #define SDW_SHIM_LCAP		0x0
22d62a7d41SVinod Koul #define SDW_SHIM_BASE		0x2C000
23d62a7d41SVinod Koul #define SDW_ALH_BASE		0x2C800
24d62a7d41SVinod Koul #define SDW_LINK_BASE		0x30000
25d62a7d41SVinod Koul #define SDW_LINK_SIZE		0x10000
26d62a7d41SVinod Koul 
27*29a269c6SPierre-Louis Bossart static void intel_link_dev_release(struct device *dev)
28*29a269c6SPierre-Louis Bossart {
29*29a269c6SPierre-Louis Bossart 	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
30*29a269c6SPierre-Louis Bossart 	struct sdw_intel_link_dev *ldev = auxiliary_dev_to_sdw_intel_link_dev(auxdev);
31*29a269c6SPierre-Louis Bossart 
32*29a269c6SPierre-Louis Bossart 	kfree(ldev);
33*29a269c6SPierre-Louis Bossart }
34*29a269c6SPierre-Louis Bossart 
35*29a269c6SPierre-Louis Bossart /* alloc, init and add link devices */
36*29a269c6SPierre-Louis Bossart static struct sdw_intel_link_dev *intel_link_dev_register(struct sdw_intel_res *res,
37*29a269c6SPierre-Louis Bossart 							  struct sdw_intel_ctx *ctx,
38*29a269c6SPierre-Louis Bossart 							  struct fwnode_handle *fwnode,
39*29a269c6SPierre-Louis Bossart 							  const char *name,
40*29a269c6SPierre-Louis Bossart 							  int link_id)
41*29a269c6SPierre-Louis Bossart {
42*29a269c6SPierre-Louis Bossart 	struct sdw_intel_link_dev *ldev;
43*29a269c6SPierre-Louis Bossart 	struct sdw_intel_link_res *link;
44*29a269c6SPierre-Louis Bossart 	struct auxiliary_device *auxdev;
45*29a269c6SPierre-Louis Bossart 	int ret;
46*29a269c6SPierre-Louis Bossart 
47*29a269c6SPierre-Louis Bossart 	ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
48*29a269c6SPierre-Louis Bossart 	if (!ldev)
49*29a269c6SPierre-Louis Bossart 		return ERR_PTR(-ENOMEM);
50*29a269c6SPierre-Louis Bossart 
51*29a269c6SPierre-Louis Bossart 	auxdev = &ldev->auxdev;
52*29a269c6SPierre-Louis Bossart 	auxdev->name = name;
53*29a269c6SPierre-Louis Bossart 	auxdev->dev.parent = res->parent;
54*29a269c6SPierre-Louis Bossart 	auxdev->dev.fwnode = fwnode;
55*29a269c6SPierre-Louis Bossart 	auxdev->dev.release = intel_link_dev_release;
56*29a269c6SPierre-Louis Bossart 
57*29a269c6SPierre-Louis Bossart 	/* we don't use an IDA since we already have a link ID */
58*29a269c6SPierre-Louis Bossart 	auxdev->id = link_id;
59*29a269c6SPierre-Louis Bossart 
60*29a269c6SPierre-Louis Bossart 	/*
61*29a269c6SPierre-Louis Bossart 	 * keep a handle on the allocated memory, to be used in all other functions.
62*29a269c6SPierre-Louis Bossart 	 * Since the same pattern is used to skip links that are not enabled, there is
63*29a269c6SPierre-Louis Bossart 	 * no need to check if ctx->ldev[i] is NULL later on.
64*29a269c6SPierre-Louis Bossart 	 */
65*29a269c6SPierre-Louis Bossart 	ctx->ldev[link_id] = ldev;
66*29a269c6SPierre-Louis Bossart 
67*29a269c6SPierre-Louis Bossart 	/* Add link information used in the driver probe */
68*29a269c6SPierre-Louis Bossart 	link = &ldev->link_res;
69*29a269c6SPierre-Louis Bossart 	link->mmio_base = res->mmio_base;
70*29a269c6SPierre-Louis Bossart 	link->registers = res->mmio_base + SDW_LINK_BASE
71*29a269c6SPierre-Louis Bossart 		+ (SDW_LINK_SIZE * link_id);
72*29a269c6SPierre-Louis Bossart 	link->shim = res->mmio_base + SDW_SHIM_BASE;
73*29a269c6SPierre-Louis Bossart 	link->alh = res->mmio_base + SDW_ALH_BASE;
74*29a269c6SPierre-Louis Bossart 
75*29a269c6SPierre-Louis Bossart 	link->ops = res->ops;
76*29a269c6SPierre-Louis Bossart 	link->dev = res->dev;
77*29a269c6SPierre-Louis Bossart 
78*29a269c6SPierre-Louis Bossart 	link->clock_stop_quirks = res->clock_stop_quirks;
79*29a269c6SPierre-Louis Bossart 	link->shim_lock = &ctx->shim_lock;
80*29a269c6SPierre-Louis Bossart 	link->shim_mask = &ctx->shim_mask;
81*29a269c6SPierre-Louis Bossart 	link->link_mask = ctx->link_mask;
82*29a269c6SPierre-Louis Bossart 
83*29a269c6SPierre-Louis Bossart 	/* now follow the two-step init/add sequence */
84*29a269c6SPierre-Louis Bossart 	ret = auxiliary_device_init(auxdev);
85*29a269c6SPierre-Louis Bossart 	if (ret < 0) {
86*29a269c6SPierre-Louis Bossart 		dev_err(res->parent, "failed to initialize link dev %s link_id %d\n",
87*29a269c6SPierre-Louis Bossart 			name, link_id);
88*29a269c6SPierre-Louis Bossart 		kfree(ldev);
89*29a269c6SPierre-Louis Bossart 		return ERR_PTR(ret);
90*29a269c6SPierre-Louis Bossart 	}
91*29a269c6SPierre-Louis Bossart 
92*29a269c6SPierre-Louis Bossart 	ret = auxiliary_device_add(&ldev->auxdev);
93*29a269c6SPierre-Louis Bossart 	if (ret < 0) {
94*29a269c6SPierre-Louis Bossart 		dev_err(res->parent, "failed to add link dev %s link_id %d\n",
95*29a269c6SPierre-Louis Bossart 			ldev->auxdev.name, link_id);
96*29a269c6SPierre-Louis Bossart 		/* ldev will be freed with the put_device() and .release sequence */
97*29a269c6SPierre-Louis Bossart 		auxiliary_device_uninit(&ldev->auxdev);
98*29a269c6SPierre-Louis Bossart 		return ERR_PTR(ret);
99*29a269c6SPierre-Louis Bossart 	}
100*29a269c6SPierre-Louis Bossart 
101*29a269c6SPierre-Louis Bossart 	return ldev;
102*29a269c6SPierre-Louis Bossart }
103*29a269c6SPierre-Louis Bossart 
104*29a269c6SPierre-Louis Bossart static void intel_link_dev_unregister(struct sdw_intel_link_dev *ldev)
105*29a269c6SPierre-Louis Bossart {
106*29a269c6SPierre-Louis Bossart 	auxiliary_device_delete(&ldev->auxdev);
107*29a269c6SPierre-Louis Bossart 	auxiliary_device_uninit(&ldev->auxdev);
108*29a269c6SPierre-Louis Bossart }
109*29a269c6SPierre-Louis Bossart 
1106d2c6669SPierre-Louis Bossart static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
111d62a7d41SVinod Koul {
112*29a269c6SPierre-Louis Bossart 	struct sdw_intel_link_dev *ldev;
1136d2c6669SPierre-Louis Bossart 	u32 link_mask;
114d62a7d41SVinod Koul 	int i;
115d62a7d41SVinod Koul 
1166d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
1176d2c6669SPierre-Louis Bossart 
118*29a269c6SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++) {
1196d2c6669SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
1206d2c6669SPierre-Louis Bossart 			continue;
1216d2c6669SPierre-Louis Bossart 
122*29a269c6SPierre-Louis Bossart 		ldev = ctx->ldev[i];
123ab996b29SPierre-Louis Bossart 
124*29a269c6SPierre-Louis Bossart 		pm_runtime_disable(&ldev->auxdev.dev);
125*29a269c6SPierre-Louis Bossart 		if (!ldev->link_res.clock_stop_quirks)
126*29a269c6SPierre-Louis Bossart 			pm_runtime_put_noidle(ldev->link_res.dev);
127*29a269c6SPierre-Louis Bossart 
128*29a269c6SPierre-Louis Bossart 		intel_link_dev_unregister(ldev);
129ebf878edSPierre-Louis Bossart 	}
130d62a7d41SVinod Koul 
131d62a7d41SVinod Koul 	return 0;
132d62a7d41SVinod Koul }
133d62a7d41SVinod Koul 
13412b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIC2             (0x10)
13512b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIS2             (0x14)
13612b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIC2_SNDW        BIT(5)
13712b16146SPierre-Louis Bossart 
13812b16146SPierre-Louis Bossart /**
13912b16146SPierre-Louis Bossart  * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ
14012b16146SPierre-Louis Bossart  * @mmio_base: The mmio base of the control register
14112b16146SPierre-Louis Bossart  * @enable: true if enable
14212b16146SPierre-Louis Bossart  */
14312b16146SPierre-Louis Bossart void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
14412b16146SPierre-Louis Bossart {
14512b16146SPierre-Louis Bossart 	u32 val;
14612b16146SPierre-Louis Bossart 
14712b16146SPierre-Louis Bossart 	val = readl(mmio_base + HDA_DSP_REG_ADSPIC2);
14812b16146SPierre-Louis Bossart 
14912b16146SPierre-Louis Bossart 	if (enable)
15012b16146SPierre-Louis Bossart 		val |= HDA_DSP_REG_ADSPIC2_SNDW;
15112b16146SPierre-Louis Bossart 	else
15212b16146SPierre-Louis Bossart 		val &= ~HDA_DSP_REG_ADSPIC2_SNDW;
15312b16146SPierre-Louis Bossart 
15412b16146SPierre-Louis Bossart 	writel(val, mmio_base + HDA_DSP_REG_ADSPIC2);
15512b16146SPierre-Louis Bossart }
1568459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);
15712b16146SPierre-Louis Bossart 
1584a98a6b2SBard Liao irqreturn_t sdw_intel_thread(int irq, void *dev_id)
1594a98a6b2SBard Liao {
1604a98a6b2SBard Liao 	struct sdw_intel_ctx *ctx = dev_id;
1614a98a6b2SBard Liao 	struct sdw_intel_link_res *link;
1624a98a6b2SBard Liao 
1634a98a6b2SBard Liao 	list_for_each_entry(link, &ctx->link_list, list)
1644a98a6b2SBard Liao 		sdw_cdns_irq(irq, link->cdns);
1654a98a6b2SBard Liao 
1664a98a6b2SBard Liao 	sdw_intel_enable_irq(ctx->mmio_base, true);
1674a98a6b2SBard Liao 	return IRQ_HANDLED;
1684a98a6b2SBard Liao }
1694a98a6b2SBard Liao EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
1704a98a6b2SBard Liao 
1716d2c6669SPierre-Louis Bossart static struct sdw_intel_ctx
1726d2c6669SPierre-Louis Bossart *sdw_intel_probe_controller(struct sdw_intel_res *res)
1736d2c6669SPierre-Louis Bossart {
1746d2c6669SPierre-Louis Bossart 	struct sdw_intel_link_res *link;
175*29a269c6SPierre-Louis Bossart 	struct sdw_intel_link_dev *ldev;
1766d2c6669SPierre-Louis Bossart 	struct sdw_intel_ctx *ctx;
1776d2c6669SPierre-Louis Bossart 	struct acpi_device *adev;
178a8184403SBard Liao 	struct sdw_slave *slave;
179a8184403SBard Liao 	struct list_head *node;
180a8184403SBard Liao 	struct sdw_bus *bus;
1816d2c6669SPierre-Louis Bossart 	u32 link_mask;
182a8184403SBard Liao 	int num_slaves = 0;
1836d2c6669SPierre-Louis Bossart 	int count;
1846d2c6669SPierre-Louis Bossart 	int i;
1856d2c6669SPierre-Louis Bossart 
1866d2c6669SPierre-Louis Bossart 	if (!res)
1876d2c6669SPierre-Louis Bossart 		return NULL;
1886d2c6669SPierre-Louis Bossart 
1896d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(res->handle, &adev))
1906d2c6669SPierre-Louis Bossart 		return NULL;
1916d2c6669SPierre-Louis Bossart 
1926d2c6669SPierre-Louis Bossart 	if (!res->count)
1936d2c6669SPierre-Louis Bossart 		return NULL;
1946d2c6669SPierre-Louis Bossart 
1956d2c6669SPierre-Louis Bossart 	count = res->count;
196d62a7d41SVinod Koul 	dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
197d62a7d41SVinod Koul 
198*29a269c6SPierre-Louis Bossart 	/*
199*29a269c6SPierre-Louis Bossart 	 * we need to alloc/free memory manually and can't use devm:
200*29a269c6SPierre-Louis Bossart 	 * this routine may be called from a workqueue, and not from
201*29a269c6SPierre-Louis Bossart 	 * the parent .probe.
202*29a269c6SPierre-Louis Bossart 	 * If devm_ was used, the memory might never be freed on errors.
203*29a269c6SPierre-Louis Bossart 	 */
204*29a269c6SPierre-Louis Bossart 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
205d62a7d41SVinod Koul 	if (!ctx)
206d62a7d41SVinod Koul 		return NULL;
207d62a7d41SVinod Koul 
208d62a7d41SVinod Koul 	ctx->count = count;
209d62a7d41SVinod Koul 
210*29a269c6SPierre-Louis Bossart 	/*
211*29a269c6SPierre-Louis Bossart 	 * allocate the array of pointers. The link-specific data is allocated
212*29a269c6SPierre-Louis Bossart 	 * as part of the first loop below and released with the auxiliary_device_uninit().
213*29a269c6SPierre-Louis Bossart 	 * If some links are disabled, the link pointer will remain NULL. Given that the
214*29a269c6SPierre-Louis Bossart 	 * number of links is small, this is simpler than using a list to keep track of links.
215*29a269c6SPierre-Louis Bossart 	 */
216*29a269c6SPierre-Louis Bossart 	ctx->ldev = kcalloc(ctx->count, sizeof(*ctx->ldev), GFP_KERNEL);
217*29a269c6SPierre-Louis Bossart 	if (!ctx->ldev) {
218*29a269c6SPierre-Louis Bossart 		kfree(ctx);
219*29a269c6SPierre-Louis Bossart 		return NULL;
220*29a269c6SPierre-Louis Bossart 	}
221*29a269c6SPierre-Louis Bossart 
2226d2c6669SPierre-Louis Bossart 	ctx->mmio_base = res->mmio_base;
2236d2c6669SPierre-Louis Bossart 	ctx->link_mask = res->link_mask;
2246d2c6669SPierre-Louis Bossart 	ctx->handle = res->handle;
2254a17c441SPierre-Louis Bossart 	mutex_init(&ctx->shim_lock);
2266d2c6669SPierre-Louis Bossart 
2276d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
228d62a7d41SVinod Koul 
2294a98a6b2SBard Liao 	INIT_LIST_HEAD(&ctx->link_list);
2304a98a6b2SBard Liao 
231*29a269c6SPierre-Louis Bossart 	for (i = 0; i < count; i++) {
232*29a269c6SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
23350302fc7SPierre-Louis Bossart 			continue;
23450302fc7SPierre-Louis Bossart 
235*29a269c6SPierre-Louis Bossart 		/*
236*29a269c6SPierre-Louis Bossart 		 * init and add a device for each link
237*29a269c6SPierre-Louis Bossart 		 *
238*29a269c6SPierre-Louis Bossart 		 * The name of the device will be soundwire_intel.link.[i],
239*29a269c6SPierre-Louis Bossart 		 * with the "soundwire_intel" module prefix automatically added
240*29a269c6SPierre-Louis Bossart 		 * by the auxiliary bus core.
241*29a269c6SPierre-Louis Bossart 		 */
242*29a269c6SPierre-Louis Bossart 		ldev = intel_link_dev_register(res,
243*29a269c6SPierre-Louis Bossart 					       ctx,
244*29a269c6SPierre-Louis Bossart 					       acpi_fwnode_handle(adev),
245*29a269c6SPierre-Louis Bossart 					       "link",
246*29a269c6SPierre-Louis Bossart 					       i);
247*29a269c6SPierre-Louis Bossart 		if (IS_ERR(ldev))
2486d2c6669SPierre-Louis Bossart 			goto err;
249*29a269c6SPierre-Louis Bossart 
250*29a269c6SPierre-Louis Bossart 		link = &ldev->link_res;
251*29a269c6SPierre-Louis Bossart 		link->cdns = dev_get_drvdata(&ldev->auxdev.dev);
2524a98a6b2SBard Liao 
25314968dd3SBard Liao 		if (!link->cdns) {
25414968dd3SBard Liao 			dev_err(&adev->dev, "failed to get link->cdns\n");
25514968dd3SBard Liao 			/*
25614968dd3SBard Liao 			 * 1 will be subtracted from i in the err label, but we need to call
25714968dd3SBard Liao 			 * intel_link_dev_unregister for this ldev, so plus 1 now
25814968dd3SBard Liao 			 */
25914968dd3SBard Liao 			i++;
26014968dd3SBard Liao 			goto err;
26114968dd3SBard Liao 		}
2624a98a6b2SBard Liao 		list_add_tail(&link->list, &ctx->link_list);
263a8184403SBard Liao 		bus = &link->cdns->bus;
264a8184403SBard Liao 		/* Calculate number of slaves */
265a8184403SBard Liao 		list_for_each(node, &bus->slaves)
266a8184403SBard Liao 			num_slaves++;
267a8184403SBard Liao 	}
268a8184403SBard Liao 
269*29a269c6SPierre-Louis Bossart 	ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
270a8184403SBard Liao 	if (!ctx->ids)
271a8184403SBard Liao 		goto err;
272a8184403SBard Liao 
273a8184403SBard Liao 	ctx->num_slaves = num_slaves;
274a8184403SBard Liao 	i = 0;
275a8184403SBard Liao 	list_for_each_entry(link, &ctx->link_list, list) {
276a8184403SBard Liao 		bus = &link->cdns->bus;
277a8184403SBard Liao 		list_for_each_entry(slave, &bus->slaves, node) {
278a8184403SBard Liao 			ctx->ids[i].id = slave->id;
279a8184403SBard Liao 			ctx->ids[i].link_id = bus->link_id;
280a8184403SBard Liao 			i++;
281a8184403SBard Liao 		}
282d62a7d41SVinod Koul 	}
283d62a7d41SVinod Koul 
284d62a7d41SVinod Koul 	return ctx;
285d62a7d41SVinod Koul 
2866d2c6669SPierre-Louis Bossart err:
287*29a269c6SPierre-Louis Bossart 	while (i--) {
288*29a269c6SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
289*29a269c6SPierre-Louis Bossart 			continue;
290*29a269c6SPierre-Louis Bossart 		ldev = ctx->ldev[i];
291*29a269c6SPierre-Louis Bossart 		intel_link_dev_unregister(ldev);
292*29a269c6SPierre-Louis Bossart 	}
293*29a269c6SPierre-Louis Bossart 	kfree(ctx->ldev);
294*29a269c6SPierre-Louis Bossart 	kfree(ctx);
295d62a7d41SVinod Koul 	return NULL;
296d62a7d41SVinod Koul }
297d62a7d41SVinod Koul 
2986d2c6669SPierre-Louis Bossart static int
2996d2c6669SPierre-Louis Bossart sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
3006d2c6669SPierre-Louis Bossart {
3016d2c6669SPierre-Louis Bossart 	struct acpi_device *adev;
302*29a269c6SPierre-Louis Bossart 	struct sdw_intel_link_dev *ldev;
3036d2c6669SPierre-Louis Bossart 	u32 caps;
3046d2c6669SPierre-Louis Bossart 	u32 link_mask;
3056d2c6669SPierre-Louis Bossart 	int i;
3066d2c6669SPierre-Louis Bossart 
3076d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(ctx->handle, &adev))
3086d2c6669SPierre-Louis Bossart 		return -EINVAL;
3096d2c6669SPierre-Louis Bossart 
3106d2c6669SPierre-Louis Bossart 	/* Check SNDWLCAP.LCOUNT */
3116d2c6669SPierre-Louis Bossart 	caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
3126d2c6669SPierre-Louis Bossart 	caps &= GENMASK(2, 0);
3136d2c6669SPierre-Louis Bossart 
3146d2c6669SPierre-Louis Bossart 	/* Check HW supported vs property value */
3156d2c6669SPierre-Louis Bossart 	if (caps < ctx->count) {
3166d2c6669SPierre-Louis Bossart 		dev_err(&adev->dev,
3176d2c6669SPierre-Louis Bossart 			"BIOS master count is larger than hardware capabilities\n");
3186d2c6669SPierre-Louis Bossart 		return -EINVAL;
3196d2c6669SPierre-Louis Bossart 	}
3206d2c6669SPierre-Louis Bossart 
321*29a269c6SPierre-Louis Bossart 	if (!ctx->ldev)
3226d2c6669SPierre-Louis Bossart 		return -EINVAL;
3236d2c6669SPierre-Louis Bossart 
3246d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
3256d2c6669SPierre-Louis Bossart 
3266d2c6669SPierre-Louis Bossart 	/* Startup SDW Master devices */
327*29a269c6SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++) {
3286d2c6669SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
3296d2c6669SPierre-Louis Bossart 			continue;
3306d2c6669SPierre-Louis Bossart 
331*29a269c6SPierre-Louis Bossart 		ldev = ctx->ldev[i];
332ab996b29SPierre-Louis Bossart 
333*29a269c6SPierre-Louis Bossart 		intel_link_startup(&ldev->auxdev);
334*29a269c6SPierre-Louis Bossart 
335*29a269c6SPierre-Louis Bossart 		if (!ldev->link_res.clock_stop_quirks) {
336ab996b29SPierre-Louis Bossart 			/*
337ab996b29SPierre-Louis Bossart 			 * we need to prevent the parent PCI device
338ab996b29SPierre-Louis Bossart 			 * from entering pm_runtime suspend, so that
339ab996b29SPierre-Louis Bossart 			 * power rails to the SoundWire IP are not
340ab996b29SPierre-Louis Bossart 			 * turned off.
341ab996b29SPierre-Louis Bossart 			 */
342*29a269c6SPierre-Louis Bossart 			pm_runtime_get_noresume(ldev->link_res.dev);
343ab996b29SPierre-Louis Bossart 		}
3446d2c6669SPierre-Louis Bossart 	}
3456d2c6669SPierre-Louis Bossart 
3466d2c6669SPierre-Louis Bossart 	return 0;
3476d2c6669SPierre-Louis Bossart }
3486d2c6669SPierre-Louis Bossart 
349d62a7d41SVinod Koul /**
3506d2c6669SPierre-Louis Bossart  * sdw_intel_probe() - SoundWire Intel probe routine
3516d2c6669SPierre-Louis Bossart  * @res: resource data
3526d2c6669SPierre-Louis Bossart  *
353*29a269c6SPierre-Louis Bossart  * This registers an auxiliary device for each Master handled by the controller,
354*29a269c6SPierre-Louis Bossart  * and SoundWire Master and Slave devices will be created by the auxiliary
3556d2c6669SPierre-Louis Bossart  * device probe. All the information necessary is stored in the context, and
3566d2c6669SPierre-Louis Bossart  * the res argument pointer can be freed after this step.
3576d2c6669SPierre-Louis Bossart  * This function will be called after sdw_intel_acpi_scan() by SOF probe.
3586d2c6669SPierre-Louis Bossart  */
3596d2c6669SPierre-Louis Bossart struct sdw_intel_ctx
3606d2c6669SPierre-Louis Bossart *sdw_intel_probe(struct sdw_intel_res *res)
3616d2c6669SPierre-Louis Bossart {
3626d2c6669SPierre-Louis Bossart 	return sdw_intel_probe_controller(res);
3636d2c6669SPierre-Louis Bossart }
3648459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT);
3656d2c6669SPierre-Louis Bossart 
3666d2c6669SPierre-Louis Bossart /**
3676d2c6669SPierre-Louis Bossart  * sdw_intel_startup() - SoundWire Intel startup
3686d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
3696d2c6669SPierre-Louis Bossart  *
3706d2c6669SPierre-Louis Bossart  * Startup Intel SoundWire controller. This function will be called after
3716d2c6669SPierre-Louis Bossart  * Intel Audio DSP is powered up.
3726d2c6669SPierre-Louis Bossart  */
3736d2c6669SPierre-Louis Bossart int sdw_intel_startup(struct sdw_intel_ctx *ctx)
3746d2c6669SPierre-Louis Bossart {
3756d2c6669SPierre-Louis Bossart 	return sdw_intel_startup_controller(ctx);
3766d2c6669SPierre-Louis Bossart }
3778459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
3786d2c6669SPierre-Louis Bossart /**
379d62a7d41SVinod Koul  * sdw_intel_exit() - SoundWire Intel exit
3806d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
381d62a7d41SVinod Koul  *
382d62a7d41SVinod Koul  * Delete the controller instances created and cleanup
383d62a7d41SVinod Koul  */
384f98f690fSPierre-Louis Bossart void sdw_intel_exit(struct sdw_intel_ctx *ctx)
385d62a7d41SVinod Koul {
3866d2c6669SPierre-Louis Bossart 	sdw_intel_cleanup(ctx);
387*29a269c6SPierre-Louis Bossart 	kfree(ctx->ids);
388*29a269c6SPierre-Louis Bossart 	kfree(ctx->ldev);
389*29a269c6SPierre-Louis Bossart 	kfree(ctx);
390d62a7d41SVinod Koul }
3918459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
392d62a7d41SVinod Koul 
393ab2c9132SRander Wang void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
394ab2c9132SRander Wang {
395*29a269c6SPierre-Louis Bossart 	struct sdw_intel_link_dev *ldev;
396ab2c9132SRander Wang 	u32 link_mask;
397ab2c9132SRander Wang 	int i;
398ab2c9132SRander Wang 
399*29a269c6SPierre-Louis Bossart 	if (!ctx->ldev)
400ab2c9132SRander Wang 		return;
401ab2c9132SRander Wang 
402ab2c9132SRander Wang 	link_mask = ctx->link_mask;
403ab2c9132SRander Wang 
404ab2c9132SRander Wang 	/* Startup SDW Master devices */
405*29a269c6SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++) {
406ab2c9132SRander Wang 		if (!(link_mask & BIT(i)))
407ab2c9132SRander Wang 			continue;
408ab2c9132SRander Wang 
409*29a269c6SPierre-Louis Bossart 		ldev = ctx->ldev[i];
410*29a269c6SPierre-Louis Bossart 
411*29a269c6SPierre-Louis Bossart 		intel_link_process_wakeen_event(&ldev->auxdev);
412ab2c9132SRander Wang 	}
413ab2c9132SRander Wang }
414ab2c9132SRander Wang EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT);
415ab2c9132SRander Wang 
416d62a7d41SVinod Koul MODULE_LICENSE("Dual BSD/GPL");
417d62a7d41SVinod Koul MODULE_DESCRIPTION("Intel Soundwire Init Library");
418