xref: /openbmc/linux/drivers/soundwire/slave.c (revision 22d55f02)
1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2 // Copyright(c) 2015-17 Intel Corporation.
3 
4 #include <linux/acpi.h>
5 #include <linux/soundwire/sdw.h>
6 #include <linux/soundwire/sdw_type.h>
7 #include "bus.h"
8 
9 static void sdw_slave_release(struct device *dev)
10 {
11 	struct sdw_slave *slave = dev_to_sdw_dev(dev);
12 
13 	kfree(slave);
14 }
15 
16 static int sdw_slave_add(struct sdw_bus *bus,
17 			 struct sdw_slave_id *id, struct fwnode_handle *fwnode)
18 {
19 	struct sdw_slave *slave;
20 	int ret;
21 
22 	slave = kzalloc(sizeof(*slave), GFP_KERNEL);
23 	if (!slave)
24 		return -ENOMEM;
25 
26 	/* Initialize data structure */
27 	memcpy(&slave->id, id, sizeof(*id));
28 	slave->dev.parent = bus->dev;
29 	slave->dev.fwnode = fwnode;
30 
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);
35 
36 	slave->dev.release = sdw_slave_release;
37 	slave->dev.bus = &sdw_bus_type;
38 	slave->bus = bus;
39 	slave->status = SDW_SLAVE_UNATTACHED;
40 	slave->dev_num = 0;
41 
42 	mutex_lock(&bus->bus_lock);
43 	list_add_tail(&slave->node, &bus->slaves);
44 	mutex_unlock(&bus->bus_lock);
45 
46 	ret = device_register(&slave->dev);
47 	if (ret) {
48 		dev_err(bus->dev, "Failed to add slave: ret %d\n", ret);
49 
50 		/*
51 		 * On err, don't free but drop ref as this will be freed
52 		 * when release method is invoked.
53 		 */
54 		mutex_lock(&bus->bus_lock);
55 		list_del(&slave->node);
56 		mutex_unlock(&bus->bus_lock);
57 		put_device(&slave->dev);
58 	}
59 
60 	return ret;
61 }
62 
63 #if IS_ENABLED(CONFIG_ACPI)
64 /*
65  * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node
66  * @bus: SDW bus instance
67  *
68  * Scans Master ACPI node for SDW child Slave devices and registers it.
69  */
70 int sdw_acpi_find_slaves(struct sdw_bus *bus)
71 {
72 	struct acpi_device *adev, *parent;
73 
74 	parent = ACPI_COMPANION(bus->dev);
75 	if (!parent) {
76 		dev_err(bus->dev, "Can't find parent for acpi bind\n");
77 		return -ENODEV;
78 	}
79 
80 	list_for_each_entry(adev, &parent->children, node) {
81 		unsigned long long addr;
82 		struct sdw_slave_id id;
83 		unsigned int link_id;
84 		acpi_status status;
85 
86 		status = acpi_evaluate_integer(adev->handle,
87 					       METHOD_NAME__ADR, NULL, &addr);
88 
89 		if (ACPI_FAILURE(status)) {
90 			dev_err(bus->dev, "_ADR resolution failed: %x\n",
91 				status);
92 			return status;
93 		}
94 
95 		/* Extract link id from ADR, Bit 51 to 48 (included) */
96 		link_id = (addr >> 48) & GENMASK(3, 0);
97 
98 		/* Check for link_id match */
99 		if (link_id != bus->link_id)
100 			continue;
101 
102 		sdw_extract_slave_id(bus, addr, &id);
103 
104 		/*
105 		 * don't error check for sdw_slave_add as we want to continue
106 		 * adding Slaves
107 		 */
108 		sdw_slave_add(bus, &id, acpi_fwnode_handle(adev));
109 	}
110 
111 	return 0;
112 }
113 
114 #endif
115