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/of.h> |
6 | #include <linux/soundwire/sdw.h> |
7 | #include <linux/soundwire/sdw_type.h> |
8 | #include <sound/sdca.h> |
9 | #include "bus.h" |
10 | #include "sysfs_local.h" |
11 | |
12 | static void sdw_slave_release(struct device *dev) |
13 | { |
14 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
15 | |
16 | of_node_put(node: slave->dev.of_node); |
17 | mutex_destroy(lock: &slave->sdw_dev_lock); |
18 | kfree(objp: slave); |
19 | } |
20 | |
21 | const struct device_type sdw_slave_type = { |
22 | .name = "sdw_slave" , |
23 | .release = sdw_slave_release, |
24 | .uevent = sdw_slave_uevent, |
25 | }; |
26 | |
27 | int sdw_slave_add(struct sdw_bus *bus, |
28 | struct sdw_slave_id *id, struct fwnode_handle *fwnode) |
29 | { |
30 | struct sdw_slave *slave; |
31 | int ret; |
32 | int i; |
33 | |
34 | slave = kzalloc(sizeof(*slave), GFP_KERNEL); |
35 | if (!slave) |
36 | return -ENOMEM; |
37 | |
38 | /* Initialize data structure */ |
39 | memcpy(&slave->id, id, sizeof(*id)); |
40 | slave->dev.parent = bus->dev; |
41 | slave->dev.fwnode = fwnode; |
42 | |
43 | if (id->unique_id == SDW_IGNORED_UNIQUE_ID) { |
44 | /* name shall be sdw:ctrl:link:mfg:part:class */ |
45 | dev_set_name(dev: &slave->dev, name: "sdw:%01x:%01x:%04x:%04x:%02x" , |
46 | bus->controller_id, bus->link_id, id->mfg_id, id->part_id, |
47 | id->class_id); |
48 | } else { |
49 | /* name shall be sdw:ctrl:link:mfg:part:class:unique */ |
50 | dev_set_name(dev: &slave->dev, name: "sdw:%01x:%01x:%04x:%04x:%02x:%01x" , |
51 | bus->controller_id, bus->link_id, id->mfg_id, id->part_id, |
52 | id->class_id, id->unique_id); |
53 | } |
54 | |
55 | slave->dev.bus = &sdw_bus_type; |
56 | slave->dev.of_node = of_node_get(to_of_node(fwnode)); |
57 | slave->dev.type = &sdw_slave_type; |
58 | slave->dev.groups = sdw_slave_status_attr_groups; |
59 | slave->bus = bus; |
60 | slave->status = SDW_SLAVE_UNATTACHED; |
61 | init_completion(x: &slave->enumeration_complete); |
62 | init_completion(x: &slave->initialization_complete); |
63 | slave->dev_num = 0; |
64 | slave->probed = false; |
65 | slave->first_interrupt_done = false; |
66 | mutex_init(&slave->sdw_dev_lock); |
67 | |
68 | for (i = 0; i < SDW_MAX_PORTS; i++) |
69 | init_completion(x: &slave->port_ready[i]); |
70 | |
71 | mutex_lock(&bus->bus_lock); |
72 | list_add_tail(new: &slave->node, head: &bus->slaves); |
73 | mutex_unlock(lock: &bus->bus_lock); |
74 | |
75 | /* |
76 | * The Soundwire driver probe may optionally register SDCA |
77 | * sub-devices, one per Function. This means the information |
78 | * on the SDCA revision and the number/type of Functions need |
79 | * to be extracted from platform firmware before the SoundWire |
80 | * driver probe, and as a consequence before the SoundWire |
81 | * device_register() below. |
82 | */ |
83 | sdca_lookup_interface_revision(slave); |
84 | sdca_lookup_functions(slave); |
85 | |
86 | ret = device_register(dev: &slave->dev); |
87 | if (ret) { |
88 | dev_err(bus->dev, "Failed to add slave: ret %d\n" , ret); |
89 | |
90 | /* |
91 | * On err, don't free but drop ref as this will be freed |
92 | * when release method is invoked. |
93 | */ |
94 | mutex_lock(&bus->bus_lock); |
95 | list_del(entry: &slave->node); |
96 | mutex_unlock(lock: &bus->bus_lock); |
97 | put_device(dev: &slave->dev); |
98 | |
99 | return ret; |
100 | } |
101 | sdw_slave_debugfs_init(slave); |
102 | |
103 | return ret; |
104 | } |
105 | EXPORT_SYMBOL(sdw_slave_add); |
106 | |
107 | #if IS_ENABLED(CONFIG_ACPI) |
108 | |
109 | static bool find_slave(struct sdw_bus *bus, |
110 | struct acpi_device *adev, |
111 | struct sdw_slave_id *id) |
112 | { |
113 | unsigned int link_id; |
114 | u64 addr; |
115 | int ret; |
116 | |
117 | ret = acpi_get_local_u64_address(handle: adev->handle, addr: &addr); |
118 | if (ret < 0) |
119 | return false; |
120 | |
121 | if (bus->ops->override_adr) |
122 | addr = bus->ops->override_adr(bus, addr); |
123 | |
124 | if (!addr) |
125 | return false; |
126 | |
127 | /* Extract link id from ADR, Bit 51 to 48 (included) */ |
128 | link_id = SDW_DISCO_LINK_ID(addr); |
129 | |
130 | /* Check for link_id match */ |
131 | if (link_id != bus->link_id) |
132 | return false; |
133 | |
134 | sdw_extract_slave_id(bus, addr, id); |
135 | |
136 | return true; |
137 | } |
138 | |
139 | struct sdw_acpi_child_walk_data { |
140 | struct sdw_bus *bus; |
141 | struct acpi_device *adev; |
142 | struct sdw_slave_id id; |
143 | bool ignore_unique_id; |
144 | }; |
145 | |
146 | static int sdw_acpi_check_duplicate(struct acpi_device *adev, void *data) |
147 | { |
148 | struct sdw_acpi_child_walk_data *cwd = data; |
149 | struct sdw_bus *bus = cwd->bus; |
150 | struct sdw_slave_id id; |
151 | |
152 | if (adev == cwd->adev) |
153 | return 0; |
154 | |
155 | if (!find_slave(bus, adev, id: &id)) |
156 | return 0; |
157 | |
158 | if (cwd->id.sdw_version != id.sdw_version || cwd->id.mfg_id != id.mfg_id || |
159 | cwd->id.part_id != id.part_id || cwd->id.class_id != id.class_id) |
160 | return 0; |
161 | |
162 | if (cwd->id.unique_id != id.unique_id) { |
163 | dev_dbg(bus->dev, |
164 | "Valid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n" , |
165 | cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, |
166 | cwd->id.part_id); |
167 | cwd->ignore_unique_id = false; |
168 | return 0; |
169 | } |
170 | |
171 | dev_err(bus->dev, |
172 | "Invalid unique IDs 0x%x 0x%x for Slave mfg_id 0x%04x, part_id 0x%04x\n" , |
173 | cwd->id.unique_id, id.unique_id, cwd->id.mfg_id, cwd->id.part_id); |
174 | return -ENODEV; |
175 | } |
176 | |
177 | static int sdw_acpi_find_one(struct acpi_device *adev, void *data) |
178 | { |
179 | struct sdw_bus *bus = data; |
180 | struct sdw_acpi_child_walk_data cwd = { |
181 | .bus = bus, |
182 | .adev = adev, |
183 | .ignore_unique_id = true, |
184 | }; |
185 | int ret; |
186 | |
187 | if (!find_slave(bus, adev, id: &cwd.id)) |
188 | return 0; |
189 | |
190 | /* Brute-force O(N^2) search for duplicates. */ |
191 | ret = acpi_dev_for_each_child(ACPI_COMPANION(bus->dev), |
192 | fn: sdw_acpi_check_duplicate, data: &cwd); |
193 | if (ret) |
194 | return ret; |
195 | |
196 | if (cwd.ignore_unique_id) |
197 | cwd.id.unique_id = SDW_IGNORED_UNIQUE_ID; |
198 | |
199 | /* Ignore errors and continue. */ |
200 | sdw_slave_add(bus, &cwd.id, acpi_fwnode_handle(adev)); |
201 | return 0; |
202 | } |
203 | |
204 | /* |
205 | * sdw_acpi_find_slaves() - Find Slave devices in Master ACPI node |
206 | * @bus: SDW bus instance |
207 | * |
208 | * Scans Master ACPI node for SDW child Slave devices and registers it. |
209 | */ |
210 | int sdw_acpi_find_slaves(struct sdw_bus *bus) |
211 | { |
212 | struct acpi_device *parent; |
213 | |
214 | parent = ACPI_COMPANION(bus->dev); |
215 | if (!parent) { |
216 | dev_err(bus->dev, "Can't find parent for acpi bind\n" ); |
217 | return -ENODEV; |
218 | } |
219 | |
220 | return acpi_dev_for_each_child(adev: parent, fn: sdw_acpi_find_one, data: bus); |
221 | } |
222 | |
223 | #endif |
224 | |
225 | /* |
226 | * sdw_of_find_slaves() - Find Slave devices in master device tree node |
227 | * @bus: SDW bus instance |
228 | * |
229 | * Scans Master DT node for SDW child Slave devices and registers it. |
230 | */ |
231 | int sdw_of_find_slaves(struct sdw_bus *bus) |
232 | { |
233 | struct device *dev = bus->dev; |
234 | struct device_node *node; |
235 | |
236 | for_each_child_of_node(bus->dev->of_node, node) { |
237 | int link_id, ret, len; |
238 | unsigned int sdw_version; |
239 | const char *compat = NULL; |
240 | struct sdw_slave_id id; |
241 | const __be32 *addr; |
242 | |
243 | compat = of_get_property(node, name: "compatible" , NULL); |
244 | if (!compat) |
245 | continue; |
246 | |
247 | ret = sscanf(compat, "sdw%01x%04hx%04hx%02hhx" , &sdw_version, |
248 | &id.mfg_id, &id.part_id, &id.class_id); |
249 | |
250 | if (ret != 4) { |
251 | dev_err(dev, "Invalid compatible string found %s\n" , |
252 | compat); |
253 | continue; |
254 | } |
255 | |
256 | addr = of_get_property(node, name: "reg" , lenp: &len); |
257 | if (!addr || (len < 2 * sizeof(u32))) { |
258 | dev_err(dev, "Invalid Link and Instance ID\n" ); |
259 | continue; |
260 | } |
261 | |
262 | link_id = be32_to_cpup(p: addr++); |
263 | id.unique_id = be32_to_cpup(p: addr); |
264 | id.sdw_version = sdw_version; |
265 | |
266 | /* Check for link_id match */ |
267 | if (link_id != bus->link_id) |
268 | continue; |
269 | |
270 | sdw_slave_add(bus, &id, of_fwnode_handle(node)); |
271 | } |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | MODULE_IMPORT_NS("SND_SOC_SDCA" ); |
277 | |