1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2*4882a593Smuzhiyun // Copyright(c) 2015-17 Intel Corporation.
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun /*
5*4882a593Smuzhiyun * SDW Intel Init Routines
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Initializes and creates SDW devices based on ACPI and Hardware values
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/acpi.h>
11*4882a593Smuzhiyun #include <linux/export.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/pm_runtime.h>
17*4882a593Smuzhiyun #include <linux/soundwire/sdw_intel.h>
18*4882a593Smuzhiyun #include "cadence_master.h"
19*4882a593Smuzhiyun #include "intel.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */
22*4882a593Smuzhiyun #define SDW_MAX_LINKS 4
23*4882a593Smuzhiyun #define SDW_SHIM_LCAP 0x0
24*4882a593Smuzhiyun #define SDW_SHIM_BASE 0x2C000
25*4882a593Smuzhiyun #define SDW_ALH_BASE 0x2C800
26*4882a593Smuzhiyun #define SDW_LINK_BASE 0x30000
27*4882a593Smuzhiyun #define SDW_LINK_SIZE 0x10000
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun static int ctrl_link_mask;
30*4882a593Smuzhiyun module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
31*4882a593Smuzhiyun MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
32*4882a593Smuzhiyun
is_link_enabled(struct fwnode_handle * fw_node,int i)33*4882a593Smuzhiyun static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun struct fwnode_handle *link;
36*4882a593Smuzhiyun char name[32];
37*4882a593Smuzhiyun u32 quirk_mask = 0;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /* Find master handle */
40*4882a593Smuzhiyun snprintf(name, sizeof(name),
41*4882a593Smuzhiyun "mipi-sdw-link-%d-subproperties", i);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun link = fwnode_get_named_child_node(fw_node, name);
44*4882a593Smuzhiyun if (!link)
45*4882a593Smuzhiyun return false;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun fwnode_property_read_u32(link,
48*4882a593Smuzhiyun "intel-quirk-mask",
49*4882a593Smuzhiyun &quirk_mask);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
52*4882a593Smuzhiyun return false;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun return true;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
sdw_intel_cleanup(struct sdw_intel_ctx * ctx)57*4882a593Smuzhiyun static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun struct sdw_intel_link_res *link = ctx->links;
60*4882a593Smuzhiyun u32 link_mask;
61*4882a593Smuzhiyun int i;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (!link)
64*4882a593Smuzhiyun return 0;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun link_mask = ctx->link_mask;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun for (i = 0; i < ctx->count; i++, link++) {
69*4882a593Smuzhiyun if (!(link_mask & BIT(i)))
70*4882a593Smuzhiyun continue;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (link->pdev) {
73*4882a593Smuzhiyun pm_runtime_disable(&link->pdev->dev);
74*4882a593Smuzhiyun platform_device_unregister(link->pdev);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (!link->clock_stop_quirks)
78*4882a593Smuzhiyun pm_runtime_put_noidle(link->dev);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun return 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun static int
sdw_intel_scan_controller(struct sdw_intel_acpi_info * info)85*4882a593Smuzhiyun sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun struct acpi_device *adev;
88*4882a593Smuzhiyun int ret, i;
89*4882a593Smuzhiyun u8 count;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (acpi_bus_get_device(info->handle, &adev))
92*4882a593Smuzhiyun return -EINVAL;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* Found controller, find links supported */
95*4882a593Smuzhiyun count = 0;
96*4882a593Smuzhiyun ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
97*4882a593Smuzhiyun "mipi-sdw-master-count", &count, 1);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /*
100*4882a593Smuzhiyun * In theory we could check the number of links supported in
101*4882a593Smuzhiyun * hardware, but in that step we cannot assume SoundWire IP is
102*4882a593Smuzhiyun * powered.
103*4882a593Smuzhiyun *
104*4882a593Smuzhiyun * In addition, if the BIOS doesn't even provide this
105*4882a593Smuzhiyun * 'master-count' property then all the inits based on link
106*4882a593Smuzhiyun * masks will fail as well.
107*4882a593Smuzhiyun *
108*4882a593Smuzhiyun * We will check the hardware capabilities in the startup() step
109*4882a593Smuzhiyun */
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (ret) {
112*4882a593Smuzhiyun dev_err(&adev->dev,
113*4882a593Smuzhiyun "Failed to read mipi-sdw-master-count: %d\n", ret);
114*4882a593Smuzhiyun return -EINVAL;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* Check count is within bounds */
118*4882a593Smuzhiyun if (count > SDW_MAX_LINKS) {
119*4882a593Smuzhiyun dev_err(&adev->dev, "Link count %d exceeds max %d\n",
120*4882a593Smuzhiyun count, SDW_MAX_LINKS);
121*4882a593Smuzhiyun return -EINVAL;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (!count) {
125*4882a593Smuzhiyun dev_warn(&adev->dev, "No SoundWire links detected\n");
126*4882a593Smuzhiyun return -EINVAL;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun info->count = count;
131*4882a593Smuzhiyun info->link_mask = 0;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun for (i = 0; i < count; i++) {
134*4882a593Smuzhiyun if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) {
135*4882a593Smuzhiyun dev_dbg(&adev->dev,
136*4882a593Smuzhiyun "Link %d masked, will not be enabled\n", i);
137*4882a593Smuzhiyun continue;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (!is_link_enabled(acpi_fwnode_handle(adev), i)) {
141*4882a593Smuzhiyun dev_dbg(&adev->dev,
142*4882a593Smuzhiyun "Link %d not selected in firmware\n", i);
143*4882a593Smuzhiyun continue;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun info->link_mask |= BIT(i);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun #define HDA_DSP_REG_ADSPIC2 (0x10)
153*4882a593Smuzhiyun #define HDA_DSP_REG_ADSPIS2 (0x14)
154*4882a593Smuzhiyun #define HDA_DSP_REG_ADSPIC2_SNDW BIT(5)
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /**
157*4882a593Smuzhiyun * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ
158*4882a593Smuzhiyun * @mmio_base: The mmio base of the control register
159*4882a593Smuzhiyun * @enable: true if enable
160*4882a593Smuzhiyun */
sdw_intel_enable_irq(void __iomem * mmio_base,bool enable)161*4882a593Smuzhiyun void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun u32 val;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun val = readl(mmio_base + HDA_DSP_REG_ADSPIC2);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (enable)
168*4882a593Smuzhiyun val |= HDA_DSP_REG_ADSPIC2_SNDW;
169*4882a593Smuzhiyun else
170*4882a593Smuzhiyun val &= ~HDA_DSP_REG_ADSPIC2_SNDW;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun writel(val, mmio_base + HDA_DSP_REG_ADSPIC2);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);
175*4882a593Smuzhiyun
sdw_intel_thread(int irq,void * dev_id)176*4882a593Smuzhiyun irqreturn_t sdw_intel_thread(int irq, void *dev_id)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun struct sdw_intel_ctx *ctx = dev_id;
179*4882a593Smuzhiyun struct sdw_intel_link_res *link;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun list_for_each_entry(link, &ctx->link_list, list)
182*4882a593Smuzhiyun sdw_cdns_irq(irq, link->cdns);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun sdw_intel_enable_irq(ctx->mmio_base, true);
185*4882a593Smuzhiyun return IRQ_HANDLED;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun static struct sdw_intel_ctx
sdw_intel_probe_controller(struct sdw_intel_res * res)190*4882a593Smuzhiyun *sdw_intel_probe_controller(struct sdw_intel_res *res)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun struct platform_device_info pdevinfo;
193*4882a593Smuzhiyun struct platform_device *pdev;
194*4882a593Smuzhiyun struct sdw_intel_link_res *link;
195*4882a593Smuzhiyun struct sdw_intel_ctx *ctx;
196*4882a593Smuzhiyun struct acpi_device *adev;
197*4882a593Smuzhiyun struct sdw_slave *slave;
198*4882a593Smuzhiyun struct list_head *node;
199*4882a593Smuzhiyun struct sdw_bus *bus;
200*4882a593Smuzhiyun u32 link_mask;
201*4882a593Smuzhiyun int num_slaves = 0;
202*4882a593Smuzhiyun int count;
203*4882a593Smuzhiyun int i;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (!res)
206*4882a593Smuzhiyun return NULL;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (acpi_bus_get_device(res->handle, &adev))
209*4882a593Smuzhiyun return NULL;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (!res->count)
212*4882a593Smuzhiyun return NULL;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun count = res->count;
215*4882a593Smuzhiyun dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL);
218*4882a593Smuzhiyun if (!ctx)
219*4882a593Smuzhiyun return NULL;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun ctx->count = count;
222*4882a593Smuzhiyun ctx->links = devm_kcalloc(&adev->dev, ctx->count,
223*4882a593Smuzhiyun sizeof(*ctx->links), GFP_KERNEL);
224*4882a593Smuzhiyun if (!ctx->links)
225*4882a593Smuzhiyun return NULL;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun ctx->count = count;
228*4882a593Smuzhiyun ctx->mmio_base = res->mmio_base;
229*4882a593Smuzhiyun ctx->link_mask = res->link_mask;
230*4882a593Smuzhiyun ctx->handle = res->handle;
231*4882a593Smuzhiyun mutex_init(&ctx->shim_lock);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun link = ctx->links;
234*4882a593Smuzhiyun link_mask = ctx->link_mask;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun INIT_LIST_HEAD(&ctx->link_list);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun /* Create SDW Master devices */
239*4882a593Smuzhiyun for (i = 0; i < count; i++, link++) {
240*4882a593Smuzhiyun if (!(link_mask & BIT(i))) {
241*4882a593Smuzhiyun dev_dbg(&adev->dev,
242*4882a593Smuzhiyun "Link %d masked, will not be enabled\n", i);
243*4882a593Smuzhiyun continue;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun link->mmio_base = res->mmio_base;
247*4882a593Smuzhiyun link->registers = res->mmio_base + SDW_LINK_BASE
248*4882a593Smuzhiyun + (SDW_LINK_SIZE * i);
249*4882a593Smuzhiyun link->shim = res->mmio_base + SDW_SHIM_BASE;
250*4882a593Smuzhiyun link->alh = res->mmio_base + SDW_ALH_BASE;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun link->ops = res->ops;
253*4882a593Smuzhiyun link->dev = res->dev;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun link->clock_stop_quirks = res->clock_stop_quirks;
256*4882a593Smuzhiyun link->shim_lock = &ctx->shim_lock;
257*4882a593Smuzhiyun link->shim_mask = &ctx->shim_mask;
258*4882a593Smuzhiyun link->link_mask = link_mask;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun memset(&pdevinfo, 0, sizeof(pdevinfo));
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun pdevinfo.parent = res->parent;
263*4882a593Smuzhiyun pdevinfo.name = "intel-sdw";
264*4882a593Smuzhiyun pdevinfo.id = i;
265*4882a593Smuzhiyun pdevinfo.fwnode = acpi_fwnode_handle(adev);
266*4882a593Smuzhiyun pdevinfo.data = link;
267*4882a593Smuzhiyun pdevinfo.size_data = sizeof(*link);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun pdev = platform_device_register_full(&pdevinfo);
270*4882a593Smuzhiyun if (IS_ERR(pdev)) {
271*4882a593Smuzhiyun dev_err(&adev->dev,
272*4882a593Smuzhiyun "platform device creation failed: %ld\n",
273*4882a593Smuzhiyun PTR_ERR(pdev));
274*4882a593Smuzhiyun goto err;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun link->pdev = pdev;
277*4882a593Smuzhiyun link->cdns = platform_get_drvdata(pdev);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun list_add_tail(&link->list, &ctx->link_list);
280*4882a593Smuzhiyun bus = &link->cdns->bus;
281*4882a593Smuzhiyun /* Calculate number of slaves */
282*4882a593Smuzhiyun list_for_each(node, &bus->slaves)
283*4882a593Smuzhiyun num_slaves++;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun ctx->ids = devm_kcalloc(&adev->dev, num_slaves,
287*4882a593Smuzhiyun sizeof(*ctx->ids), GFP_KERNEL);
288*4882a593Smuzhiyun if (!ctx->ids)
289*4882a593Smuzhiyun goto err;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun ctx->num_slaves = num_slaves;
292*4882a593Smuzhiyun i = 0;
293*4882a593Smuzhiyun list_for_each_entry(link, &ctx->link_list, list) {
294*4882a593Smuzhiyun bus = &link->cdns->bus;
295*4882a593Smuzhiyun list_for_each_entry(slave, &bus->slaves, node) {
296*4882a593Smuzhiyun ctx->ids[i].id = slave->id;
297*4882a593Smuzhiyun ctx->ids[i].link_id = bus->link_id;
298*4882a593Smuzhiyun i++;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun return ctx;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun err:
305*4882a593Smuzhiyun ctx->count = i;
306*4882a593Smuzhiyun sdw_intel_cleanup(ctx);
307*4882a593Smuzhiyun return NULL;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun static int
sdw_intel_startup_controller(struct sdw_intel_ctx * ctx)311*4882a593Smuzhiyun sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun struct acpi_device *adev;
314*4882a593Smuzhiyun struct sdw_intel_link_res *link;
315*4882a593Smuzhiyun u32 caps;
316*4882a593Smuzhiyun u32 link_mask;
317*4882a593Smuzhiyun int i;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (acpi_bus_get_device(ctx->handle, &adev))
320*4882a593Smuzhiyun return -EINVAL;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun /* Check SNDWLCAP.LCOUNT */
323*4882a593Smuzhiyun caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
324*4882a593Smuzhiyun caps &= GENMASK(2, 0);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /* Check HW supported vs property value */
327*4882a593Smuzhiyun if (caps < ctx->count) {
328*4882a593Smuzhiyun dev_err(&adev->dev,
329*4882a593Smuzhiyun "BIOS master count is larger than hardware capabilities\n");
330*4882a593Smuzhiyun return -EINVAL;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (!ctx->links)
334*4882a593Smuzhiyun return -EINVAL;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun link = ctx->links;
337*4882a593Smuzhiyun link_mask = ctx->link_mask;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* Startup SDW Master devices */
340*4882a593Smuzhiyun for (i = 0; i < ctx->count; i++, link++) {
341*4882a593Smuzhiyun if (!(link_mask & BIT(i)))
342*4882a593Smuzhiyun continue;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun intel_master_startup(link->pdev);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (!link->clock_stop_quirks) {
347*4882a593Smuzhiyun /*
348*4882a593Smuzhiyun * we need to prevent the parent PCI device
349*4882a593Smuzhiyun * from entering pm_runtime suspend, so that
350*4882a593Smuzhiyun * power rails to the SoundWire IP are not
351*4882a593Smuzhiyun * turned off.
352*4882a593Smuzhiyun */
353*4882a593Smuzhiyun pm_runtime_get_noresume(link->dev);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
sdw_intel_acpi_cb(acpi_handle handle,u32 level,void * cdata,void ** return_value)360*4882a593Smuzhiyun static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
361*4882a593Smuzhiyun void *cdata, void **return_value)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun struct sdw_intel_acpi_info *info = cdata;
364*4882a593Smuzhiyun struct acpi_device *adev;
365*4882a593Smuzhiyun acpi_status status;
366*4882a593Smuzhiyun u64 adr;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
369*4882a593Smuzhiyun if (ACPI_FAILURE(status))
370*4882a593Smuzhiyun return AE_OK; /* keep going */
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (acpi_bus_get_device(handle, &adev)) {
373*4882a593Smuzhiyun pr_err("%s: Couldn't find ACPI handle\n", __func__);
374*4882a593Smuzhiyun return AE_NOT_FOUND;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun info->handle = handle;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /*
380*4882a593Smuzhiyun * On some Intel platforms, multiple children of the HDAS
381*4882a593Smuzhiyun * device can be found, but only one of them is the SoundWire
382*4882a593Smuzhiyun * controller. The SNDW device is always exposed with
383*4882a593Smuzhiyun * Name(_ADR, 0x40000000), with bits 31..28 representing the
384*4882a593Smuzhiyun * SoundWire link so filter accordingly
385*4882a593Smuzhiyun */
386*4882a593Smuzhiyun if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
387*4882a593Smuzhiyun return AE_OK; /* keep going */
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun /* device found, stop namespace walk */
390*4882a593Smuzhiyun return AE_CTRL_TERMINATE;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /**
394*4882a593Smuzhiyun * sdw_intel_acpi_scan() - SoundWire Intel init routine
395*4882a593Smuzhiyun * @parent_handle: ACPI parent handle
396*4882a593Smuzhiyun * @info: description of what firmware/DSDT tables expose
397*4882a593Smuzhiyun *
398*4882a593Smuzhiyun * This scans the namespace and queries firmware to figure out which
399*4882a593Smuzhiyun * links to enable. A follow-up use of sdw_intel_probe() and
400*4882a593Smuzhiyun * sdw_intel_startup() is required for creation of devices and bus
401*4882a593Smuzhiyun * startup
402*4882a593Smuzhiyun */
sdw_intel_acpi_scan(acpi_handle * parent_handle,struct sdw_intel_acpi_info * info)403*4882a593Smuzhiyun int sdw_intel_acpi_scan(acpi_handle *parent_handle,
404*4882a593Smuzhiyun struct sdw_intel_acpi_info *info)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun acpi_status status;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun info->handle = NULL;
409*4882a593Smuzhiyun status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
410*4882a593Smuzhiyun parent_handle, 1,
411*4882a593Smuzhiyun sdw_intel_acpi_cb,
412*4882a593Smuzhiyun NULL, info, NULL);
413*4882a593Smuzhiyun if (ACPI_FAILURE(status) || info->handle == NULL)
414*4882a593Smuzhiyun return -ENODEV;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun return sdw_intel_scan_controller(info);
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT);
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun /**
421*4882a593Smuzhiyun * sdw_intel_probe() - SoundWire Intel probe routine
422*4882a593Smuzhiyun * @res: resource data
423*4882a593Smuzhiyun *
424*4882a593Smuzhiyun * This registers a platform device for each Master handled by the controller,
425*4882a593Smuzhiyun * and SoundWire Master and Slave devices will be created by the platform
426*4882a593Smuzhiyun * device probe. All the information necessary is stored in the context, and
427*4882a593Smuzhiyun * the res argument pointer can be freed after this step.
428*4882a593Smuzhiyun * This function will be called after sdw_intel_acpi_scan() by SOF probe.
429*4882a593Smuzhiyun */
430*4882a593Smuzhiyun struct sdw_intel_ctx
sdw_intel_probe(struct sdw_intel_res * res)431*4882a593Smuzhiyun *sdw_intel_probe(struct sdw_intel_res *res)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun return sdw_intel_probe_controller(res);
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /**
438*4882a593Smuzhiyun * sdw_intel_startup() - SoundWire Intel startup
439*4882a593Smuzhiyun * @ctx: SoundWire context allocated in the probe
440*4882a593Smuzhiyun *
441*4882a593Smuzhiyun * Startup Intel SoundWire controller. This function will be called after
442*4882a593Smuzhiyun * Intel Audio DSP is powered up.
443*4882a593Smuzhiyun */
sdw_intel_startup(struct sdw_intel_ctx * ctx)444*4882a593Smuzhiyun int sdw_intel_startup(struct sdw_intel_ctx *ctx)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun return sdw_intel_startup_controller(ctx);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
449*4882a593Smuzhiyun /**
450*4882a593Smuzhiyun * sdw_intel_exit() - SoundWire Intel exit
451*4882a593Smuzhiyun * @ctx: SoundWire context allocated in the probe
452*4882a593Smuzhiyun *
453*4882a593Smuzhiyun * Delete the controller instances created and cleanup
454*4882a593Smuzhiyun */
sdw_intel_exit(struct sdw_intel_ctx * ctx)455*4882a593Smuzhiyun void sdw_intel_exit(struct sdw_intel_ctx *ctx)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun sdw_intel_cleanup(ctx);
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
460*4882a593Smuzhiyun
sdw_intel_process_wakeen_event(struct sdw_intel_ctx * ctx)461*4882a593Smuzhiyun void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun struct sdw_intel_link_res *link;
464*4882a593Smuzhiyun u32 link_mask;
465*4882a593Smuzhiyun int i;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun if (!ctx->links)
468*4882a593Smuzhiyun return;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun link = ctx->links;
471*4882a593Smuzhiyun link_mask = ctx->link_mask;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun /* Startup SDW Master devices */
474*4882a593Smuzhiyun for (i = 0; i < ctx->count; i++, link++) {
475*4882a593Smuzhiyun if (!(link_mask & BIT(i)))
476*4882a593Smuzhiyun continue;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun intel_master_process_wakeen_event(link->pdev);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun MODULE_LICENSE("Dual BSD/GPL");
484*4882a593Smuzhiyun MODULE_DESCRIPTION("Intel Soundwire Init Library");
485