1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2 // Copyright(c) 2015-17 Intel Corporation.
4 #include <linux/acpi.h>
5 #include <linux/soundwire/sdw.h>
6 #include <linux/soundwire/sdw_type.h>
9 static void sdw_slave_release(struct device
*dev
)
11 struct sdw_slave
*slave
= dev_to_sdw_dev(dev
);
16 static int sdw_slave_add(struct sdw_bus
*bus
,
17 struct sdw_slave_id
*id
, struct fwnode_handle
*fwnode
)
19 struct sdw_slave
*slave
;
22 slave
= kzalloc(sizeof(*slave
), GFP_KERNEL
);
26 /* Initialize data structure */
27 memcpy(&slave
->id
, id
, sizeof(*id
));
28 slave
->dev
.parent
= bus
->dev
;
29 slave
->dev
.fwnode
= fwnode
;
31 /* name shall be sdw:link:mfg:part:class:unique */
32 dev_set_name(&slave
->dev
, "sdw:%x:%x:%x:%x:%x",
33 bus
->link_id
, id
->mfg_id
, id
->part_id
,
34 id
->class_id
, id
->unique_id
);
36 slave
->dev
.release
= sdw_slave_release
;
37 slave
->dev
.bus
= &sdw_bus_type
;
39 slave
->status
= SDW_SLAVE_UNATTACHED
;
42 mutex_lock(&bus
->bus_lock
);
43 list_add_tail(&slave
->node
, &bus
->slaves
);
44 mutex_unlock(&bus
->bus_lock
);
46 ret
= device_register(&slave
->dev
);
48 dev_err(bus
->dev
, "Failed to add slave: ret %d\n", ret
);
51 * On err, don't free but drop ref as this will be freed
52 * when release method is invoked.
54 mutex_lock(&bus
->bus_lock
);
55 list_del(&slave
->node
);
56 mutex_unlock(&bus
->bus_lock
);
57 put_device(&slave
->dev
);
63 #if IS_ENABLED(CONFIG_ACPI)
65 * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
66 * @bus: SDW bus instance
68 * Scans Master ACPI node for SDW child Slave devices and registers it.
70 int sdw_acpi_find_slaves(struct sdw_bus
*bus
)
72 struct acpi_device
*adev
, *parent
;
74 parent
= ACPI_COMPANION(bus
->dev
);
76 dev_err(bus
->dev
, "Can't find parent for acpi bind\n");
80 list_for_each_entry(adev
, &parent
->children
, node
) {
81 unsigned long long addr
;
82 struct sdw_slave_id id
;
86 status
= acpi_evaluate_integer(adev
->handle
,
87 METHOD_NAME__ADR
, NULL
, &addr
);
89 if (ACPI_FAILURE(status
)) {
90 dev_err(bus
->dev
, "_ADR resolution failed: %x\n",
95 /* Extract link id from ADR, Bit 51 to 48 (included) */
96 link_id
= (addr
>> 48) & GENMASK(3, 0);
98 /* Check for link_id match */
99 if (link_id
!= bus
->link_id
)
102 sdw_extract_slave_id(bus
, addr
, &id
);
105 * don't error check for sdw_slave_add as we want to continue
108 sdw_slave_add(bus
, &id
, acpi_fwnode_handle(adev
));