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