Commit | Line | Data |
---|---|---|
eb50fd3a | 1 | // SPDX-License-Identifier: GPL-2.0 |
e1e9dbdd | 2 | /* |
4ab9b3c2 | 3 | * Greybus interface code |
e1e9dbdd AE |
4 | * |
5 | * Copyright 2014 Google Inc. | |
a46e9671 | 6 | * Copyright 2014 Linaro Ltd. |
e1e9dbdd AE |
7 | */ |
8 | ||
30a3bf7b | 9 | #include <linux/delay.h> |
ec0ad868 | 10 | #include <linux/greybus.h> |
30a3bf7b | 11 | |
cb4c8441 | 12 | #include "greybus_trace.h" |
c2d80906 | 13 | |
7dea1d5f | 14 | #define GB_INTERFACE_MODE_SWITCH_TIMEOUT 2000 |
55742d2a | 15 | |
e9f2f688 JH |
16 | #define GB_INTERFACE_DEVICE_ID_BAD 0xff |
17 | ||
30a3bf7b DL |
18 | #define GB_INTERFACE_AUTOSUSPEND_MS 3000 |
19 | ||
20 | /* Time required for interface to enter standby before disabling REFCLK */ | |
21 | #define GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS 20 | |
22 | ||
50ad4163 JH |
23 | /* Don't-care selector index */ |
24 | #define DME_SELECTOR_INDEX_NULL 0 | |
25 | ||
153ff7e7 | 26 | /* DME attributes */ |
50ad4163 JH |
27 | /* FIXME: remove ES2 support and DME_T_TST_SRC_INCREMENT */ |
28 | #define DME_T_TST_SRC_INCREMENT 0x4083 | |
29 | ||
153ff7e7 JH |
30 | #define DME_DDBL1_MANUFACTURERID 0x5003 |
31 | #define DME_DDBL1_PRODUCTID 0x5004 | |
32 | ||
23931ffb JH |
33 | #define DME_TOSHIBA_GMP_VID 0x6000 |
34 | #define DME_TOSHIBA_GMP_PID 0x6001 | |
35 | #define DME_TOSHIBA_GMP_SN0 0x6002 | |
36 | #define DME_TOSHIBA_GMP_SN1 0x6003 | |
37 | #define DME_TOSHIBA_GMP_INIT_STATUS 0x6101 | |
153ff7e7 JH |
38 | |
39 | /* DDBL1 Manufacturer and Product ids */ | |
40 | #define TOSHIBA_DMID 0x0126 | |
41 | #define TOSHIBA_ES2_BRIDGE_DPID 0x1000 | |
42 | #define TOSHIBA_ES3_APBRIDGE_DPID 0x1001 | |
e54b106d | 43 | #define TOSHIBA_ES3_GBPHY_DPID 0x1002 |
153ff7e7 | 44 | |
30a3bf7b DL |
45 | static int gb_interface_hibernate_link(struct gb_interface *intf); |
46 | static int gb_interface_refclk_set(struct gb_interface *intf, bool enable); | |
153ff7e7 JH |
47 | |
48 | static int gb_interface_dme_attr_get(struct gb_interface *intf, | |
0c85ae28 | 49 | u16 attr, u32 *val) |
153ff7e7 JH |
50 | { |
51 | return gb_svc_dme_peer_get(intf->hd->svc, intf->interface_id, | |
50ad4163 | 52 | attr, DME_SELECTOR_INDEX_NULL, val); |
153ff7e7 JH |
53 | } |
54 | ||
55 | static int gb_interface_read_ara_dme(struct gb_interface *intf) | |
56 | { | |
a7be8461 | 57 | u32 sn0, sn1; |
153ff7e7 JH |
58 | int ret; |
59 | ||
60 | /* | |
61 | * Unless this is a Toshiba bridge, bail out until we have defined | |
23931ffb | 62 | * standard GMP attributes. |
153ff7e7 JH |
63 | */ |
64 | if (intf->ddbl1_manufacturer_id != TOSHIBA_DMID) { | |
65 | dev_err(&intf->dev, "unknown manufacturer %08x\n", | |
0c85ae28 | 66 | intf->ddbl1_manufacturer_id); |
153ff7e7 JH |
67 | return -ENODEV; |
68 | } | |
69 | ||
23931ffb | 70 | ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_VID, |
153ff7e7 JH |
71 | &intf->vendor_id); |
72 | if (ret) | |
73 | return ret; | |
74 | ||
23931ffb | 75 | ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_PID, |
153ff7e7 JH |
76 | &intf->product_id); |
77 | if (ret) | |
78 | return ret; | |
79 | ||
23931ffb | 80 | ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN0, &sn0); |
a7be8461 JH |
81 | if (ret) |
82 | return ret; | |
83 | ||
23931ffb | 84 | ret = gb_interface_dme_attr_get(intf, DME_TOSHIBA_GMP_SN1, &sn1); |
a7be8461 JH |
85 | if (ret) |
86 | return ret; | |
87 | ||
88 | intf->serial_number = (u64)sn1 << 32 | sn0; | |
153ff7e7 JH |
89 | |
90 | return 0; | |
91 | } | |
92 | ||
93 | static int gb_interface_read_dme(struct gb_interface *intf) | |
94 | { | |
95 | int ret; | |
96 | ||
27b9e257 JH |
97 | /* DME attributes have already been read */ |
98 | if (intf->dme_read) | |
99 | return 0; | |
100 | ||
153ff7e7 JH |
101 | ret = gb_interface_dme_attr_get(intf, DME_DDBL1_MANUFACTURERID, |
102 | &intf->ddbl1_manufacturer_id); | |
103 | if (ret) | |
104 | return ret; | |
105 | ||
106 | ret = gb_interface_dme_attr_get(intf, DME_DDBL1_PRODUCTID, | |
107 | &intf->ddbl1_product_id); | |
108 | if (ret) | |
109 | return ret; | |
110 | ||
7d7acc06 | 111 | if (intf->ddbl1_manufacturer_id == TOSHIBA_DMID && |
0c85ae28 | 112 | intf->ddbl1_product_id == TOSHIBA_ES2_BRIDGE_DPID) { |
23931ffb | 113 | intf->quirks |= GB_INTERFACE_QUIRK_NO_GMP_IDS; |
7d7acc06 JH |
114 | intf->quirks |= GB_INTERFACE_QUIRK_NO_INIT_STATUS; |
115 | } | |
116 | ||
27b9e257 JH |
117 | ret = gb_interface_read_ara_dme(intf); |
118 | if (ret) | |
119 | return ret; | |
120 | ||
121 | intf->dme_read = true; | |
122 | ||
123 | return 0; | |
153ff7e7 | 124 | } |
e9f2f688 | 125 | |
4d5f6218 JH |
126 | static int gb_interface_route_create(struct gb_interface *intf) |
127 | { | |
128 | struct gb_svc *svc = intf->hd->svc; | |
129 | u8 intf_id = intf->interface_id; | |
130 | u8 device_id; | |
131 | int ret; | |
132 | ||
e9f2f688 | 133 | /* Allocate an interface device id. */ |
4d5f6218 | 134 | ret = ida_simple_get(&svc->device_id_map, |
e9f2f688 JH |
135 | GB_SVC_DEVICE_ID_MIN, GB_SVC_DEVICE_ID_MAX + 1, |
136 | GFP_KERNEL); | |
4d5f6218 JH |
137 | if (ret < 0) { |
138 | dev_err(&intf->dev, "failed to allocate device id: %d\n", ret); | |
139 | return ret; | |
140 | } | |
141 | device_id = ret; | |
142 | ||
143 | ret = gb_svc_intf_device_id(svc, intf_id, device_id); | |
144 | if (ret) { | |
145 | dev_err(&intf->dev, "failed to set device id %u: %d\n", | |
0c85ae28 | 146 | device_id, ret); |
4d5f6218 JH |
147 | goto err_ida_remove; |
148 | } | |
149 | ||
e9f2f688 JH |
150 | /* FIXME: Hard-coded AP device id. */ |
151 | ret = gb_svc_route_create(svc, svc->ap_intf_id, GB_SVC_DEVICE_ID_AP, | |
4d5f6218 JH |
152 | intf_id, device_id); |
153 | if (ret) { | |
154 | dev_err(&intf->dev, "failed to create route: %d\n", ret); | |
155 | goto err_svc_id_free; | |
156 | } | |
157 | ||
158 | intf->device_id = device_id; | |
159 | ||
160 | return 0; | |
161 | ||
162 | err_svc_id_free: | |
163 | /* | |
164 | * XXX Should we tell SVC that this id doesn't belong to interface | |
165 | * XXX anymore. | |
166 | */ | |
167 | err_ida_remove: | |
168 | ida_simple_remove(&svc->device_id_map, device_id); | |
169 | ||
170 | return ret; | |
171 | } | |
172 | ||
173 | static void gb_interface_route_destroy(struct gb_interface *intf) | |
174 | { | |
175 | struct gb_svc *svc = intf->hd->svc; | |
176 | ||
e9f2f688 | 177 | if (intf->device_id == GB_INTERFACE_DEVICE_ID_BAD) |
4d5f6218 JH |
178 | return; |
179 | ||
180 | gb_svc_route_destroy(svc, svc->ap_intf_id, intf->interface_id); | |
181 | ida_simple_remove(&svc->device_id_map, intf->device_id); | |
e9f2f688 | 182 | intf->device_id = GB_INTERFACE_DEVICE_ID_BAD; |
4d5f6218 JH |
183 | } |
184 | ||
55742d2a JH |
185 | /* Locking: Caller holds the interface mutex. */ |
186 | static int gb_interface_legacy_mode_switch(struct gb_interface *intf) | |
187 | { | |
188 | int ret; | |
189 | ||
190 | dev_info(&intf->dev, "legacy mode switch detected\n"); | |
191 | ||
192 | /* Mark as disconnected to prevent I/O during disable. */ | |
193 | intf->disconnected = true; | |
194 | gb_interface_disable(intf); | |
195 | intf->disconnected = false; | |
196 | ||
197 | ret = gb_interface_enable(intf); | |
198 | if (ret) { | |
199 | dev_err(&intf->dev, "failed to re-enable interface: %d\n", ret); | |
200 | gb_interface_deactivate(intf); | |
201 | } | |
202 | ||
203 | return ret; | |
204 | } | |
205 | ||
206 | void gb_interface_mailbox_event(struct gb_interface *intf, u16 result, | |
0c85ae28 | 207 | u32 mailbox) |
55742d2a JH |
208 | { |
209 | mutex_lock(&intf->mutex); | |
210 | ||
211 | if (result) { | |
212 | dev_warn(&intf->dev, | |
0c85ae28 DS |
213 | "mailbox event with UniPro error: 0x%04x\n", |
214 | result); | |
55742d2a JH |
215 | goto err_disable; |
216 | } | |
217 | ||
218 | if (mailbox != GB_SVC_INTF_MAILBOX_GREYBUS) { | |
219 | dev_warn(&intf->dev, | |
0c85ae28 DS |
220 | "mailbox event with unexpected value: 0x%08x\n", |
221 | mailbox); | |
55742d2a JH |
222 | goto err_disable; |
223 | } | |
224 | ||
225 | if (intf->quirks & GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH) { | |
226 | gb_interface_legacy_mode_switch(intf); | |
227 | goto out_unlock; | |
228 | } | |
229 | ||
230 | if (!intf->mode_switch) { | |
231 | dev_warn(&intf->dev, "unexpected mailbox event: 0x%08x\n", | |
0c85ae28 | 232 | mailbox); |
55742d2a JH |
233 | goto err_disable; |
234 | } | |
235 | ||
236 | dev_info(&intf->dev, "mode switch detected\n"); | |
237 | ||
238 | complete(&intf->mode_switch_completion); | |
239 | ||
240 | out_unlock: | |
241 | mutex_unlock(&intf->mutex); | |
242 | ||
243 | return; | |
244 | ||
245 | err_disable: | |
246 | gb_interface_disable(intf); | |
247 | gb_interface_deactivate(intf); | |
248 | mutex_unlock(&intf->mutex); | |
249 | } | |
250 | ||
251 | static void gb_interface_mode_switch_work(struct work_struct *work) | |
252 | { | |
253 | struct gb_interface *intf; | |
254 | struct gb_control *control; | |
255 | unsigned long timeout; | |
256 | int ret; | |
257 | ||
258 | intf = container_of(work, struct gb_interface, mode_switch_work); | |
259 | ||
260 | mutex_lock(&intf->mutex); | |
261 | /* Make sure interface is still enabled. */ | |
262 | if (!intf->enabled) { | |
263 | dev_dbg(&intf->dev, "mode switch aborted\n"); | |
264 | intf->mode_switch = false; | |
265 | mutex_unlock(&intf->mutex); | |
266 | goto out_interface_put; | |
267 | } | |
268 | ||
269 | /* | |
270 | * Prepare the control device for mode switch and make sure to get an | |
271 | * extra reference before it goes away during interface disable. | |
272 | */ | |
273 | control = gb_control_get(intf->control); | |
274 | gb_control_mode_switch_prepare(control); | |
275 | gb_interface_disable(intf); | |
276 | mutex_unlock(&intf->mutex); | |
277 | ||
278 | timeout = msecs_to_jiffies(GB_INTERFACE_MODE_SWITCH_TIMEOUT); | |
279 | ret = wait_for_completion_interruptible_timeout( | |
280 | &intf->mode_switch_completion, timeout); | |
281 | ||
282 | /* Finalise control-connection mode switch. */ | |
283 | gb_control_mode_switch_complete(control); | |
284 | gb_control_put(control); | |
285 | ||
286 | if (ret < 0) { | |
287 | dev_err(&intf->dev, "mode switch interrupted\n"); | |
288 | goto err_deactivate; | |
289 | } else if (ret == 0) { | |
290 | dev_err(&intf->dev, "mode switch timed out\n"); | |
291 | goto err_deactivate; | |
292 | } | |
293 | ||
294 | /* Re-enable (re-enumerate) interface if still active. */ | |
295 | mutex_lock(&intf->mutex); | |
296 | intf->mode_switch = false; | |
297 | if (intf->active) { | |
298 | ret = gb_interface_enable(intf); | |
299 | if (ret) { | |
300 | dev_err(&intf->dev, "failed to re-enable interface: %d\n", | |
0c85ae28 | 301 | ret); |
55742d2a JH |
302 | gb_interface_deactivate(intf); |
303 | } | |
304 | } | |
305 | mutex_unlock(&intf->mutex); | |
306 | ||
307 | out_interface_put: | |
308 | gb_interface_put(intf); | |
309 | ||
310 | return; | |
311 | ||
312 | err_deactivate: | |
313 | mutex_lock(&intf->mutex); | |
314 | intf->mode_switch = false; | |
315 | gb_interface_deactivate(intf); | |
316 | mutex_unlock(&intf->mutex); | |
317 | ||
318 | gb_interface_put(intf); | |
319 | } | |
320 | ||
321 | int gb_interface_request_mode_switch(struct gb_interface *intf) | |
322 | { | |
323 | int ret = 0; | |
324 | ||
325 | mutex_lock(&intf->mutex); | |
326 | if (intf->mode_switch) { | |
327 | ret = -EBUSY; | |
328 | goto out_unlock; | |
329 | } | |
330 | ||
331 | intf->mode_switch = true; | |
332 | reinit_completion(&intf->mode_switch_completion); | |
333 | ||
334 | /* | |
335 | * Get a reference to the interface device, which will be put once the | |
336 | * mode switch is complete. | |
337 | */ | |
338 | get_device(&intf->dev); | |
339 | ||
340 | if (!queue_work(system_long_wq, &intf->mode_switch_work)) { | |
341 | put_device(&intf->dev); | |
342 | ret = -EBUSY; | |
343 | goto out_unlock; | |
344 | } | |
345 | ||
346 | out_unlock: | |
347 | mutex_unlock(&intf->mutex); | |
348 | ||
349 | return ret; | |
350 | } | |
351 | EXPORT_SYMBOL_GPL(gb_interface_request_mode_switch); | |
352 | ||
c2d80906 | 353 | /* |
133e366b | 354 | * T_TstSrcIncrement is written by the module on ES2 as a stand-in for the |
50ad4163 JH |
355 | * init-status attribute DME_TOSHIBA_INIT_STATUS. The AP needs to read and |
356 | * clear it after reading a non-zero value from it. | |
c2d80906 JH |
357 | * |
358 | * FIXME: This is module-hardware dependent and needs to be extended for every | |
359 | * type of module we want to support. | |
360 | */ | |
133e366b | 361 | static int gb_interface_read_and_clear_init_status(struct gb_interface *intf) |
c2d80906 JH |
362 | { |
363 | struct gb_host_device *hd = intf->hd; | |
a4b08df4 | 364 | unsigned long bootrom_quirks; |
0c543f9b | 365 | unsigned long s2l_quirks; |
c2d80906 JH |
366 | int ret; |
367 | u32 value; | |
368 | u16 attr; | |
369 | u8 init_status; | |
370 | ||
371 | /* | |
133e366b JH |
372 | * ES2 bridges use T_TstSrcIncrement for the init status. |
373 | * | |
374 | * FIXME: Remove ES2 support | |
c2d80906 | 375 | */ |
7d7acc06 | 376 | if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS) |
50ad4163 | 377 | attr = DME_T_TST_SRC_INCREMENT; |
c2d80906 | 378 | else |
23931ffb | 379 | attr = DME_TOSHIBA_GMP_INIT_STATUS; |
c2d80906 | 380 | |
c2d80906 | 381 | ret = gb_svc_dme_peer_get(hd->svc, intf->interface_id, attr, |
50ad4163 | 382 | DME_SELECTOR_INDEX_NULL, &value); |
c2d80906 JH |
383 | if (ret) |
384 | return ret; | |
385 | ||
386 | /* | |
133e366b JH |
387 | * A nonzero init status indicates the module has finished |
388 | * initializing. | |
c2d80906 JH |
389 | */ |
390 | if (!value) { | |
133e366b | 391 | dev_err(&intf->dev, "invalid init status\n"); |
c2d80906 JH |
392 | return -ENODEV; |
393 | } | |
394 | ||
395 | /* | |
ec199ccd | 396 | * Extract the init status. |
133e366b | 397 | * |
c2d80906 JH |
398 | * For ES2: We need to check lowest 8 bits of 'value'. |
399 | * For ES3: We need to check highest 8 bits out of 32 of 'value'. | |
133e366b JH |
400 | * |
401 | * FIXME: Remove ES2 support | |
c2d80906 | 402 | */ |
7d7acc06 | 403 | if (intf->quirks & GB_INTERFACE_QUIRK_NO_INIT_STATUS) |
e12811ef | 404 | init_status = value & 0xff; |
c2d80906 JH |
405 | else |
406 | init_status = value >> 24; | |
407 | ||
ec199ccd | 408 | /* |
a4b08df4 JH |
409 | * Check if the interface is executing the quirky ES3 bootrom that, |
410 | * for example, requires E2EFC, CSD and CSV to be disabled. | |
ec199ccd | 411 | */ |
d9fa3494 | 412 | bootrom_quirks = GB_INTERFACE_QUIRK_NO_CPORT_FEATURES | |
55742d2a | 413 | GB_INTERFACE_QUIRK_FORCED_DISABLE | |
2358024b | 414 | GB_INTERFACE_QUIRK_LEGACY_MODE_SWITCH | |
47cbaf5e | 415 | GB_INTERFACE_QUIRK_NO_BUNDLE_ACTIVATE; |
0c543f9b VK |
416 | |
417 | s2l_quirks = GB_INTERFACE_QUIRK_NO_PM; | |
418 | ||
ec199ccd | 419 | switch (init_status) { |
50ad4163 JH |
420 | case GB_INIT_BOOTROM_UNIPRO_BOOT_STARTED: |
421 | case GB_INIT_BOOTROM_FALLBACK_UNIPRO_BOOT_STARTED: | |
a4b08df4 | 422 | intf->quirks |= bootrom_quirks; |
ec199ccd | 423 | break; |
0c543f9b VK |
424 | case GB_INIT_S2_LOADER_BOOT_STARTED: |
425 | /* S2 Loader doesn't support runtime PM */ | |
426 | intf->quirks &= ~bootrom_quirks; | |
427 | intf->quirks |= s2l_quirks; | |
428 | break; | |
6ddbed57 | 429 | default: |
a4b08df4 | 430 | intf->quirks &= ~bootrom_quirks; |
0c543f9b | 431 | intf->quirks &= ~s2l_quirks; |
ec199ccd | 432 | } |
c2d80906 | 433 | |
133e366b | 434 | /* Clear the init status. */ |
c2d80906 | 435 | return gb_svc_dme_peer_set(hd->svc, intf->interface_id, attr, |
50ad4163 | 436 | DME_SELECTOR_INDEX_NULL, 0); |
c2d80906 JH |
437 | } |
438 | ||
4ab9b3c2 GKH |
439 | /* interface sysfs attributes */ |
440 | #define gb_interface_attr(field, type) \ | |
441 | static ssize_t field##_show(struct device *dev, \ | |
442 | struct device_attribute *attr, \ | |
443 | char *buf) \ | |
ab88eb58 | 444 | { \ |
4ab9b3c2 | 445 | struct gb_interface *intf = to_gb_interface(dev); \ |
2c7df744 | 446 | return scnprintf(buf, PAGE_SIZE, type"\n", intf->field); \ |
ab88eb58 GKH |
447 | } \ |
448 | static DEVICE_ATTR_RO(field) | |
449 | ||
0e9403a0 VK |
450 | gb_interface_attr(ddbl1_manufacturer_id, "0x%08x"); |
451 | gb_interface_attr(ddbl1_product_id, "0x%08x"); | |
2c7df744 | 452 | gb_interface_attr(interface_id, "%u"); |
611924dd GKH |
453 | gb_interface_attr(vendor_id, "0x%08x"); |
454 | gb_interface_attr(product_id, "0x%08x"); | |
57c6bcc6 | 455 | gb_interface_attr(serial_number, "0x%016llx"); |
ab88eb58 | 456 | |
ddb10c8a DL |
457 | static ssize_t voltage_now_show(struct device *dev, |
458 | struct device_attribute *attr, char *buf) | |
459 | { | |
460 | struct gb_interface *intf = to_gb_interface(dev); | |
461 | int ret; | |
462 | u32 measurement; | |
463 | ||
464 | ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id, | |
465 | GB_SVC_PWRMON_TYPE_VOL, | |
466 | &measurement); | |
467 | if (ret) { | |
468 | dev_err(&intf->dev, "failed to get voltage sample (%d)\n", ret); | |
469 | return ret; | |
470 | } | |
471 | ||
472 | return sprintf(buf, "%u\n", measurement); | |
473 | } | |
474 | static DEVICE_ATTR_RO(voltage_now); | |
475 | ||
476 | static ssize_t current_now_show(struct device *dev, | |
477 | struct device_attribute *attr, char *buf) | |
478 | { | |
479 | struct gb_interface *intf = to_gb_interface(dev); | |
480 | int ret; | |
481 | u32 measurement; | |
482 | ||
483 | ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id, | |
484 | GB_SVC_PWRMON_TYPE_CURR, | |
485 | &measurement); | |
486 | if (ret) { | |
487 | dev_err(&intf->dev, "failed to get current sample (%d)\n", ret); | |
488 | return ret; | |
489 | } | |
490 | ||
491 | return sprintf(buf, "%u\n", measurement); | |
492 | } | |
493 | static DEVICE_ATTR_RO(current_now); | |
494 | ||
495 | static ssize_t power_now_show(struct device *dev, | |
496 | struct device_attribute *attr, char *buf) | |
497 | { | |
498 | struct gb_interface *intf = to_gb_interface(dev); | |
499 | int ret; | |
500 | u32 measurement; | |
501 | ||
502 | ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id, | |
503 | GB_SVC_PWRMON_TYPE_PWR, | |
504 | &measurement); | |
505 | if (ret) { | |
506 | dev_err(&intf->dev, "failed to get power sample (%d)\n", ret); | |
507 | return ret; | |
508 | } | |
509 | ||
510 | return sprintf(buf, "%u\n", measurement); | |
511 | } | |
512 | static DEVICE_ATTR_RO(power_now); | |
513 | ||
93e29c85 VK |
514 | static ssize_t power_state_show(struct device *dev, |
515 | struct device_attribute *attr, char *buf) | |
516 | { | |
517 | struct gb_interface *intf = to_gb_interface(dev); | |
518 | ||
519 | if (intf->active) | |
520 | return scnprintf(buf, PAGE_SIZE, "on\n"); | |
521 | else | |
522 | return scnprintf(buf, PAGE_SIZE, "off\n"); | |
523 | } | |
524 | ||
525 | static ssize_t power_state_store(struct device *dev, | |
526 | struct device_attribute *attr, const char *buf, | |
527 | size_t len) | |
528 | { | |
529 | struct gb_interface *intf = to_gb_interface(dev); | |
530 | bool activate; | |
531 | int ret = 0; | |
532 | ||
533 | if (kstrtobool(buf, &activate)) | |
534 | return -EINVAL; | |
535 | ||
536 | mutex_lock(&intf->mutex); | |
537 | ||
538 | if (activate == intf->active) | |
539 | goto unlock; | |
540 | ||
541 | if (activate) { | |
542 | ret = gb_interface_activate(intf); | |
543 | if (ret) { | |
544 | dev_err(&intf->dev, | |
545 | "failed to activate interface: %d\n", ret); | |
546 | goto unlock; | |
547 | } | |
548 | ||
549 | ret = gb_interface_enable(intf); | |
550 | if (ret) { | |
551 | dev_err(&intf->dev, | |
552 | "failed to enable interface: %d\n", ret); | |
553 | gb_interface_deactivate(intf); | |
554 | goto unlock; | |
555 | } | |
556 | } else { | |
557 | gb_interface_disable(intf); | |
558 | gb_interface_deactivate(intf); | |
559 | } | |
560 | ||
561 | unlock: | |
562 | mutex_unlock(&intf->mutex); | |
563 | ||
564 | if (ret) | |
565 | return ret; | |
566 | ||
567 | return len; | |
568 | } | |
569 | static DEVICE_ATTR_RW(power_state); | |
570 | ||
1bb61840 JH |
571 | static const char *gb_interface_type_string(struct gb_interface *intf) |
572 | { | |
573 | static const char * const types[] = { | |
a212b758 JH |
574 | [GB_INTERFACE_TYPE_INVALID] = "invalid", |
575 | [GB_INTERFACE_TYPE_UNKNOWN] = "unknown", | |
576 | [GB_INTERFACE_TYPE_DUMMY] = "dummy", | |
577 | [GB_INTERFACE_TYPE_UNIPRO] = "unipro", | |
578 | [GB_INTERFACE_TYPE_GREYBUS] = "greybus", | |
1bb61840 JH |
579 | }; |
580 | ||
581 | return types[intf->type]; | |
582 | } | |
583 | ||
584 | static ssize_t interface_type_show(struct device *dev, | |
585 | struct device_attribute *attr, char *buf) | |
586 | { | |
587 | struct gb_interface *intf = to_gb_interface(dev); | |
588 | ||
589 | return sprintf(buf, "%s\n", gb_interface_type_string(intf)); | |
590 | } | |
591 | static DEVICE_ATTR_RO(interface_type); | |
592 | ||
441ac1fa | 593 | static struct attribute *interface_unipro_attrs[] = { |
0e9403a0 VK |
594 | &dev_attr_ddbl1_manufacturer_id.attr, |
595 | &dev_attr_ddbl1_product_id.attr, | |
441ac1fa JH |
596 | NULL |
597 | }; | |
598 | ||
599 | static struct attribute *interface_greybus_attrs[] = { | |
9f59263a JH |
600 | &dev_attr_vendor_id.attr, |
601 | &dev_attr_product_id.attr, | |
57c6bcc6 | 602 | &dev_attr_serial_number.attr, |
441ac1fa JH |
603 | NULL |
604 | }; | |
605 | ||
606 | static struct attribute *interface_power_attrs[] = { | |
ddb10c8a DL |
607 | &dev_attr_voltage_now.attr, |
608 | &dev_attr_current_now.attr, | |
609 | &dev_attr_power_now.attr, | |
93e29c85 | 610 | &dev_attr_power_state.attr, |
441ac1fa JH |
611 | NULL |
612 | }; | |
613 | ||
614 | static struct attribute *interface_common_attrs[] = { | |
b5d1d128 | 615 | &dev_attr_interface_id.attr, |
1bb61840 | 616 | &dev_attr_interface_type.attr, |
441ac1fa JH |
617 | NULL |
618 | }; | |
619 | ||
83564252 | 620 | static umode_t interface_unipro_is_visible(struct kobject *kobj, |
0c85ae28 | 621 | struct attribute *attr, int n) |
83564252 | 622 | { |
947bece1 | 623 | struct device *dev = kobj_to_dev(kobj); |
83564252 JH |
624 | struct gb_interface *intf = to_gb_interface(dev); |
625 | ||
626 | switch (intf->type) { | |
a212b758 JH |
627 | case GB_INTERFACE_TYPE_UNIPRO: |
628 | case GB_INTERFACE_TYPE_GREYBUS: | |
83564252 JH |
629 | return attr->mode; |
630 | default: | |
631 | return 0; | |
632 | } | |
633 | } | |
634 | ||
635 | static umode_t interface_greybus_is_visible(struct kobject *kobj, | |
0c85ae28 | 636 | struct attribute *attr, int n) |
83564252 | 637 | { |
947bece1 | 638 | struct device *dev = kobj_to_dev(kobj); |
83564252 JH |
639 | struct gb_interface *intf = to_gb_interface(dev); |
640 | ||
641 | switch (intf->type) { | |
a212b758 | 642 | case GB_INTERFACE_TYPE_GREYBUS: |
83564252 JH |
643 | return attr->mode; |
644 | default: | |
645 | return 0; | |
646 | } | |
647 | } | |
648 | ||
649 | static umode_t interface_power_is_visible(struct kobject *kobj, | |
0c85ae28 | 650 | struct attribute *attr, int n) |
83564252 | 651 | { |
947bece1 | 652 | struct device *dev = kobj_to_dev(kobj); |
83564252 JH |
653 | struct gb_interface *intf = to_gb_interface(dev); |
654 | ||
655 | switch (intf->type) { | |
a212b758 JH |
656 | case GB_INTERFACE_TYPE_UNIPRO: |
657 | case GB_INTERFACE_TYPE_GREYBUS: | |
83564252 JH |
658 | return attr->mode; |
659 | default: | |
660 | return 0; | |
661 | } | |
662 | } | |
663 | ||
441ac1fa | 664 | static const struct attribute_group interface_unipro_group = { |
83564252 | 665 | .is_visible = interface_unipro_is_visible, |
441ac1fa JH |
666 | .attrs = interface_unipro_attrs, |
667 | }; | |
668 | ||
669 | static const struct attribute_group interface_greybus_group = { | |
83564252 | 670 | .is_visible = interface_greybus_is_visible, |
441ac1fa JH |
671 | .attrs = interface_greybus_attrs, |
672 | }; | |
673 | ||
674 | static const struct attribute_group interface_power_group = { | |
83564252 | 675 | .is_visible = interface_power_is_visible, |
441ac1fa JH |
676 | .attrs = interface_power_attrs, |
677 | }; | |
678 | ||
679 | static const struct attribute_group interface_common_group = { | |
680 | .attrs = interface_common_attrs, | |
681 | }; | |
682 | ||
683 | static const struct attribute_group *interface_groups[] = { | |
684 | &interface_unipro_group, | |
685 | &interface_greybus_group, | |
686 | &interface_power_group, | |
687 | &interface_common_group, | |
688 | NULL | |
ab88eb58 | 689 | }; |
ab88eb58 | 690 | |
51b5d8d7 | 691 | static void gb_interface_release(struct device *dev) |
697e55d3 | 692 | { |
4ab9b3c2 | 693 | struct gb_interface *intf = to_gb_interface(dev); |
697e55d3 | 694 | |
cb4c8441 AE |
695 | trace_gb_interface_release(intf); |
696 | ||
4ab9b3c2 | 697 | kfree(intf); |
697e55d3 AE |
698 | } |
699 | ||
948c6227 | 700 | #ifdef CONFIG_PM |
30a3bf7b DL |
701 | static int gb_interface_suspend(struct device *dev) |
702 | { | |
703 | struct gb_interface *intf = to_gb_interface(dev); | |
bdfb95c4 | 704 | int ret; |
30a3bf7b DL |
705 | |
706 | ret = gb_control_interface_suspend_prepare(intf->control); | |
707 | if (ret) | |
708 | return ret; | |
709 | ||
30a3bf7b DL |
710 | ret = gb_control_suspend(intf->control); |
711 | if (ret) | |
712 | goto err_hibernate_abort; | |
713 | ||
714 | ret = gb_interface_hibernate_link(intf); | |
715 | if (ret) | |
716 | return ret; | |
717 | ||
718 | /* Delay to allow interface to enter standby before disabling refclk */ | |
719 | msleep(GB_INTERFACE_SUSPEND_HIBERNATE_DELAY_MS); | |
720 | ||
721 | ret = gb_interface_refclk_set(intf, false); | |
722 | if (ret) | |
723 | return ret; | |
724 | ||
725 | return 0; | |
726 | ||
727 | err_hibernate_abort: | |
728 | gb_control_interface_hibernate_abort(intf->control); | |
729 | ||
30a3bf7b DL |
730 | return ret; |
731 | } | |
732 | ||
733 | static int gb_interface_resume(struct device *dev) | |
734 | { | |
735 | struct gb_interface *intf = to_gb_interface(dev); | |
736 | struct gb_svc *svc = intf->hd->svc; | |
737 | int ret; | |
738 | ||
739 | ret = gb_interface_refclk_set(intf, true); | |
740 | if (ret) | |
741 | return ret; | |
742 | ||
743 | ret = gb_svc_intf_resume(svc, intf->interface_id); | |
744 | if (ret) | |
745 | return ret; | |
746 | ||
747 | ret = gb_control_resume(intf->control); | |
748 | if (ret) | |
749 | return ret; | |
750 | ||
30a3bf7b DL |
751 | return 0; |
752 | } | |
753 | ||
754 | static int gb_interface_runtime_idle(struct device *dev) | |
755 | { | |
756 | pm_runtime_mark_last_busy(dev); | |
757 | pm_request_autosuspend(dev); | |
758 | ||
759 | return 0; | |
760 | } | |
761 | #endif | |
762 | ||
763 | static const struct dev_pm_ops gb_interface_pm_ops = { | |
764 | SET_RUNTIME_PM_OPS(gb_interface_suspend, gb_interface_resume, | |
765 | gb_interface_runtime_idle) | |
766 | }; | |
767 | ||
4ab9b3c2 GKH |
768 | struct device_type greybus_interface_type = { |
769 | .name = "greybus_interface", | |
51b5d8d7 | 770 | .release = gb_interface_release, |
30a3bf7b | 771 | .pm = &gb_interface_pm_ops, |
f0f61b90 GKH |
772 | }; |
773 | ||
e1e9dbdd | 774 | /* |
23931ffb | 775 | * A Greybus module represents a user-replaceable component on a GMP |
4ab9b3c2 GKH |
776 | * phone. An interface is the physical connection on that module. A |
777 | * module may have more than one interface. | |
e1e9dbdd | 778 | * |
c9d9d0d4 VK |
779 | * Create a gb_interface structure to represent a discovered interface. |
780 | * The position of interface within the Endo is encoded in "interface_id" | |
781 | * argument. | |
782 | * | |
df671553 | 783 | * Returns a pointer to the new interfce or a null pointer if a |
e1e9dbdd AE |
784 | * failure occurs due to memory exhaustion. |
785 | */ | |
b15d97d7 | 786 | struct gb_interface *gb_interface_create(struct gb_module *module, |
6c68da26 | 787 | u8 interface_id) |
e1e9dbdd | 788 | { |
b15d97d7 | 789 | struct gb_host_device *hd = module->hd; |
4ab9b3c2 | 790 | struct gb_interface *intf; |
e1e9dbdd | 791 | |
4ab9b3c2 GKH |
792 | intf = kzalloc(sizeof(*intf), GFP_KERNEL); |
793 | if (!intf) | |
8b0df4b2 | 794 | return NULL; |
e1e9dbdd | 795 | |
4ab9b3c2 | 796 | intf->hd = hd; /* XXX refcount? */ |
b15d97d7 | 797 | intf->module = module; |
c9d9d0d4 | 798 | intf->interface_id = interface_id; |
4ab9b3c2 | 799 | INIT_LIST_HEAD(&intf->bundles); |
86cad666 | 800 | INIT_LIST_HEAD(&intf->manifest_descs); |
36602a29 | 801 | mutex_init(&intf->mutex); |
55742d2a JH |
802 | INIT_WORK(&intf->mode_switch_work, gb_interface_mode_switch_work); |
803 | init_completion(&intf->mode_switch_completion); | |
e1e9dbdd | 804 | |
c3add788 | 805 | /* Invalid device id to start with */ |
e9f2f688 | 806 | intf->device_id = GB_INTERFACE_DEVICE_ID_BAD; |
c3add788 | 807 | |
b15d97d7 | 808 | intf->dev.parent = &module->dev; |
4ab9b3c2 GKH |
809 | intf->dev.bus = &greybus_bus_type; |
810 | intf->dev.type = &greybus_interface_type; | |
811 | intf->dev.groups = interface_groups; | |
b15d97d7 | 812 | intf->dev.dma_mask = module->dev.dma_mask; |
4ab9b3c2 | 813 | device_initialize(&intf->dev); |
b15d97d7 | 814 | dev_set_name(&intf->dev, "%s.%u", dev_name(&module->dev), |
0c85ae28 | 815 | interface_id); |
0a68a16b | 816 | |
30a3bf7b DL |
817 | pm_runtime_set_autosuspend_delay(&intf->dev, |
818 | GB_INTERFACE_AUTOSUSPEND_MS); | |
819 | ||
cb4c8441 AE |
820 | trace_gb_interface_create(intf); |
821 | ||
4ab9b3c2 | 822 | return intf; |
e1e9dbdd AE |
823 | } |
824 | ||
ec562f28 JH |
825 | static int gb_interface_vsys_set(struct gb_interface *intf, bool enable) |
826 | { | |
827 | struct gb_svc *svc = intf->hd->svc; | |
828 | int ret; | |
829 | ||
830 | dev_dbg(&intf->dev, "%s - %d\n", __func__, enable); | |
831 | ||
832 | ret = gb_svc_intf_vsys_set(svc, intf->interface_id, enable); | |
833 | if (ret) { | |
ae36e81e | 834 | dev_err(&intf->dev, "failed to set v_sys: %d\n", ret); |
ec562f28 JH |
835 | return ret; |
836 | } | |
837 | ||
838 | return 0; | |
839 | } | |
840 | ||
841 | static int gb_interface_refclk_set(struct gb_interface *intf, bool enable) | |
842 | { | |
843 | struct gb_svc *svc = intf->hd->svc; | |
844 | int ret; | |
845 | ||
846 | dev_dbg(&intf->dev, "%s - %d\n", __func__, enable); | |
847 | ||
848 | ret = gb_svc_intf_refclk_set(svc, intf->interface_id, enable); | |
849 | if (ret) { | |
ae36e81e | 850 | dev_err(&intf->dev, "failed to set refclk: %d\n", ret); |
ec562f28 JH |
851 | return ret; |
852 | } | |
853 | ||
854 | return 0; | |
855 | } | |
856 | ||
857 | static int gb_interface_unipro_set(struct gb_interface *intf, bool enable) | |
858 | { | |
859 | struct gb_svc *svc = intf->hd->svc; | |
860 | int ret; | |
861 | ||
862 | dev_dbg(&intf->dev, "%s - %d\n", __func__, enable); | |
863 | ||
864 | ret = gb_svc_intf_unipro_set(svc, intf->interface_id, enable); | |
865 | if (ret) { | |
ae36e81e | 866 | dev_err(&intf->dev, "failed to set UniPro: %d\n", ret); |
ec562f28 JH |
867 | return ret; |
868 | } | |
869 | ||
870 | return 0; | |
871 | } | |
872 | ||
62491622 JH |
873 | static int gb_interface_activate_operation(struct gb_interface *intf, |
874 | enum gb_interface_type *intf_type) | |
ec562f28 JH |
875 | { |
876 | struct gb_svc *svc = intf->hd->svc; | |
877 | u8 type; | |
878 | int ret; | |
879 | ||
880 | dev_dbg(&intf->dev, "%s\n", __func__); | |
881 | ||
882 | ret = gb_svc_intf_activate(svc, intf->interface_id, &type); | |
883 | if (ret) { | |
884 | dev_err(&intf->dev, "failed to activate: %d\n", ret); | |
885 | return ret; | |
886 | } | |
887 | ||
888 | switch (type) { | |
889 | case GB_SVC_INTF_TYPE_DUMMY: | |
62491622 | 890 | *intf_type = GB_INTERFACE_TYPE_DUMMY; |
ec562f28 JH |
891 | /* FIXME: handle as an error for now */ |
892 | return -ENODEV; | |
893 | case GB_SVC_INTF_TYPE_UNIPRO: | |
62491622 | 894 | *intf_type = GB_INTERFACE_TYPE_UNIPRO; |
ec562f28 | 895 | dev_err(&intf->dev, "interface type UniPro not supported\n"); |
3e93cb6a JH |
896 | /* FIXME: handle as an error for now */ |
897 | return -ENODEV; | |
ec562f28 | 898 | case GB_SVC_INTF_TYPE_GREYBUS: |
62491622 | 899 | *intf_type = GB_INTERFACE_TYPE_GREYBUS; |
ec562f28 JH |
900 | break; |
901 | default: | |
902 | dev_err(&intf->dev, "unknown interface type: %u\n", type); | |
62491622 | 903 | *intf_type = GB_INTERFACE_TYPE_UNKNOWN; |
ec562f28 JH |
904 | return -ENODEV; |
905 | } | |
906 | ||
907 | return 0; | |
908 | } | |
909 | ||
910 | static int gb_interface_hibernate_link(struct gb_interface *intf) | |
911 | { | |
cc28c2c2 | 912 | struct gb_svc *svc = intf->hd->svc; |
ec562f28 | 913 | |
cc28c2c2 | 914 | return gb_svc_intf_set_power_mode_hibernate(svc, intf->interface_id); |
ec562f28 JH |
915 | } |
916 | ||
62491622 JH |
917 | static int _gb_interface_activate(struct gb_interface *intf, |
918 | enum gb_interface_type *type) | |
4d5f6218 JH |
919 | { |
920 | int ret; | |
921 | ||
62491622 JH |
922 | *type = GB_INTERFACE_TYPE_UNKNOWN; |
923 | ||
12169bc9 | 924 | if (intf->ejected || intf->removed) |
36602a29 JH |
925 | return -ENODEV; |
926 | ||
ec562f28 | 927 | ret = gb_interface_vsys_set(intf, true); |
153ff7e7 JH |
928 | if (ret) |
929 | return ret; | |
930 | ||
ec562f28 JH |
931 | ret = gb_interface_refclk_set(intf, true); |
932 | if (ret) | |
933 | goto err_vsys_disable; | |
934 | ||
935 | ret = gb_interface_unipro_set(intf, true); | |
936 | if (ret) | |
937 | goto err_refclk_disable; | |
938 | ||
62491622 | 939 | ret = gb_interface_activate_operation(intf, type); |
4f7e413b JH |
940 | if (ret) { |
941 | switch (*type) { | |
942 | case GB_INTERFACE_TYPE_UNIPRO: | |
943 | case GB_INTERFACE_TYPE_GREYBUS: | |
944 | goto err_hibernate_link; | |
945 | default: | |
946 | goto err_unipro_disable; | |
947 | } | |
948 | } | |
ec562f28 JH |
949 | |
950 | ret = gb_interface_read_dme(intf); | |
951 | if (ret) | |
952 | goto err_hibernate_link; | |
953 | ||
4d5f6218 JH |
954 | ret = gb_interface_route_create(intf); |
955 | if (ret) | |
ec562f28 | 956 | goto err_hibernate_link; |
4d5f6218 | 957 | |
1e1565e5 JH |
958 | intf->active = true; |
959 | ||
cb4c8441 AE |
960 | trace_gb_interface_activate(intf); |
961 | ||
4d5f6218 | 962 | return 0; |
ec562f28 JH |
963 | |
964 | err_hibernate_link: | |
965 | gb_interface_hibernate_link(intf); | |
966 | err_unipro_disable: | |
967 | gb_interface_unipro_set(intf, false); | |
968 | err_refclk_disable: | |
969 | gb_interface_refclk_set(intf, false); | |
970 | err_vsys_disable: | |
971 | gb_interface_vsys_set(intf, false); | |
972 | ||
973 | return ret; | |
4d5f6218 JH |
974 | } |
975 | ||
3e93cb6a | 976 | /* |
62491622 JH |
977 | * At present, we assume a UniPro-only module to be a Greybus module that |
978 | * failed to send its mailbox poke. There is some reason to believe that this | |
979 | * is because of a bug in the ES3 bootrom. | |
3e93cb6a | 980 | * |
62491622 | 981 | * FIXME: Check if this is a Toshiba bridge before retrying? |
3e93cb6a | 982 | */ |
62491622 JH |
983 | static int _gb_interface_activate_es3_hack(struct gb_interface *intf, |
984 | enum gb_interface_type *type) | |
3e93cb6a JH |
985 | { |
986 | int retries = 3; | |
987 | int ret; | |
988 | ||
3e93cb6a | 989 | while (retries--) { |
62491622 JH |
990 | ret = _gb_interface_activate(intf, type); |
991 | if (ret == -ENODEV && *type == GB_INTERFACE_TYPE_UNIPRO) | |
3e93cb6a JH |
992 | continue; |
993 | ||
994 | break; | |
995 | } | |
996 | ||
997 | return ret; | |
998 | } | |
999 | ||
62491622 JH |
1000 | /* |
1001 | * Activate an interface. | |
1002 | * | |
1003 | * Locking: Caller holds the interface mutex. | |
1004 | */ | |
1005 | int gb_interface_activate(struct gb_interface *intf) | |
1006 | { | |
1007 | enum gb_interface_type type; | |
1008 | int ret; | |
1009 | ||
1010 | switch (intf->type) { | |
1011 | case GB_INTERFACE_TYPE_INVALID: | |
1012 | case GB_INTERFACE_TYPE_GREYBUS: | |
1013 | ret = _gb_interface_activate_es3_hack(intf, &type); | |
1014 | break; | |
1015 | default: | |
1016 | ret = _gb_interface_activate(intf, &type); | |
1017 | } | |
1018 | ||
1019 | /* Make sure type is detected correctly during reactivation. */ | |
1020 | if (intf->type != GB_INTERFACE_TYPE_INVALID) { | |
1021 | if (type != intf->type) { | |
1022 | dev_err(&intf->dev, "failed to detect interface type\n"); | |
1023 | ||
1024 | if (!ret) | |
1025 | gb_interface_deactivate(intf); | |
1026 | ||
1027 | return -EIO; | |
1028 | } | |
1029 | } else { | |
1030 | intf->type = type; | |
1031 | } | |
1032 | ||
1033 | return ret; | |
1034 | } | |
1035 | ||
36602a29 JH |
1036 | /* |
1037 | * Deactivate an interface. | |
1038 | * | |
1039 | * Locking: Caller holds the interface mutex. | |
1040 | */ | |
4d5f6218 JH |
1041 | void gb_interface_deactivate(struct gb_interface *intf) |
1042 | { | |
1e1565e5 JH |
1043 | if (!intf->active) |
1044 | return; | |
1045 | ||
cb4c8441 AE |
1046 | trace_gb_interface_deactivate(intf); |
1047 | ||
55742d2a JH |
1048 | /* Abort any ongoing mode switch. */ |
1049 | if (intf->mode_switch) | |
1050 | complete(&intf->mode_switch_completion); | |
1051 | ||
4d5f6218 | 1052 | gb_interface_route_destroy(intf); |
ec562f28 JH |
1053 | gb_interface_hibernate_link(intf); |
1054 | gb_interface_unipro_set(intf, false); | |
1055 | gb_interface_refclk_set(intf, false); | |
1056 | gb_interface_vsys_set(intf, false); | |
1e1565e5 JH |
1057 | |
1058 | intf->active = false; | |
4d5f6218 JH |
1059 | } |
1060 | ||
7a137fb2 | 1061 | /* |
96fb6c34 JH |
1062 | * Enable an interface by enabling its control connection, fetching the |
1063 | * manifest and other information over it, and finally registering its child | |
1064 | * devices. | |
36602a29 JH |
1065 | * |
1066 | * Locking: Caller holds the interface mutex. | |
676daaf4 | 1067 | */ |
35580af0 | 1068 | int gb_interface_enable(struct gb_interface *intf) |
676daaf4 | 1069 | { |
49605839 | 1070 | struct gb_control *control; |
a77660a7 | 1071 | struct gb_bundle *bundle, *tmp; |
6c68da26 VK |
1072 | int ret, size; |
1073 | void *manifest; | |
1074 | ||
133e366b | 1075 | ret = gb_interface_read_and_clear_init_status(intf); |
c2d80906 | 1076 | if (ret) { |
133e366b | 1077 | dev_err(&intf->dev, "failed to clear init status: %d\n", ret); |
c2d80906 JH |
1078 | return ret; |
1079 | } | |
1080 | ||
c634650e | 1081 | /* Establish control connection */ |
49605839 JH |
1082 | control = gb_control_create(intf); |
1083 | if (IS_ERR(control)) { | |
ae0f6454 | 1084 | dev_err(&intf->dev, "failed to create control device: %ld\n", |
0c85ae28 | 1085 | PTR_ERR(control)); |
49605839 JH |
1086 | return PTR_ERR(control); |
1087 | } | |
1088 | intf->control = control; | |
1089 | ||
c634650e JH |
1090 | ret = gb_control_enable(intf->control); |
1091 | if (ret) | |
49605839 | 1092 | goto err_put_control; |
0bf1f244 | 1093 | |
6c68da26 VK |
1094 | /* Get manifest size using control protocol on CPort */ |
1095 | size = gb_control_get_manifest_size_operation(intf); | |
1096 | if (size <= 0) { | |
5626e0bf | 1097 | dev_err(&intf->dev, "failed to get manifest size: %d\n", size); |
11548c83 | 1098 | |
6c68da26 | 1099 | if (size) |
11548c83 | 1100 | ret = size; |
6c68da26 | 1101 | else |
11548c83 JH |
1102 | ret = -EINVAL; |
1103 | ||
1104 | goto err_disable_control; | |
6c68da26 VK |
1105 | } |
1106 | ||
1107 | manifest = kmalloc(size, GFP_KERNEL); | |
11548c83 JH |
1108 | if (!manifest) { |
1109 | ret = -ENOMEM; | |
1110 | goto err_disable_control; | |
1111 | } | |
6c68da26 VK |
1112 | |
1113 | /* Get manifest using control protocol on CPort */ | |
1114 | ret = gb_control_get_manifest_operation(intf, manifest, size); | |
1115 | if (ret) { | |
5626e0bf | 1116 | dev_err(&intf->dev, "failed to get manifest: %d\n", ret); |
a77660a7 | 1117 | goto err_free_manifest; |
676daaf4 VK |
1118 | } |
1119 | ||
1120 | /* | |
6c68da26 VK |
1121 | * Parse the manifest and build up our data structures representing |
1122 | * what's in it. | |
676daaf4 | 1123 | */ |
6c68da26 | 1124 | if (!gb_manifest_parse(intf, manifest, size)) { |
5626e0bf | 1125 | dev_err(&intf->dev, "failed to parse manifest\n"); |
6c68da26 | 1126 | ret = -EINVAL; |
a77660a7 | 1127 | goto err_destroy_bundles; |
676daaf4 VK |
1128 | } |
1129 | ||
b807aa7a JH |
1130 | ret = gb_control_get_bundle_versions(intf->control); |
1131 | if (ret) | |
a77660a7 JH |
1132 | goto err_destroy_bundles; |
1133 | ||
4523eae6 DL |
1134 | /* Register the control device and any bundles */ |
1135 | ret = gb_control_add(intf->control); | |
1136 | if (ret) | |
bdfb95c4 | 1137 | goto err_destroy_bundles; |
4523eae6 | 1138 | |
30a3bf7b DL |
1139 | pm_runtime_use_autosuspend(&intf->dev); |
1140 | pm_runtime_get_noresume(&intf->dev); | |
1141 | pm_runtime_set_active(&intf->dev); | |
1142 | pm_runtime_enable(&intf->dev); | |
1143 | ||
96fb6c34 JH |
1144 | list_for_each_entry_safe_reverse(bundle, tmp, &intf->bundles, links) { |
1145 | ret = gb_bundle_add(bundle); | |
1146 | if (ret) { | |
1147 | gb_bundle_destroy(bundle); | |
1148 | continue; | |
1149 | } | |
1150 | } | |
1151 | ||
a77660a7 | 1152 | kfree(manifest); |
b807aa7a | 1153 | |
49605839 JH |
1154 | intf->enabled = true; |
1155 | ||
30a3bf7b DL |
1156 | pm_runtime_put(&intf->dev); |
1157 | ||
cb4c8441 AE |
1158 | trace_gb_interface_enable(intf); |
1159 | ||
a77660a7 JH |
1160 | return 0; |
1161 | ||
1162 | err_destroy_bundles: | |
1163 | list_for_each_entry_safe(bundle, tmp, &intf->bundles, links) | |
1164 | gb_bundle_destroy(bundle); | |
1165 | err_free_manifest: | |
7a137fb2 | 1166 | kfree(manifest); |
11548c83 JH |
1167 | err_disable_control: |
1168 | gb_control_disable(intf->control); | |
49605839 JH |
1169 | err_put_control: |
1170 | gb_control_put(intf->control); | |
1171 | intf->control = NULL; | |
7a137fb2 JH |
1172 | |
1173 | return ret; | |
1174 | } | |
1175 | ||
36602a29 JH |
1176 | /* |
1177 | * Disable an interface and destroy its bundles. | |
1178 | * | |
1179 | * Locking: Caller holds the interface mutex. | |
1180 | */ | |
629c0d00 JH |
1181 | void gb_interface_disable(struct gb_interface *intf) |
1182 | { | |
1183 | struct gb_bundle *bundle; | |
1184 | struct gb_bundle *next; | |
1185 | ||
49605839 JH |
1186 | if (!intf->enabled) |
1187 | return; | |
1188 | ||
cb4c8441 AE |
1189 | trace_gb_interface_disable(intf); |
1190 | ||
30a3bf7b DL |
1191 | pm_runtime_get_sync(&intf->dev); |
1192 | ||
d9fa3494 JH |
1193 | /* Set disconnected flag to avoid I/O during connection tear down. */ |
1194 | if (intf->quirks & GB_INTERFACE_QUIRK_FORCED_DISABLE) | |
1195 | intf->disconnected = true; | |
1196 | ||
629c0d00 JH |
1197 | list_for_each_entry_safe(bundle, next, &intf->bundles, links) |
1198 | gb_bundle_destroy(bundle); | |
1199 | ||
576bffb5 DL |
1200 | if (!intf->mode_switch && !intf->disconnected) |
1201 | gb_control_interface_deactivate_prepare(intf->control); | |
1202 | ||
7326e07b | 1203 | gb_control_del(intf->control); |
629c0d00 | 1204 | gb_control_disable(intf->control); |
49605839 JH |
1205 | gb_control_put(intf->control); |
1206 | intf->control = NULL; | |
1207 | ||
1208 | intf->enabled = false; | |
30a3bf7b DL |
1209 | |
1210 | pm_runtime_disable(&intf->dev); | |
1211 | pm_runtime_set_suspended(&intf->dev); | |
1212 | pm_runtime_dont_use_autosuspend(&intf->dev); | |
1213 | pm_runtime_put_noidle(&intf->dev); | |
629c0d00 JH |
1214 | } |
1215 | ||
96fb6c34 | 1216 | /* Register an interface. */ |
7a137fb2 JH |
1217 | int gb_interface_add(struct gb_interface *intf) |
1218 | { | |
7a137fb2 JH |
1219 | int ret; |
1220 | ||
ab66dd78 JH |
1221 | ret = device_add(&intf->dev); |
1222 | if (ret) { | |
1223 | dev_err(&intf->dev, "failed to register interface: %d\n", ret); | |
7a137fb2 | 1224 | return ret; |
ab66dd78 JH |
1225 | } |
1226 | ||
cb4c8441 AE |
1227 | trace_gb_interface_add(intf); |
1228 | ||
c80a982f | 1229 | dev_info(&intf->dev, "Interface added (%s)\n", |
0c85ae28 | 1230 | gb_interface_type_string(intf)); |
c80a982f JH |
1231 | |
1232 | switch (intf->type) { | |
a212b758 | 1233 | case GB_INTERFACE_TYPE_GREYBUS: |
23931ffb | 1234 | dev_info(&intf->dev, "GMP VID=0x%08x, PID=0x%08x\n", |
0c85ae28 | 1235 | intf->vendor_id, intf->product_id); |
37b8b73f | 1236 | fallthrough; |
a212b758 | 1237 | case GB_INTERFACE_TYPE_UNIPRO: |
c80a982f | 1238 | dev_info(&intf->dev, "DDBL1 Manufacturer=0x%08x, Product=0x%08x\n", |
0c85ae28 DS |
1239 | intf->ddbl1_manufacturer_id, |
1240 | intf->ddbl1_product_id); | |
c80a982f | 1241 | break; |
a212b758 JH |
1242 | default: |
1243 | break; | |
c80a982f | 1244 | } |
907d1e16 | 1245 | |
7a137fb2 | 1246 | return 0; |
676daaf4 | 1247 | } |
629c0d00 | 1248 | |
b15d97d7 JH |
1249 | /* Deregister an interface. */ |
1250 | void gb_interface_del(struct gb_interface *intf) | |
629c0d00 JH |
1251 | { |
1252 | if (device_is_registered(&intf->dev)) { | |
cb4c8441 AE |
1253 | trace_gb_interface_del(intf); |
1254 | ||
629c0d00 JH |
1255 | device_del(&intf->dev); |
1256 | dev_info(&intf->dev, "Interface removed\n"); | |
1257 | } | |
b15d97d7 | 1258 | } |
629c0d00 | 1259 | |
b15d97d7 JH |
1260 | void gb_interface_put(struct gb_interface *intf) |
1261 | { | |
629c0d00 JH |
1262 | put_device(&intf->dev); |
1263 | } |