xref: /linux/drivers/soundwire/intel_init.c (revision a81844034e5b382df6cc06bc2943ae24be797afd)
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>
15d62a7d41SVinod Koul #include <linux/platform_device.h>
16d62a7d41SVinod Koul #include <linux/soundwire/sdw_intel.h>
17b6109dd6SPierre-Louis Bossart #include "cadence_master.h"
18d62a7d41SVinod Koul #include "intel.h"
19d62a7d41SVinod Koul 
206f11586fSPierre-Louis Bossart #define SDW_LINK_TYPE		4 /* from Intel ACPI documentation */
21d62a7d41SVinod Koul #define SDW_MAX_LINKS		4
22d62a7d41SVinod Koul #define SDW_SHIM_LCAP		0x0
23d62a7d41SVinod Koul #define SDW_SHIM_BASE		0x2C000
24d62a7d41SVinod Koul #define SDW_ALH_BASE		0x2C800
25d62a7d41SVinod Koul #define SDW_LINK_BASE		0x30000
26d62a7d41SVinod Koul #define SDW_LINK_SIZE		0x10000
27d62a7d41SVinod Koul 
286d2c6669SPierre-Louis Bossart static int ctrl_link_mask;
296d2c6669SPierre-Louis Bossart module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
3050302fc7SPierre-Louis Bossart MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
3150302fc7SPierre-Louis Bossart 
326d2c6669SPierre-Louis Bossart static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
336d2c6669SPierre-Louis Bossart {
346d2c6669SPierre-Louis Bossart 	struct fwnode_handle *link;
356d2c6669SPierre-Louis Bossart 	char name[32];
366d2c6669SPierre-Louis Bossart 	u32 quirk_mask = 0;
376d2c6669SPierre-Louis Bossart 
386d2c6669SPierre-Louis Bossart 	/* Find master handle */
396d2c6669SPierre-Louis Bossart 	snprintf(name, sizeof(name),
406d2c6669SPierre-Louis Bossart 		 "mipi-sdw-link-%d-subproperties", i);
416d2c6669SPierre-Louis Bossart 
426d2c6669SPierre-Louis Bossart 	link = fwnode_get_named_child_node(fw_node, name);
436d2c6669SPierre-Louis Bossart 	if (!link)
446d2c6669SPierre-Louis Bossart 		return false;
456d2c6669SPierre-Louis Bossart 
466d2c6669SPierre-Louis Bossart 	fwnode_property_read_u32(link,
476d2c6669SPierre-Louis Bossart 				 "intel-quirk-mask",
486d2c6669SPierre-Louis Bossart 				 &quirk_mask);
496d2c6669SPierre-Louis Bossart 
506d2c6669SPierre-Louis Bossart 	if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
516d2c6669SPierre-Louis Bossart 		return false;
526d2c6669SPierre-Louis Bossart 
536d2c6669SPierre-Louis Bossart 	return true;
546d2c6669SPierre-Louis Bossart }
556d2c6669SPierre-Louis Bossart 
566d2c6669SPierre-Louis Bossart static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
57d62a7d41SVinod Koul {
58f98f690fSPierre-Louis Bossart 	struct sdw_intel_link_res *link = ctx->links;
596d2c6669SPierre-Louis Bossart 	u32 link_mask;
60d62a7d41SVinod Koul 	int i;
61d62a7d41SVinod Koul 
62d62a7d41SVinod Koul 	if (!link)
63d62a7d41SVinod Koul 		return 0;
64d62a7d41SVinod Koul 
656d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
666d2c6669SPierre-Louis Bossart 
676d2c6669SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++, link++) {
686d2c6669SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
696d2c6669SPierre-Louis Bossart 			continue;
706d2c6669SPierre-Louis Bossart 
71d62a7d41SVinod Koul 		if (link->pdev)
72d62a7d41SVinod Koul 			platform_device_unregister(link->pdev);
73d62a7d41SVinod Koul 	}
74d62a7d41SVinod Koul 
75d62a7d41SVinod Koul 	return 0;
76d62a7d41SVinod Koul }
77d62a7d41SVinod Koul 
786d2c6669SPierre-Louis Bossart static int
796d2c6669SPierre-Louis Bossart sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
80d62a7d41SVinod Koul {
81d62a7d41SVinod Koul 	struct acpi_device *adev;
82d62a7d41SVinod Koul 	int ret, i;
83d62a7d41SVinod Koul 	u8 count;
84d62a7d41SVinod Koul 
856d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(info->handle, &adev))
866d2c6669SPierre-Louis Bossart 		return -EINVAL;
87d62a7d41SVinod Koul 
88d62a7d41SVinod Koul 	/* Found controller, find links supported */
89d62a7d41SVinod Koul 	count = 0;
90d62a7d41SVinod Koul 	ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
91d62a7d41SVinod Koul 					    "mipi-sdw-master-count", &count, 1);
92d62a7d41SVinod Koul 
936d2c6669SPierre-Louis Bossart 	/*
946d2c6669SPierre-Louis Bossart 	 * In theory we could check the number of links supported in
956d2c6669SPierre-Louis Bossart 	 * hardware, but in that step we cannot assume SoundWire IP is
966d2c6669SPierre-Louis Bossart 	 * powered.
976d2c6669SPierre-Louis Bossart 	 *
986d2c6669SPierre-Louis Bossart 	 * In addition, if the BIOS doesn't even provide this
996d2c6669SPierre-Louis Bossart 	 * 'master-count' property then all the inits based on link
1006d2c6669SPierre-Louis Bossart 	 * masks will fail as well.
1016d2c6669SPierre-Louis Bossart 	 *
1026d2c6669SPierre-Louis Bossart 	 * We will check the hardware capabilities in the startup() step
1036d2c6669SPierre-Louis Bossart 	 */
1046d2c6669SPierre-Louis Bossart 
105d62a7d41SVinod Koul 	if (ret) {
106d62a7d41SVinod Koul 		dev_err(&adev->dev,
107d62a7d41SVinod Koul 			"Failed to read mipi-sdw-master-count: %d\n", ret);
1086d2c6669SPierre-Louis Bossart 		return -EINVAL;
109d62a7d41SVinod Koul 	}
110d62a7d41SVinod Koul 
111d62a7d41SVinod Koul 	/* Check count is within bounds */
112d62a7d41SVinod Koul 	if (count > SDW_MAX_LINKS) {
113d62a7d41SVinod Koul 		dev_err(&adev->dev, "Link count %d exceeds max %d\n",
114d62a7d41SVinod Koul 			count, SDW_MAX_LINKS);
1156d2c6669SPierre-Louis Bossart 		return -EINVAL;
1166f7219feSGuennadi Liakhovetski 	}
1176f7219feSGuennadi Liakhovetski 
1186f7219feSGuennadi Liakhovetski 	if (!count) {
119432732b8SPierre-Louis Bossart 		dev_warn(&adev->dev, "No SoundWire links detected\n");
1206d2c6669SPierre-Louis Bossart 		return -EINVAL;
1216d2c6669SPierre-Louis Bossart 	}
1226d2c6669SPierre-Louis Bossart 	dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count);
1236d2c6669SPierre-Louis Bossart 
1246d2c6669SPierre-Louis Bossart 	info->count = count;
1256d2c6669SPierre-Louis Bossart 	info->link_mask = 0;
1266d2c6669SPierre-Louis Bossart 
1276d2c6669SPierre-Louis Bossart 	for (i = 0; i < count; i++) {
1286d2c6669SPierre-Louis Bossart 		if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) {
1296d2c6669SPierre-Louis Bossart 			dev_dbg(&adev->dev,
1306d2c6669SPierre-Louis Bossart 				"Link %d masked, will not be enabled\n", i);
1316d2c6669SPierre-Louis Bossart 			continue;
132d62a7d41SVinod Koul 		}
133d62a7d41SVinod Koul 
1346d2c6669SPierre-Louis Bossart 		if (!is_link_enabled(acpi_fwnode_handle(adev), i)) {
1356d2c6669SPierre-Louis Bossart 			dev_dbg(&adev->dev,
1366d2c6669SPierre-Louis Bossart 				"Link %d not selected in firmware\n", i);
1376d2c6669SPierre-Louis Bossart 			continue;
1386d2c6669SPierre-Louis Bossart 		}
1396d2c6669SPierre-Louis Bossart 
1406d2c6669SPierre-Louis Bossart 		info->link_mask |= BIT(i);
1416d2c6669SPierre-Louis Bossart 	}
1426d2c6669SPierre-Louis Bossart 
1436d2c6669SPierre-Louis Bossart 	return 0;
1446d2c6669SPierre-Louis Bossart }
1456d2c6669SPierre-Louis Bossart 
14612b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIC2             (0x10)
14712b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIS2             (0x14)
14812b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIC2_SNDW        BIT(5)
14912b16146SPierre-Louis Bossart 
15012b16146SPierre-Louis Bossart /**
15112b16146SPierre-Louis Bossart  * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ
15212b16146SPierre-Louis Bossart  * @mmio_base: The mmio base of the control register
15312b16146SPierre-Louis Bossart  * @enable: true if enable
15412b16146SPierre-Louis Bossart  */
15512b16146SPierre-Louis Bossart void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
15612b16146SPierre-Louis Bossart {
15712b16146SPierre-Louis Bossart 	u32 val;
15812b16146SPierre-Louis Bossart 
15912b16146SPierre-Louis Bossart 	val = readl(mmio_base + HDA_DSP_REG_ADSPIC2);
16012b16146SPierre-Louis Bossart 
16112b16146SPierre-Louis Bossart 	if (enable)
16212b16146SPierre-Louis Bossart 		val |= HDA_DSP_REG_ADSPIC2_SNDW;
16312b16146SPierre-Louis Bossart 	else
16412b16146SPierre-Louis Bossart 		val &= ~HDA_DSP_REG_ADSPIC2_SNDW;
16512b16146SPierre-Louis Bossart 
16612b16146SPierre-Louis Bossart 	writel(val, mmio_base + HDA_DSP_REG_ADSPIC2);
16712b16146SPierre-Louis Bossart }
1688459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);
16912b16146SPierre-Louis Bossart 
1704a98a6b2SBard Liao irqreturn_t sdw_intel_thread(int irq, void *dev_id)
1714a98a6b2SBard Liao {
1724a98a6b2SBard Liao 	struct sdw_intel_ctx *ctx = dev_id;
1734a98a6b2SBard Liao 	struct sdw_intel_link_res *link;
1744a98a6b2SBard Liao 
1754a98a6b2SBard Liao 	list_for_each_entry(link, &ctx->link_list, list)
1764a98a6b2SBard Liao 		sdw_cdns_irq(irq, link->cdns);
1774a98a6b2SBard Liao 
1784a98a6b2SBard Liao 	sdw_intel_enable_irq(ctx->mmio_base, true);
1794a98a6b2SBard Liao 	return IRQ_HANDLED;
1804a98a6b2SBard Liao }
1814a98a6b2SBard Liao EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
1824a98a6b2SBard Liao 
1836d2c6669SPierre-Louis Bossart static struct sdw_intel_ctx
1846d2c6669SPierre-Louis Bossart *sdw_intel_probe_controller(struct sdw_intel_res *res)
1856d2c6669SPierre-Louis Bossart {
1866d2c6669SPierre-Louis Bossart 	struct platform_device_info pdevinfo;
1876d2c6669SPierre-Louis Bossart 	struct platform_device *pdev;
1886d2c6669SPierre-Louis Bossart 	struct sdw_intel_link_res *link;
1896d2c6669SPierre-Louis Bossart 	struct sdw_intel_ctx *ctx;
1906d2c6669SPierre-Louis Bossart 	struct acpi_device *adev;
191*a8184403SBard Liao 	struct sdw_slave *slave;
192*a8184403SBard Liao 	struct list_head *node;
193*a8184403SBard Liao 	struct sdw_bus *bus;
1946d2c6669SPierre-Louis Bossart 	u32 link_mask;
195*a8184403SBard Liao 	int num_slaves = 0;
1966d2c6669SPierre-Louis Bossart 	int count;
1976d2c6669SPierre-Louis Bossart 	int i;
1986d2c6669SPierre-Louis Bossart 
1996d2c6669SPierre-Louis Bossart 	if (!res)
2006d2c6669SPierre-Louis Bossart 		return NULL;
2016d2c6669SPierre-Louis Bossart 
2026d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(res->handle, &adev))
2036d2c6669SPierre-Louis Bossart 		return NULL;
2046d2c6669SPierre-Louis Bossart 
2056d2c6669SPierre-Louis Bossart 	if (!res->count)
2066d2c6669SPierre-Louis Bossart 		return NULL;
2076d2c6669SPierre-Louis Bossart 
2086d2c6669SPierre-Louis Bossart 	count = res->count;
209d62a7d41SVinod Koul 	dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
210d62a7d41SVinod Koul 
211dd906cc6SPierre-Louis Bossart 	ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL);
212d62a7d41SVinod Koul 	if (!ctx)
213d62a7d41SVinod Koul 		return NULL;
214d62a7d41SVinod Koul 
215d62a7d41SVinod Koul 	ctx->count = count;
216dd906cc6SPierre-Louis Bossart 	ctx->links = devm_kcalloc(&adev->dev, ctx->count,
217dd906cc6SPierre-Louis Bossart 				  sizeof(*ctx->links), GFP_KERNEL);
218d62a7d41SVinod Koul 	if (!ctx->links)
219dd906cc6SPierre-Louis Bossart 		return NULL;
220d62a7d41SVinod Koul 
2216d2c6669SPierre-Louis Bossart 	ctx->count = count;
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 
227d62a7d41SVinod Koul 	link = ctx->links;
2286d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
229d62a7d41SVinod Koul 
2304a98a6b2SBard Liao 	INIT_LIST_HEAD(&ctx->link_list);
2314a98a6b2SBard Liao 
232d62a7d41SVinod Koul 	/* Create SDW Master devices */
2336d2c6669SPierre-Louis Bossart 	for (i = 0; i < count; i++, link++) {
2349cd1c5a7SPierre-Louis Bossart 		if (!(link_mask & BIT(i))) {
23550302fc7SPierre-Louis Bossart 			dev_dbg(&adev->dev,
23650302fc7SPierre-Louis Bossart 				"Link %d masked, will not be enabled\n", i);
23750302fc7SPierre-Louis Bossart 			continue;
23850302fc7SPierre-Louis Bossart 		}
23950302fc7SPierre-Louis Bossart 
2406d2c6669SPierre-Louis Bossart 		link->mmio_base = res->mmio_base;
241f98f690fSPierre-Louis Bossart 		link->registers = res->mmio_base + SDW_LINK_BASE
242d62a7d41SVinod Koul 			+ (SDW_LINK_SIZE * i);
243f98f690fSPierre-Louis Bossart 		link->shim = res->mmio_base + SDW_SHIM_BASE;
244f98f690fSPierre-Louis Bossart 		link->alh = res->mmio_base + SDW_ALH_BASE;
245d62a7d41SVinod Koul 
246f98f690fSPierre-Louis Bossart 		link->ops = res->ops;
2474b206d34SRander Wang 		link->dev = res->dev;
248c46302ecSVinod Koul 
2494a17c441SPierre-Louis Bossart 		link->shim_lock = &ctx->shim_lock;
2504a17c441SPierre-Louis Bossart 		link->shim_mask = &ctx->shim_mask;
2514a17c441SPierre-Louis Bossart 
252d62a7d41SVinod Koul 		memset(&pdevinfo, 0, sizeof(pdevinfo));
253d62a7d41SVinod Koul 
254d62a7d41SVinod Koul 		pdevinfo.parent = res->parent;
2556d2c6669SPierre-Louis Bossart 		pdevinfo.name = "intel-sdw";
256d62a7d41SVinod Koul 		pdevinfo.id = i;
257d62a7d41SVinod Koul 		pdevinfo.fwnode = acpi_fwnode_handle(adev);
2584ab34412SPierre-Louis Bossart 		pdevinfo.data = link;
2594ab34412SPierre-Louis Bossart 		pdevinfo.size_data = sizeof(*link);
260d62a7d41SVinod Koul 
261d62a7d41SVinod Koul 		pdev = platform_device_register_full(&pdevinfo);
262d62a7d41SVinod Koul 		if (IS_ERR(pdev)) {
263d62a7d41SVinod Koul 			dev_err(&adev->dev,
264d62a7d41SVinod Koul 				"platform device creation failed: %ld\n",
265d62a7d41SVinod Koul 				PTR_ERR(pdev));
2666d2c6669SPierre-Louis Bossart 			goto err;
267d62a7d41SVinod Koul 		}
268d62a7d41SVinod Koul 		link->pdev = pdev;
2694a98a6b2SBard Liao 		link->cdns = platform_get_drvdata(pdev);
2704a98a6b2SBard Liao 
2714a98a6b2SBard Liao 		list_add_tail(&link->list, &ctx->link_list);
272*a8184403SBard Liao 		bus = &link->cdns->bus;
273*a8184403SBard Liao 		/* Calculate number of slaves */
274*a8184403SBard Liao 		list_for_each(node, &bus->slaves)
275*a8184403SBard Liao 			num_slaves++;
276*a8184403SBard Liao 	}
277*a8184403SBard Liao 
278*a8184403SBard Liao 	ctx->ids = devm_kcalloc(&adev->dev, num_slaves,
279*a8184403SBard Liao 				sizeof(*ctx->ids), GFP_KERNEL);
280*a8184403SBard Liao 	if (!ctx->ids)
281*a8184403SBard Liao 		goto err;
282*a8184403SBard Liao 
283*a8184403SBard Liao 	ctx->num_slaves = num_slaves;
284*a8184403SBard Liao 	i = 0;
285*a8184403SBard Liao 	list_for_each_entry(link, &ctx->link_list, list) {
286*a8184403SBard Liao 		bus = &link->cdns->bus;
287*a8184403SBard Liao 		list_for_each_entry(slave, &bus->slaves, node) {
288*a8184403SBard Liao 			ctx->ids[i].id = slave->id;
289*a8184403SBard Liao 			ctx->ids[i].link_id = bus->link_id;
290*a8184403SBard Liao 			i++;
291*a8184403SBard Liao 		}
292d62a7d41SVinod Koul 	}
293d62a7d41SVinod Koul 
294d62a7d41SVinod Koul 	return ctx;
295d62a7d41SVinod Koul 
2966d2c6669SPierre-Louis Bossart err:
297dd906cc6SPierre-Louis Bossart 	ctx->count = i;
2986d2c6669SPierre-Louis Bossart 	sdw_intel_cleanup(ctx);
299d62a7d41SVinod Koul 	return NULL;
300d62a7d41SVinod Koul }
301d62a7d41SVinod Koul 
3026d2c6669SPierre-Louis Bossart static int
3036d2c6669SPierre-Louis Bossart sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
3046d2c6669SPierre-Louis Bossart {
3056d2c6669SPierre-Louis Bossart 	struct acpi_device *adev;
3066d2c6669SPierre-Louis Bossart 	struct sdw_intel_link_res *link;
3076d2c6669SPierre-Louis Bossart 	u32 caps;
3086d2c6669SPierre-Louis Bossart 	u32 link_mask;
3096d2c6669SPierre-Louis Bossart 	int i;
3106d2c6669SPierre-Louis Bossart 
3116d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(ctx->handle, &adev))
3126d2c6669SPierre-Louis Bossart 		return -EINVAL;
3136d2c6669SPierre-Louis Bossart 
3146d2c6669SPierre-Louis Bossart 	/* Check SNDWLCAP.LCOUNT */
3156d2c6669SPierre-Louis Bossart 	caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
3166d2c6669SPierre-Louis Bossart 	caps &= GENMASK(2, 0);
3176d2c6669SPierre-Louis Bossart 
3186d2c6669SPierre-Louis Bossart 	/* Check HW supported vs property value */
3196d2c6669SPierre-Louis Bossart 	if (caps < ctx->count) {
3206d2c6669SPierre-Louis Bossart 		dev_err(&adev->dev,
3216d2c6669SPierre-Louis Bossart 			"BIOS master count is larger than hardware capabilities\n");
3226d2c6669SPierre-Louis Bossart 		return -EINVAL;
3236d2c6669SPierre-Louis Bossart 	}
3246d2c6669SPierre-Louis Bossart 
3256d2c6669SPierre-Louis Bossart 	if (!ctx->links)
3266d2c6669SPierre-Louis Bossart 		return -EINVAL;
3276d2c6669SPierre-Louis Bossart 
3286d2c6669SPierre-Louis Bossart 	link = ctx->links;
3296d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
3306d2c6669SPierre-Louis Bossart 
3316d2c6669SPierre-Louis Bossart 	/* Startup SDW Master devices */
3326d2c6669SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++, link++) {
3336d2c6669SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
3346d2c6669SPierre-Louis Bossart 			continue;
3356d2c6669SPierre-Louis Bossart 
3366d2c6669SPierre-Louis Bossart 		intel_master_startup(link->pdev);
3376d2c6669SPierre-Louis Bossart 	}
3386d2c6669SPierre-Louis Bossart 
3396d2c6669SPierre-Louis Bossart 	return 0;
3406d2c6669SPierre-Louis Bossart }
3416d2c6669SPierre-Louis Bossart 
342d62a7d41SVinod Koul static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
343d62a7d41SVinod Koul 				     void *cdata, void **return_value)
344d62a7d41SVinod Koul {
3456d2c6669SPierre-Louis Bossart 	struct sdw_intel_acpi_info *info = cdata;
346d62a7d41SVinod Koul 	struct acpi_device *adev;
3476f11586fSPierre-Louis Bossart 	acpi_status status;
3486f11586fSPierre-Louis Bossart 	u64 adr;
3496f11586fSPierre-Louis Bossart 
3506f11586fSPierre-Louis Bossart 	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
3516f11586fSPierre-Louis Bossart 	if (ACPI_FAILURE(status))
3526f11586fSPierre-Louis Bossart 		return AE_OK; /* keep going */
353d62a7d41SVinod Koul 
354d62a7d41SVinod Koul 	if (acpi_bus_get_device(handle, &adev)) {
355e1c815f4SVinod Koul 		pr_err("%s: Couldn't find ACPI handle\n", __func__);
356d62a7d41SVinod Koul 		return AE_NOT_FOUND;
357d62a7d41SVinod Koul 	}
358d62a7d41SVinod Koul 
3596d2c6669SPierre-Louis Bossart 	info->handle = handle;
3606f11586fSPierre-Louis Bossart 
3616f11586fSPierre-Louis Bossart 	/*
3626f11586fSPierre-Louis Bossart 	 * On some Intel platforms, multiple children of the HDAS
3636f11586fSPierre-Louis Bossart 	 * device can be found, but only one of them is the SoundWire
3646f11586fSPierre-Louis Bossart 	 * controller. The SNDW device is always exposed with
3656f11586fSPierre-Louis Bossart 	 * Name(_ADR, 0x40000000), with bits 31..28 representing the
3666f11586fSPierre-Louis Bossart 	 * SoundWire link so filter accordingly
3676f11586fSPierre-Louis Bossart 	 */
3686f11586fSPierre-Louis Bossart 	if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
3696f11586fSPierre-Louis Bossart 		return AE_OK; /* keep going */
3706f11586fSPierre-Louis Bossart 
3716f11586fSPierre-Louis Bossart 	/* device found, stop namespace walk */
3726f11586fSPierre-Louis Bossart 	return AE_CTRL_TERMINATE;
373d62a7d41SVinod Koul }
374d62a7d41SVinod Koul 
375d62a7d41SVinod Koul /**
3766d2c6669SPierre-Louis Bossart  * sdw_intel_acpi_scan() - SoundWire Intel init routine
377d62a7d41SVinod Koul  * @parent_handle: ACPI parent handle
3786d2c6669SPierre-Louis Bossart  * @info: description of what firmware/DSDT tables expose
379d62a7d41SVinod Koul  *
3806d2c6669SPierre-Louis Bossart  * This scans the namespace and queries firmware to figure out which
3816d2c6669SPierre-Louis Bossart  * links to enable. A follow-up use of sdw_intel_probe() and
3826d2c6669SPierre-Louis Bossart  * sdw_intel_startup() is required for creation of devices and bus
3836d2c6669SPierre-Louis Bossart  * startup
384d62a7d41SVinod Koul  */
3856d2c6669SPierre-Louis Bossart int sdw_intel_acpi_scan(acpi_handle *parent_handle,
3866d2c6669SPierre-Louis Bossart 			struct sdw_intel_acpi_info *info)
387d62a7d41SVinod Koul {
388d62a7d41SVinod Koul 	acpi_status status;
389d62a7d41SVinod Koul 
390d62a7d41SVinod Koul 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
391d62a7d41SVinod Koul 				     parent_handle, 1,
392d62a7d41SVinod Koul 				     sdw_intel_acpi_cb,
3936d2c6669SPierre-Louis Bossart 				     NULL, info, NULL);
394d62a7d41SVinod Koul 	if (ACPI_FAILURE(status))
3956d2c6669SPierre-Louis Bossart 		return -ENODEV;
396d62a7d41SVinod Koul 
3976d2c6669SPierre-Louis Bossart 	return sdw_intel_scan_controller(info);
398d62a7d41SVinod Koul }
3998459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT);
400d62a7d41SVinod Koul 
401d62a7d41SVinod Koul /**
4026d2c6669SPierre-Louis Bossart  * sdw_intel_probe() - SoundWire Intel probe routine
4036d2c6669SPierre-Louis Bossart  * @res: resource data
4046d2c6669SPierre-Louis Bossart  *
4056d2c6669SPierre-Louis Bossart  * This registers a platform device for each Master handled by the controller,
4066d2c6669SPierre-Louis Bossart  * and SoundWire Master and Slave devices will be created by the platform
4076d2c6669SPierre-Louis Bossart  * device probe. All the information necessary is stored in the context, and
4086d2c6669SPierre-Louis Bossart  * the res argument pointer can be freed after this step.
4096d2c6669SPierre-Louis Bossart  * This function will be called after sdw_intel_acpi_scan() by SOF probe.
4106d2c6669SPierre-Louis Bossart  */
4116d2c6669SPierre-Louis Bossart struct sdw_intel_ctx
4126d2c6669SPierre-Louis Bossart *sdw_intel_probe(struct sdw_intel_res *res)
4136d2c6669SPierre-Louis Bossart {
4146d2c6669SPierre-Louis Bossart 	return sdw_intel_probe_controller(res);
4156d2c6669SPierre-Louis Bossart }
4168459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT);
4176d2c6669SPierre-Louis Bossart 
4186d2c6669SPierre-Louis Bossart /**
4196d2c6669SPierre-Louis Bossart  * sdw_intel_startup() - SoundWire Intel startup
4206d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
4216d2c6669SPierre-Louis Bossart  *
4226d2c6669SPierre-Louis Bossart  * Startup Intel SoundWire controller. This function will be called after
4236d2c6669SPierre-Louis Bossart  * Intel Audio DSP is powered up.
4246d2c6669SPierre-Louis Bossart  */
4256d2c6669SPierre-Louis Bossart int sdw_intel_startup(struct sdw_intel_ctx *ctx)
4266d2c6669SPierre-Louis Bossart {
4276d2c6669SPierre-Louis Bossart 	return sdw_intel_startup_controller(ctx);
4286d2c6669SPierre-Louis Bossart }
4298459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
4306d2c6669SPierre-Louis Bossart /**
431d62a7d41SVinod Koul  * sdw_intel_exit() - SoundWire Intel exit
4326d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
433d62a7d41SVinod Koul  *
434d62a7d41SVinod Koul  * Delete the controller instances created and cleanup
435d62a7d41SVinod Koul  */
436f98f690fSPierre-Louis Bossart void sdw_intel_exit(struct sdw_intel_ctx *ctx)
437d62a7d41SVinod Koul {
4386d2c6669SPierre-Louis Bossart 	sdw_intel_cleanup(ctx);
439d62a7d41SVinod Koul }
4408459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
441d62a7d41SVinod Koul 
442ab2c9132SRander Wang void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
443ab2c9132SRander Wang {
444ab2c9132SRander Wang 	struct sdw_intel_link_res *link;
445ab2c9132SRander Wang 	u32 link_mask;
446ab2c9132SRander Wang 	int i;
447ab2c9132SRander Wang 
448ab2c9132SRander Wang 	if (!ctx->links)
449ab2c9132SRander Wang 		return;
450ab2c9132SRander Wang 
451ab2c9132SRander Wang 	link = ctx->links;
452ab2c9132SRander Wang 	link_mask = ctx->link_mask;
453ab2c9132SRander Wang 
454ab2c9132SRander Wang 	/* Startup SDW Master devices */
455ab2c9132SRander Wang 	for (i = 0; i < ctx->count; i++, link++) {
456ab2c9132SRander Wang 		if (!(link_mask & BIT(i)))
457ab2c9132SRander Wang 			continue;
458ab2c9132SRander Wang 
459ab2c9132SRander Wang 		intel_master_process_wakeen_event(link->pdev);
460ab2c9132SRander Wang 	}
461ab2c9132SRander Wang }
462ab2c9132SRander Wang EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT);
463ab2c9132SRander Wang 
464d62a7d41SVinod Koul MODULE_LICENSE("Dual BSD/GPL");
465d62a7d41SVinod Koul MODULE_DESCRIPTION("Intel Soundwire Init Library");
466