xref: /linux/drivers/soundwire/intel_init.c (revision 4a98a6b2fa75cf90863b7898457b211ace587e8a)
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>
12*4a98a6b2SBard 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 
170*4a98a6b2SBard Liao irqreturn_t sdw_intel_thread(int irq, void *dev_id)
171*4a98a6b2SBard Liao {
172*4a98a6b2SBard Liao 	struct sdw_intel_ctx *ctx = dev_id;
173*4a98a6b2SBard Liao 	struct sdw_intel_link_res *link;
174*4a98a6b2SBard Liao 
175*4a98a6b2SBard Liao 	list_for_each_entry(link, &ctx->link_list, list)
176*4a98a6b2SBard Liao 		sdw_cdns_irq(irq, link->cdns);
177*4a98a6b2SBard Liao 
178*4a98a6b2SBard Liao 	sdw_intel_enable_irq(ctx->mmio_base, true);
179*4a98a6b2SBard Liao 	return IRQ_HANDLED;
180*4a98a6b2SBard Liao }
181*4a98a6b2SBard Liao EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
182*4a98a6b2SBard 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;
1916d2c6669SPierre-Louis Bossart 	u32 link_mask;
1926d2c6669SPierre-Louis Bossart 	int count;
1936d2c6669SPierre-Louis Bossart 	int i;
1946d2c6669SPierre-Louis Bossart 
1956d2c6669SPierre-Louis Bossart 	if (!res)
1966d2c6669SPierre-Louis Bossart 		return NULL;
1976d2c6669SPierre-Louis Bossart 
1986d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(res->handle, &adev))
1996d2c6669SPierre-Louis Bossart 		return NULL;
2006d2c6669SPierre-Louis Bossart 
2016d2c6669SPierre-Louis Bossart 	if (!res->count)
2026d2c6669SPierre-Louis Bossart 		return NULL;
2036d2c6669SPierre-Louis Bossart 
2046d2c6669SPierre-Louis Bossart 	count = res->count;
205d62a7d41SVinod Koul 	dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
206d62a7d41SVinod Koul 
207dd906cc6SPierre-Louis Bossart 	ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL);
208d62a7d41SVinod Koul 	if (!ctx)
209d62a7d41SVinod Koul 		return NULL;
210d62a7d41SVinod Koul 
211d62a7d41SVinod Koul 	ctx->count = count;
212dd906cc6SPierre-Louis Bossart 	ctx->links = devm_kcalloc(&adev->dev, ctx->count,
213dd906cc6SPierre-Louis Bossart 				  sizeof(*ctx->links), GFP_KERNEL);
214d62a7d41SVinod Koul 	if (!ctx->links)
215dd906cc6SPierre-Louis Bossart 		return NULL;
216d62a7d41SVinod Koul 
2176d2c6669SPierre-Louis Bossart 	ctx->count = count;
2186d2c6669SPierre-Louis Bossart 	ctx->mmio_base = res->mmio_base;
2196d2c6669SPierre-Louis Bossart 	ctx->link_mask = res->link_mask;
2206d2c6669SPierre-Louis Bossart 	ctx->handle = res->handle;
2214a17c441SPierre-Louis Bossart 	mutex_init(&ctx->shim_lock);
2226d2c6669SPierre-Louis Bossart 
223d62a7d41SVinod Koul 	link = ctx->links;
2246d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
225d62a7d41SVinod Koul 
226*4a98a6b2SBard Liao 	INIT_LIST_HEAD(&ctx->link_list);
227*4a98a6b2SBard Liao 
228d62a7d41SVinod Koul 	/* Create SDW Master devices */
2296d2c6669SPierre-Louis Bossart 	for (i = 0; i < count; i++, link++) {
2309cd1c5a7SPierre-Louis Bossart 		if (!(link_mask & BIT(i))) {
23150302fc7SPierre-Louis Bossart 			dev_dbg(&adev->dev,
23250302fc7SPierre-Louis Bossart 				"Link %d masked, will not be enabled\n", i);
23350302fc7SPierre-Louis Bossart 			continue;
23450302fc7SPierre-Louis Bossart 		}
23550302fc7SPierre-Louis Bossart 
2366d2c6669SPierre-Louis Bossart 		link->mmio_base = res->mmio_base;
237f98f690fSPierre-Louis Bossart 		link->registers = res->mmio_base + SDW_LINK_BASE
238d62a7d41SVinod Koul 			+ (SDW_LINK_SIZE * i);
239f98f690fSPierre-Louis Bossart 		link->shim = res->mmio_base + SDW_SHIM_BASE;
240f98f690fSPierre-Louis Bossart 		link->alh = res->mmio_base + SDW_ALH_BASE;
241d62a7d41SVinod Koul 
242f98f690fSPierre-Louis Bossart 		link->ops = res->ops;
2434b206d34SRander Wang 		link->dev = res->dev;
244c46302ecSVinod Koul 
2454a17c441SPierre-Louis Bossart 		link->shim_lock = &ctx->shim_lock;
2464a17c441SPierre-Louis Bossart 		link->shim_mask = &ctx->shim_mask;
2474a17c441SPierre-Louis Bossart 
248d62a7d41SVinod Koul 		memset(&pdevinfo, 0, sizeof(pdevinfo));
249d62a7d41SVinod Koul 
250d62a7d41SVinod Koul 		pdevinfo.parent = res->parent;
2516d2c6669SPierre-Louis Bossart 		pdevinfo.name = "intel-sdw";
252d62a7d41SVinod Koul 		pdevinfo.id = i;
253d62a7d41SVinod Koul 		pdevinfo.fwnode = acpi_fwnode_handle(adev);
2544ab34412SPierre-Louis Bossart 		pdevinfo.data = link;
2554ab34412SPierre-Louis Bossart 		pdevinfo.size_data = sizeof(*link);
256d62a7d41SVinod Koul 
257d62a7d41SVinod Koul 		pdev = platform_device_register_full(&pdevinfo);
258d62a7d41SVinod Koul 		if (IS_ERR(pdev)) {
259d62a7d41SVinod Koul 			dev_err(&adev->dev,
260d62a7d41SVinod Koul 				"platform device creation failed: %ld\n",
261d62a7d41SVinod Koul 				PTR_ERR(pdev));
2626d2c6669SPierre-Louis Bossart 			goto err;
263d62a7d41SVinod Koul 		}
264d62a7d41SVinod Koul 		link->pdev = pdev;
265*4a98a6b2SBard Liao 		link->cdns = platform_get_drvdata(pdev);
266*4a98a6b2SBard Liao 
267*4a98a6b2SBard Liao 		list_add_tail(&link->list, &ctx->link_list);
268d62a7d41SVinod Koul 	}
269d62a7d41SVinod Koul 
270d62a7d41SVinod Koul 	return ctx;
271d62a7d41SVinod Koul 
2726d2c6669SPierre-Louis Bossart err:
273dd906cc6SPierre-Louis Bossart 	ctx->count = i;
2746d2c6669SPierre-Louis Bossart 	sdw_intel_cleanup(ctx);
275d62a7d41SVinod Koul 	return NULL;
276d62a7d41SVinod Koul }
277d62a7d41SVinod Koul 
2786d2c6669SPierre-Louis Bossart static int
2796d2c6669SPierre-Louis Bossart sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
2806d2c6669SPierre-Louis Bossart {
2816d2c6669SPierre-Louis Bossart 	struct acpi_device *adev;
2826d2c6669SPierre-Louis Bossart 	struct sdw_intel_link_res *link;
2836d2c6669SPierre-Louis Bossart 	u32 caps;
2846d2c6669SPierre-Louis Bossart 	u32 link_mask;
2856d2c6669SPierre-Louis Bossart 	int i;
2866d2c6669SPierre-Louis Bossart 
2876d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(ctx->handle, &adev))
2886d2c6669SPierre-Louis Bossart 		return -EINVAL;
2896d2c6669SPierre-Louis Bossart 
2906d2c6669SPierre-Louis Bossart 	/* Check SNDWLCAP.LCOUNT */
2916d2c6669SPierre-Louis Bossart 	caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
2926d2c6669SPierre-Louis Bossart 	caps &= GENMASK(2, 0);
2936d2c6669SPierre-Louis Bossart 
2946d2c6669SPierre-Louis Bossart 	/* Check HW supported vs property value */
2956d2c6669SPierre-Louis Bossart 	if (caps < ctx->count) {
2966d2c6669SPierre-Louis Bossart 		dev_err(&adev->dev,
2976d2c6669SPierre-Louis Bossart 			"BIOS master count is larger than hardware capabilities\n");
2986d2c6669SPierre-Louis Bossart 		return -EINVAL;
2996d2c6669SPierre-Louis Bossart 	}
3006d2c6669SPierre-Louis Bossart 
3016d2c6669SPierre-Louis Bossart 	if (!ctx->links)
3026d2c6669SPierre-Louis Bossart 		return -EINVAL;
3036d2c6669SPierre-Louis Bossart 
3046d2c6669SPierre-Louis Bossart 	link = ctx->links;
3056d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
3066d2c6669SPierre-Louis Bossart 
3076d2c6669SPierre-Louis Bossart 	/* Startup SDW Master devices */
3086d2c6669SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++, link++) {
3096d2c6669SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
3106d2c6669SPierre-Louis Bossart 			continue;
3116d2c6669SPierre-Louis Bossart 
3126d2c6669SPierre-Louis Bossart 		intel_master_startup(link->pdev);
3136d2c6669SPierre-Louis Bossart 	}
3146d2c6669SPierre-Louis Bossart 
3156d2c6669SPierre-Louis Bossart 	return 0;
3166d2c6669SPierre-Louis Bossart }
3176d2c6669SPierre-Louis Bossart 
318d62a7d41SVinod Koul static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
319d62a7d41SVinod Koul 				     void *cdata, void **return_value)
320d62a7d41SVinod Koul {
3216d2c6669SPierre-Louis Bossart 	struct sdw_intel_acpi_info *info = cdata;
322d62a7d41SVinod Koul 	struct acpi_device *adev;
3236f11586fSPierre-Louis Bossart 	acpi_status status;
3246f11586fSPierre-Louis Bossart 	u64 adr;
3256f11586fSPierre-Louis Bossart 
3266f11586fSPierre-Louis Bossart 	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
3276f11586fSPierre-Louis Bossart 	if (ACPI_FAILURE(status))
3286f11586fSPierre-Louis Bossart 		return AE_OK; /* keep going */
329d62a7d41SVinod Koul 
330d62a7d41SVinod Koul 	if (acpi_bus_get_device(handle, &adev)) {
331e1c815f4SVinod Koul 		pr_err("%s: Couldn't find ACPI handle\n", __func__);
332d62a7d41SVinod Koul 		return AE_NOT_FOUND;
333d62a7d41SVinod Koul 	}
334d62a7d41SVinod Koul 
3356d2c6669SPierre-Louis Bossart 	info->handle = handle;
3366f11586fSPierre-Louis Bossart 
3376f11586fSPierre-Louis Bossart 	/*
3386f11586fSPierre-Louis Bossart 	 * On some Intel platforms, multiple children of the HDAS
3396f11586fSPierre-Louis Bossart 	 * device can be found, but only one of them is the SoundWire
3406f11586fSPierre-Louis Bossart 	 * controller. The SNDW device is always exposed with
3416f11586fSPierre-Louis Bossart 	 * Name(_ADR, 0x40000000), with bits 31..28 representing the
3426f11586fSPierre-Louis Bossart 	 * SoundWire link so filter accordingly
3436f11586fSPierre-Louis Bossart 	 */
3446f11586fSPierre-Louis Bossart 	if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
3456f11586fSPierre-Louis Bossart 		return AE_OK; /* keep going */
3466f11586fSPierre-Louis Bossart 
3476f11586fSPierre-Louis Bossart 	/* device found, stop namespace walk */
3486f11586fSPierre-Louis Bossart 	return AE_CTRL_TERMINATE;
349d62a7d41SVinod Koul }
350d62a7d41SVinod Koul 
351d62a7d41SVinod Koul /**
3526d2c6669SPierre-Louis Bossart  * sdw_intel_acpi_scan() - SoundWire Intel init routine
353d62a7d41SVinod Koul  * @parent_handle: ACPI parent handle
3546d2c6669SPierre-Louis Bossart  * @info: description of what firmware/DSDT tables expose
355d62a7d41SVinod Koul  *
3566d2c6669SPierre-Louis Bossart  * This scans the namespace and queries firmware to figure out which
3576d2c6669SPierre-Louis Bossart  * links to enable. A follow-up use of sdw_intel_probe() and
3586d2c6669SPierre-Louis Bossart  * sdw_intel_startup() is required for creation of devices and bus
3596d2c6669SPierre-Louis Bossart  * startup
360d62a7d41SVinod Koul  */
3616d2c6669SPierre-Louis Bossart int sdw_intel_acpi_scan(acpi_handle *parent_handle,
3626d2c6669SPierre-Louis Bossart 			struct sdw_intel_acpi_info *info)
363d62a7d41SVinod Koul {
364d62a7d41SVinod Koul 	acpi_status status;
365d62a7d41SVinod Koul 
366d62a7d41SVinod Koul 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
367d62a7d41SVinod Koul 				     parent_handle, 1,
368d62a7d41SVinod Koul 				     sdw_intel_acpi_cb,
3696d2c6669SPierre-Louis Bossart 				     NULL, info, NULL);
370d62a7d41SVinod Koul 	if (ACPI_FAILURE(status))
3716d2c6669SPierre-Louis Bossart 		return -ENODEV;
372d62a7d41SVinod Koul 
3736d2c6669SPierre-Louis Bossart 	return sdw_intel_scan_controller(info);
374d62a7d41SVinod Koul }
3758459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT);
376d62a7d41SVinod Koul 
377d62a7d41SVinod Koul /**
3786d2c6669SPierre-Louis Bossart  * sdw_intel_probe() - SoundWire Intel probe routine
3796d2c6669SPierre-Louis Bossart  * @res: resource data
3806d2c6669SPierre-Louis Bossart  *
3816d2c6669SPierre-Louis Bossart  * This registers a platform device for each Master handled by the controller,
3826d2c6669SPierre-Louis Bossart  * and SoundWire Master and Slave devices will be created by the platform
3836d2c6669SPierre-Louis Bossart  * device probe. All the information necessary is stored in the context, and
3846d2c6669SPierre-Louis Bossart  * the res argument pointer can be freed after this step.
3856d2c6669SPierre-Louis Bossart  * This function will be called after sdw_intel_acpi_scan() by SOF probe.
3866d2c6669SPierre-Louis Bossart  */
3876d2c6669SPierre-Louis Bossart struct sdw_intel_ctx
3886d2c6669SPierre-Louis Bossart *sdw_intel_probe(struct sdw_intel_res *res)
3896d2c6669SPierre-Louis Bossart {
3906d2c6669SPierre-Louis Bossart 	return sdw_intel_probe_controller(res);
3916d2c6669SPierre-Louis Bossart }
3928459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT);
3936d2c6669SPierre-Louis Bossart 
3946d2c6669SPierre-Louis Bossart /**
3956d2c6669SPierre-Louis Bossart  * sdw_intel_startup() - SoundWire Intel startup
3966d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
3976d2c6669SPierre-Louis Bossart  *
3986d2c6669SPierre-Louis Bossart  * Startup Intel SoundWire controller. This function will be called after
3996d2c6669SPierre-Louis Bossart  * Intel Audio DSP is powered up.
4006d2c6669SPierre-Louis Bossart  */
4016d2c6669SPierre-Louis Bossart int sdw_intel_startup(struct sdw_intel_ctx *ctx)
4026d2c6669SPierre-Louis Bossart {
4036d2c6669SPierre-Louis Bossart 	return sdw_intel_startup_controller(ctx);
4046d2c6669SPierre-Louis Bossart }
4058459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
4066d2c6669SPierre-Louis Bossart /**
407d62a7d41SVinod Koul  * sdw_intel_exit() - SoundWire Intel exit
4086d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
409d62a7d41SVinod Koul  *
410d62a7d41SVinod Koul  * Delete the controller instances created and cleanup
411d62a7d41SVinod Koul  */
412f98f690fSPierre-Louis Bossart void sdw_intel_exit(struct sdw_intel_ctx *ctx)
413d62a7d41SVinod Koul {
4146d2c6669SPierre-Louis Bossart 	sdw_intel_cleanup(ctx);
415d62a7d41SVinod Koul }
4168459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
417d62a7d41SVinod Koul 
418d62a7d41SVinod Koul MODULE_LICENSE("Dual BSD/GPL");
419d62a7d41SVinod Koul MODULE_DESCRIPTION("Intel Soundwire Init Library");
420