]>
Commit | Line | Data |
---|---|---|
acd6199f WW |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * Intel La Jolla Cove Adapter USB driver | |
4 | * | |
5 | * Copyright (c) 2023, Intel Corporation. | |
6 | */ | |
7 | ||
8 | #include <linux/acpi.h> | |
9 | #include <linux/auxiliary_bus.h> | |
10 | #include <linux/dev_printk.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/mod_devicetable.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/mutex.h> | |
15 | #include <linux/slab.h> | |
16 | #include <linux/spinlock.h> | |
17 | #include <linux/types.h> | |
18 | #include <linux/usb.h> | |
19 | #include <linux/usb/ljca.h> | |
20 | ||
21 | #include <asm/unaligned.h> | |
22 | ||
23 | /* command flags */ | |
24 | #define LJCA_ACK_FLAG BIT(0) | |
25 | #define LJCA_RESP_FLAG BIT(1) | |
26 | #define LJCA_CMPL_FLAG BIT(2) | |
27 | ||
28 | #define LJCA_MAX_PACKET_SIZE 64u | |
29 | #define LJCA_MAX_PAYLOAD_SIZE \ | |
30 | (LJCA_MAX_PACKET_SIZE - sizeof(struct ljca_msg)) | |
31 | ||
32 | #define LJCA_WRITE_TIMEOUT_MS 200 | |
33 | #define LJCA_WRITE_ACK_TIMEOUT_MS 500 | |
34 | #define LJCA_ENUM_CLIENT_TIMEOUT_MS 20 | |
35 | ||
36 | /* ljca client type */ | |
37 | enum ljca_client_type { | |
38 | LJCA_CLIENT_MNG = 1, | |
39 | LJCA_CLIENT_GPIO = 3, | |
40 | LJCA_CLIENT_I2C = 4, | |
41 | LJCA_CLIENT_SPI = 5, | |
42 | }; | |
43 | ||
44 | /* MNG client commands */ | |
45 | enum ljca_mng_cmd { | |
46 | LJCA_MNG_RESET = 2, | |
47 | LJCA_MNG_ENUM_GPIO = 4, | |
48 | LJCA_MNG_ENUM_I2C = 5, | |
49 | LJCA_MNG_ENUM_SPI = 8, | |
50 | }; | |
51 | ||
52 | /* ljca client acpi _ADR */ | |
53 | enum ljca_client_acpi_adr { | |
54 | LJCA_GPIO_ACPI_ADR, | |
55 | LJCA_I2C1_ACPI_ADR, | |
56 | LJCA_I2C2_ACPI_ADR, | |
57 | LJCA_SPI1_ACPI_ADR, | |
58 | LJCA_SPI2_ACPI_ADR, | |
59 | LJCA_CLIENT_ACPI_ADR_MAX, | |
60 | }; | |
61 | ||
62 | /* ljca cmd message structure */ | |
63 | struct ljca_msg { | |
64 | u8 type; | |
65 | u8 cmd; | |
66 | u8 flags; | |
67 | u8 len; | |
68 | u8 data[] __counted_by(len); | |
69 | } __packed; | |
70 | ||
71 | struct ljca_i2c_ctr_info { | |
72 | u8 id; | |
73 | u8 capacity; | |
74 | u8 intr_pin; | |
75 | } __packed; | |
76 | ||
77 | struct ljca_i2c_descriptor { | |
78 | u8 num; | |
79 | struct ljca_i2c_ctr_info info[] __counted_by(num); | |
80 | } __packed; | |
81 | ||
82 | struct ljca_spi_ctr_info { | |
83 | u8 id; | |
84 | u8 capacity; | |
85 | u8 intr_pin; | |
86 | } __packed; | |
87 | ||
88 | struct ljca_spi_descriptor { | |
89 | u8 num; | |
90 | struct ljca_spi_ctr_info info[] __counted_by(num); | |
91 | } __packed; | |
92 | ||
93 | struct ljca_bank_descriptor { | |
94 | u8 bank_id; | |
95 | u8 pin_num; | |
96 | ||
97 | /* 1 bit for each gpio, 1 means valid */ | |
98 | __le32 valid_pins; | |
99 | } __packed; | |
100 | ||
101 | struct ljca_gpio_descriptor { | |
102 | u8 pins_per_bank; | |
103 | u8 bank_num; | |
104 | struct ljca_bank_descriptor bank_desc[] __counted_by(bank_num); | |
105 | } __packed; | |
106 | ||
107 | /** | |
108 | * struct ljca_adapter - represent a ljca adapter | |
109 | * | |
110 | * @intf: the usb interface for this ljca adapter | |
111 | * @usb_dev: the usb device for this ljca adapter | |
112 | * @dev: the specific device info of the usb interface | |
113 | * @rx_pipe: bulk in pipe for receive data from firmware | |
114 | * @tx_pipe: bulk out pipe for send data to firmware | |
115 | * @rx_urb: urb used for the bulk in pipe | |
116 | * @rx_buf: buffer used to receive command response and event | |
117 | * @rx_len: length of rx buffer | |
118 | * @ex_buf: external buffer to save command response | |
119 | * @ex_buf_len: length of external buffer | |
120 | * @actual_length: actual length of data copied to external buffer | |
121 | * @tx_buf: buffer used to download command to firmware | |
122 | * @tx_buf_len: length of tx buffer | |
123 | * @lock: spinlock to protect tx_buf and ex_buf | |
124 | * @cmd_completion: completion object as the command receives ack | |
125 | * @mutex: mutex to avoid command download concurrently | |
126 | * @client_list: client device list | |
127 | * @disconnect: usb disconnect ongoing or not | |
128 | * @reset_id: used to reset firmware | |
129 | */ | |
130 | struct ljca_adapter { | |
131 | struct usb_interface *intf; | |
132 | struct usb_device *usb_dev; | |
133 | struct device *dev; | |
134 | ||
135 | unsigned int rx_pipe; | |
136 | unsigned int tx_pipe; | |
137 | ||
138 | struct urb *rx_urb; | |
139 | void *rx_buf; | |
140 | unsigned int rx_len; | |
141 | ||
142 | u8 *ex_buf; | |
143 | u8 ex_buf_len; | |
144 | u8 actual_length; | |
145 | ||
146 | void *tx_buf; | |
147 | u8 tx_buf_len; | |
148 | ||
149 | spinlock_t lock; | |
150 | ||
151 | struct completion cmd_completion; | |
152 | struct mutex mutex; | |
153 | ||
154 | struct list_head client_list; | |
155 | ||
156 | bool disconnect; | |
157 | ||
158 | u32 reset_id; | |
159 | }; | |
160 | ||
161 | struct ljca_match_ids_walk_data { | |
162 | const struct acpi_device_id *ids; | |
163 | const char *uid; | |
164 | struct acpi_device *adev; | |
165 | }; | |
166 | ||
167 | static const struct acpi_device_id ljca_gpio_hids[] = { | |
168 | { "INTC1074" }, | |
169 | { "INTC1096" }, | |
170 | { "INTC100B" }, | |
171 | { "INTC10D1" }, | |
172 | {}, | |
173 | }; | |
174 | ||
175 | static const struct acpi_device_id ljca_i2c_hids[] = { | |
176 | { "INTC1075" }, | |
177 | { "INTC1097" }, | |
178 | { "INTC100C" }, | |
179 | { "INTC10D2" }, | |
180 | {}, | |
181 | }; | |
182 | ||
183 | static const struct acpi_device_id ljca_spi_hids[] = { | |
184 | { "INTC1091" }, | |
185 | { "INTC1098" }, | |
186 | { "INTC100D" }, | |
187 | { "INTC10D3" }, | |
188 | {}, | |
189 | }; | |
190 | ||
191 | static void ljca_handle_event(struct ljca_adapter *adap, | |
192 | struct ljca_msg *header) | |
193 | { | |
194 | struct ljca_client *client; | |
195 | ||
196 | list_for_each_entry(client, &adap->client_list, link) { | |
197 | /* | |
198 | * Currently only GPIO register event callback, but | |
199 | * firmware message structure should include id when | |
200 | * multiple same type clients register event callback. | |
201 | */ | |
202 | if (client->type == header->type) { | |
203 | unsigned long flags; | |
204 | ||
205 | spin_lock_irqsave(&client->event_cb_lock, flags); | |
206 | client->event_cb(client->context, header->cmd, | |
207 | header->data, header->len); | |
208 | spin_unlock_irqrestore(&client->event_cb_lock, flags); | |
209 | ||
210 | break; | |
211 | } | |
212 | } | |
213 | } | |
214 | ||
215 | /* process command ack and received data if available */ | |
216 | static void ljca_handle_cmd_ack(struct ljca_adapter *adap, struct ljca_msg *header) | |
217 | { | |
218 | struct ljca_msg *tx_header = adap->tx_buf; | |
219 | u8 ibuf_len, actual_len = 0; | |
220 | unsigned long flags; | |
221 | u8 *ibuf; | |
222 | ||
223 | spin_lock_irqsave(&adap->lock, flags); | |
224 | ||
225 | if (tx_header->type != header->type || tx_header->cmd != header->cmd) { | |
226 | spin_unlock_irqrestore(&adap->lock, flags); | |
227 | dev_err(adap->dev, "cmd ack mismatch error\n"); | |
228 | return; | |
229 | } | |
230 | ||
231 | ibuf_len = adap->ex_buf_len; | |
232 | ibuf = adap->ex_buf; | |
233 | ||
234 | if (ibuf && ibuf_len) { | |
235 | actual_len = min(header->len, ibuf_len); | |
236 | ||
237 | /* copy received data to external buffer */ | |
238 | memcpy(ibuf, header->data, actual_len); | |
239 | } | |
240 | /* update copied data length */ | |
241 | adap->actual_length = actual_len; | |
242 | ||
243 | spin_unlock_irqrestore(&adap->lock, flags); | |
244 | ||
245 | complete(&adap->cmd_completion); | |
246 | } | |
247 | ||
248 | static void ljca_recv(struct urb *urb) | |
249 | { | |
250 | struct ljca_msg *header = urb->transfer_buffer; | |
251 | struct ljca_adapter *adap = urb->context; | |
252 | int ret; | |
253 | ||
254 | switch (urb->status) { | |
255 | case 0: | |
256 | /* success */ | |
257 | break; | |
258 | case -ENOENT: | |
259 | /* | |
260 | * directly complete the possible ongoing transfer | |
261 | * during disconnect | |
262 | */ | |
263 | if (adap->disconnect) | |
264 | complete(&adap->cmd_completion); | |
265 | return; | |
266 | case -ECONNRESET: | |
267 | case -ESHUTDOWN: | |
268 | case -EPIPE: | |
269 | /* rx urb is terminated */ | |
270 | dev_dbg(adap->dev, "rx urb terminated with status: %d\n", | |
271 | urb->status); | |
272 | return; | |
273 | default: | |
274 | dev_dbg(adap->dev, "rx urb error: %d\n", urb->status); | |
275 | goto resubmit; | |
276 | } | |
277 | ||
278 | if (header->len + sizeof(*header) != urb->actual_length) | |
279 | goto resubmit; | |
280 | ||
281 | if (header->flags & LJCA_ACK_FLAG) | |
282 | ljca_handle_cmd_ack(adap, header); | |
283 | else | |
284 | ljca_handle_event(adap, header); | |
285 | ||
286 | resubmit: | |
287 | ret = usb_submit_urb(urb, GFP_ATOMIC); | |
288 | if (ret && ret != -EPERM) | |
289 | dev_err(adap->dev, "resubmit rx urb error %d\n", ret); | |
290 | } | |
291 | ||
292 | static int ljca_send(struct ljca_adapter *adap, u8 type, u8 cmd, | |
293 | const u8 *obuf, u8 obuf_len, u8 *ibuf, u8 ibuf_len, | |
294 | bool ack, unsigned long timeout) | |
295 | { | |
296 | unsigned int msg_len = sizeof(struct ljca_msg) + obuf_len; | |
297 | struct ljca_msg *header = adap->tx_buf; | |
298 | unsigned int transferred; | |
299 | unsigned long flags; | |
300 | int ret; | |
301 | ||
302 | if (adap->disconnect) | |
303 | return -ENODEV; | |
304 | ||
305 | if (msg_len > adap->tx_buf_len) | |
306 | return -EINVAL; | |
307 | ||
308 | mutex_lock(&adap->mutex); | |
309 | ||
310 | spin_lock_irqsave(&adap->lock, flags); | |
311 | ||
312 | header->type = type; | |
313 | header->cmd = cmd; | |
314 | header->len = obuf_len; | |
315 | if (obuf) | |
316 | memcpy(header->data, obuf, obuf_len); | |
317 | ||
318 | header->flags = LJCA_CMPL_FLAG | (ack ? LJCA_ACK_FLAG : 0); | |
319 | ||
320 | adap->ex_buf = ibuf; | |
321 | adap->ex_buf_len = ibuf_len; | |
322 | adap->actual_length = 0; | |
323 | ||
324 | spin_unlock_irqrestore(&adap->lock, flags); | |
325 | ||
326 | reinit_completion(&adap->cmd_completion); | |
327 | ||
328 | ret = usb_autopm_get_interface(adap->intf); | |
329 | if (ret < 0) | |
330 | goto out; | |
331 | ||
332 | ret = usb_bulk_msg(adap->usb_dev, adap->tx_pipe, header, | |
333 | msg_len, &transferred, LJCA_WRITE_TIMEOUT_MS); | |
334 | ||
335 | usb_autopm_put_interface(adap->intf); | |
336 | ||
337 | if (ret < 0) | |
338 | goto out; | |
339 | if (transferred != msg_len) { | |
340 | ret = -EIO; | |
341 | goto out; | |
342 | } | |
343 | ||
344 | if (ack) { | |
345 | ret = wait_for_completion_timeout(&adap->cmd_completion, | |
346 | timeout); | |
347 | if (!ret) { | |
348 | ret = -ETIMEDOUT; | |
349 | goto out; | |
350 | } | |
351 | } | |
352 | ret = adap->actual_length; | |
353 | ||
354 | out: | |
355 | spin_lock_irqsave(&adap->lock, flags); | |
356 | adap->ex_buf = NULL; | |
357 | adap->ex_buf_len = 0; | |
358 | ||
359 | memset(header, 0, sizeof(*header)); | |
360 | spin_unlock_irqrestore(&adap->lock, flags); | |
361 | ||
362 | mutex_unlock(&adap->mutex); | |
363 | ||
364 | return ret; | |
365 | } | |
366 | ||
367 | int ljca_transfer(struct ljca_client *client, u8 cmd, const u8 *obuf, | |
368 | u8 obuf_len, u8 *ibuf, u8 ibuf_len) | |
369 | { | |
370 | return ljca_send(client->adapter, client->type, cmd, | |
371 | obuf, obuf_len, ibuf, ibuf_len, true, | |
372 | LJCA_WRITE_ACK_TIMEOUT_MS); | |
373 | } | |
374 | EXPORT_SYMBOL_NS_GPL(ljca_transfer, LJCA); | |
375 | ||
376 | int ljca_transfer_noack(struct ljca_client *client, u8 cmd, const u8 *obuf, | |
377 | u8 obuf_len) | |
378 | { | |
379 | return ljca_send(client->adapter, client->type, cmd, obuf, | |
380 | obuf_len, NULL, 0, false, LJCA_WRITE_ACK_TIMEOUT_MS); | |
381 | } | |
382 | EXPORT_SYMBOL_NS_GPL(ljca_transfer_noack, LJCA); | |
383 | ||
384 | int ljca_register_event_cb(struct ljca_client *client, ljca_event_cb_t event_cb, | |
385 | void *context) | |
386 | { | |
387 | unsigned long flags; | |
388 | ||
389 | if (!event_cb) | |
390 | return -EINVAL; | |
391 | ||
392 | spin_lock_irqsave(&client->event_cb_lock, flags); | |
393 | ||
394 | if (client->event_cb) { | |
395 | spin_unlock_irqrestore(&client->event_cb_lock, flags); | |
396 | return -EALREADY; | |
397 | } | |
398 | ||
399 | client->event_cb = event_cb; | |
400 | client->context = context; | |
401 | ||
402 | spin_unlock_irqrestore(&client->event_cb_lock, flags); | |
403 | ||
404 | return 0; | |
405 | } | |
406 | EXPORT_SYMBOL_NS_GPL(ljca_register_event_cb, LJCA); | |
407 | ||
408 | void ljca_unregister_event_cb(struct ljca_client *client) | |
409 | { | |
410 | unsigned long flags; | |
411 | ||
412 | spin_lock_irqsave(&client->event_cb_lock, flags); | |
413 | ||
414 | client->event_cb = NULL; | |
415 | client->context = NULL; | |
416 | ||
417 | spin_unlock_irqrestore(&client->event_cb_lock, flags); | |
418 | } | |
419 | EXPORT_SYMBOL_NS_GPL(ljca_unregister_event_cb, LJCA); | |
420 | ||
421 | static int ljca_match_device_ids(struct acpi_device *adev, void *data) | |
422 | { | |
423 | struct ljca_match_ids_walk_data *wd = data; | |
424 | const char *uid = acpi_device_uid(adev); | |
425 | ||
426 | if (acpi_match_device_ids(adev, wd->ids)) | |
427 | return 0; | |
428 | ||
429 | if (!wd->uid) | |
430 | goto match; | |
431 | ||
432 | if (!uid) | |
433 | /* | |
434 | * Some DSDTs have only one ACPI companion for the two I2C | |
435 | * controllers and they don't set a UID at all (e.g. Dell | |
436 | * Latitude 9420). On these platforms only the first I2C | |
437 | * controller is used, so if a HID match has no UID we use | |
438 | * "0" as the UID and assign ACPI companion to the first | |
439 | * I2C controller. | |
440 | */ | |
441 | uid = "0"; | |
442 | else | |
443 | uid = strchr(uid, wd->uid[0]); | |
444 | ||
445 | if (!uid || strcmp(uid, wd->uid)) | |
446 | return 0; | |
447 | ||
448 | match: | |
449 | wd->adev = adev; | |
450 | ||
451 | return 1; | |
452 | } | |
453 | ||
454 | /* bind auxiliary device to acpi device */ | |
455 | static void ljca_auxdev_acpi_bind(struct ljca_adapter *adap, | |
456 | struct auxiliary_device *auxdev, | |
457 | u64 adr, u8 id) | |
458 | { | |
459 | struct ljca_match_ids_walk_data wd = { 0 }; | |
acd6199f | 460 | struct device *dev = adap->dev; |
30ce1c03 | 461 | struct acpi_device *parent; |
acd6199f WW |
462 | char uid[4]; |
463 | ||
464 | parent = ACPI_COMPANION(dev); | |
465 | if (!parent) | |
466 | return; | |
467 | ||
468 | /* | |
30ce1c03 | 469 | * Currently LJCA hw doesn't use _ADR instead the shipped |
acd6199f WW |
470 | * platforms use _HID to distinguish children devices. |
471 | */ | |
472 | switch (adr) { | |
473 | case LJCA_GPIO_ACPI_ADR: | |
474 | wd.ids = ljca_gpio_hids; | |
475 | break; | |
476 | case LJCA_I2C1_ACPI_ADR: | |
477 | case LJCA_I2C2_ACPI_ADR: | |
478 | snprintf(uid, sizeof(uid), "%d", id); | |
479 | wd.uid = uid; | |
480 | wd.ids = ljca_i2c_hids; | |
481 | break; | |
482 | case LJCA_SPI1_ACPI_ADR: | |
483 | case LJCA_SPI2_ACPI_ADR: | |
484 | wd.ids = ljca_spi_hids; | |
485 | break; | |
486 | default: | |
487 | dev_warn(dev, "unsupported _ADR\n"); | |
488 | return; | |
489 | } | |
490 | ||
491 | acpi_dev_for_each_child(parent, ljca_match_device_ids, &wd); | |
492 | if (wd.adev) { | |
493 | ACPI_COMPANION_SET(&auxdev->dev, wd.adev); | |
494 | return; | |
495 | } | |
496 | ||
497 | parent = ACPI_COMPANION(dev->parent->parent); | |
498 | if (!parent) | |
499 | return; | |
500 | ||
501 | acpi_dev_for_each_child(parent, ljca_match_device_ids, &wd); | |
502 | if (wd.adev) | |
503 | ACPI_COMPANION_SET(&auxdev->dev, wd.adev); | |
504 | } | |
505 | ||
506 | static void ljca_auxdev_release(struct device *dev) | |
507 | { | |
508 | struct auxiliary_device *auxdev = to_auxiliary_dev(dev); | |
509 | ||
510 | kfree(auxdev->dev.platform_data); | |
511 | } | |
512 | ||
513 | static int ljca_new_client_device(struct ljca_adapter *adap, u8 type, u8 id, | |
514 | char *name, void *data, u64 adr) | |
515 | { | |
516 | struct auxiliary_device *auxdev; | |
517 | struct ljca_client *client; | |
518 | int ret; | |
519 | ||
520 | client = kzalloc(sizeof *client, GFP_KERNEL); | |
521 | if (!client) | |
522 | return -ENOMEM; | |
523 | ||
524 | client->type = type; | |
525 | client->id = id; | |
526 | client->adapter = adap; | |
527 | spin_lock_init(&client->event_cb_lock); | |
528 | ||
529 | auxdev = &client->auxdev; | |
530 | auxdev->name = name; | |
531 | auxdev->id = id; | |
532 | ||
533 | auxdev->dev.parent = adap->dev; | |
534 | auxdev->dev.platform_data = data; | |
535 | auxdev->dev.release = ljca_auxdev_release; | |
536 | ||
537 | ret = auxiliary_device_init(auxdev); | |
538 | if (ret) | |
539 | goto err_free; | |
540 | ||
541 | ljca_auxdev_acpi_bind(adap, auxdev, adr, id); | |
542 | ||
543 | ret = auxiliary_device_add(auxdev); | |
544 | if (ret) | |
545 | goto err_uninit; | |
546 | ||
547 | list_add_tail(&client->link, &adap->client_list); | |
548 | ||
549 | return 0; | |
550 | ||
551 | err_uninit: | |
552 | auxiliary_device_uninit(auxdev); | |
553 | ||
554 | err_free: | |
555 | kfree(client); | |
556 | ||
557 | return ret; | |
558 | } | |
559 | ||
560 | static int ljca_enumerate_gpio(struct ljca_adapter *adap) | |
561 | { | |
562 | u32 valid_pin[LJCA_MAX_GPIO_NUM / BITS_PER_TYPE(u32)]; | |
563 | struct ljca_gpio_descriptor *desc; | |
564 | struct ljca_gpio_info *gpio_info; | |
565 | u8 buf[LJCA_MAX_PAYLOAD_SIZE]; | |
566 | int ret, gpio_num; | |
567 | unsigned int i; | |
568 | ||
569 | ret = ljca_send(adap, LJCA_CLIENT_MNG, LJCA_MNG_ENUM_GPIO, NULL, 0, buf, | |
570 | sizeof(buf), true, LJCA_ENUM_CLIENT_TIMEOUT_MS); | |
571 | if (ret < 0) | |
572 | return ret; | |
573 | ||
574 | /* check firmware response */ | |
575 | desc = (struct ljca_gpio_descriptor *)buf; | |
576 | if (ret != struct_size(desc, bank_desc, desc->bank_num)) | |
577 | return -EINVAL; | |
578 | ||
579 | gpio_num = desc->pins_per_bank * desc->bank_num; | |
580 | if (gpio_num > LJCA_MAX_GPIO_NUM) | |
581 | return -EINVAL; | |
582 | ||
583 | /* construct platform data */ | |
584 | gpio_info = kzalloc(sizeof *gpio_info, GFP_KERNEL); | |
585 | if (!gpio_info) | |
586 | return -ENOMEM; | |
587 | gpio_info->num = gpio_num; | |
588 | ||
589 | for (i = 0; i < desc->bank_num; i++) | |
590 | valid_pin[i] = get_unaligned_le32(&desc->bank_desc[i].valid_pins); | |
591 | bitmap_from_arr32(gpio_info->valid_pin_map, valid_pin, gpio_num); | |
592 | ||
593 | ret = ljca_new_client_device(adap, LJCA_CLIENT_GPIO, 0, "ljca-gpio", | |
594 | gpio_info, LJCA_GPIO_ACPI_ADR); | |
595 | if (ret) | |
596 | kfree(gpio_info); | |
597 | ||
598 | return ret; | |
599 | } | |
600 | ||
601 | static int ljca_enumerate_i2c(struct ljca_adapter *adap) | |
602 | { | |
603 | struct ljca_i2c_descriptor *desc; | |
604 | struct ljca_i2c_info *i2c_info; | |
605 | u8 buf[LJCA_MAX_PAYLOAD_SIZE]; | |
606 | unsigned int i; | |
607 | int ret; | |
608 | ||
609 | ret = ljca_send(adap, LJCA_CLIENT_MNG, LJCA_MNG_ENUM_I2C, NULL, 0, buf, | |
610 | sizeof(buf), true, LJCA_ENUM_CLIENT_TIMEOUT_MS); | |
611 | if (ret < 0) | |
612 | return ret; | |
613 | ||
614 | /* check firmware response */ | |
615 | desc = (struct ljca_i2c_descriptor *)buf; | |
616 | if (ret != struct_size(desc, info, desc->num)) | |
617 | return -EINVAL; | |
618 | ||
619 | for (i = 0; i < desc->num; i++) { | |
620 | /* construct platform data */ | |
621 | i2c_info = kzalloc(sizeof *i2c_info, GFP_KERNEL); | |
622 | if (!i2c_info) | |
623 | return -ENOMEM; | |
624 | ||
625 | i2c_info->id = desc->info[i].id; | |
626 | i2c_info->capacity = desc->info[i].capacity; | |
627 | i2c_info->intr_pin = desc->info[i].intr_pin; | |
628 | ||
629 | ret = ljca_new_client_device(adap, LJCA_CLIENT_I2C, i, | |
630 | "ljca-i2c", i2c_info, | |
631 | LJCA_I2C1_ACPI_ADR + i); | |
632 | if (ret) { | |
633 | kfree(i2c_info); | |
634 | return ret; | |
635 | } | |
636 | } | |
637 | ||
638 | return 0; | |
639 | } | |
640 | ||
641 | static int ljca_enumerate_spi(struct ljca_adapter *adap) | |
642 | { | |
643 | struct ljca_spi_descriptor *desc; | |
644 | struct ljca_spi_info *spi_info; | |
645 | u8 buf[LJCA_MAX_PAYLOAD_SIZE]; | |
646 | unsigned int i; | |
647 | int ret; | |
648 | ||
372ee6a3 | 649 | /* Not all LJCA chips implement SPI, a timeout reading the descriptors is normal */ |
acd6199f WW |
650 | ret = ljca_send(adap, LJCA_CLIENT_MNG, LJCA_MNG_ENUM_SPI, NULL, 0, buf, |
651 | sizeof(buf), true, LJCA_ENUM_CLIENT_TIMEOUT_MS); | |
652 | if (ret < 0) | |
372ee6a3 | 653 | return (ret == -ETIMEDOUT) ? 0 : ret; |
acd6199f WW |
654 | |
655 | /* check firmware response */ | |
656 | desc = (struct ljca_spi_descriptor *)buf; | |
657 | if (ret != struct_size(desc, info, desc->num)) | |
658 | return -EINVAL; | |
659 | ||
660 | for (i = 0; i < desc->num; i++) { | |
661 | /* construct platform data */ | |
662 | spi_info = kzalloc(sizeof *spi_info, GFP_KERNEL); | |
663 | if (!spi_info) | |
664 | return -ENOMEM; | |
665 | ||
666 | spi_info->id = desc->info[i].id; | |
667 | spi_info->capacity = desc->info[i].capacity; | |
668 | ||
669 | ret = ljca_new_client_device(adap, LJCA_CLIENT_SPI, i, | |
670 | "ljca-spi", spi_info, | |
671 | LJCA_SPI1_ACPI_ADR + i); | |
672 | if (ret) { | |
673 | kfree(spi_info); | |
674 | return ret; | |
675 | } | |
676 | } | |
677 | ||
678 | return 0; | |
679 | } | |
680 | ||
681 | static int ljca_reset_handshake(struct ljca_adapter *adap) | |
682 | { | |
683 | __le32 reset_id = cpu_to_le32(adap->reset_id); | |
684 | __le32 reset_id_ret = 0; | |
685 | int ret; | |
686 | ||
687 | adap->reset_id++; | |
688 | ||
689 | ret = ljca_send(adap, LJCA_CLIENT_MNG, LJCA_MNG_RESET, (u8 *)&reset_id, | |
690 | sizeof(__le32), (u8 *)&reset_id_ret, sizeof(__le32), | |
691 | true, LJCA_WRITE_ACK_TIMEOUT_MS); | |
692 | if (ret < 0) | |
693 | return ret; | |
694 | ||
695 | if (reset_id_ret != reset_id) | |
696 | return -EINVAL; | |
697 | ||
698 | return 0; | |
699 | } | |
700 | ||
701 | static int ljca_enumerate_clients(struct ljca_adapter *adap) | |
702 | { | |
703 | struct ljca_client *client, *next; | |
704 | int ret; | |
705 | ||
706 | ret = ljca_reset_handshake(adap); | |
707 | if (ret) | |
708 | goto err_kill; | |
709 | ||
710 | ret = ljca_enumerate_gpio(adap); | |
711 | if (ret) { | |
712 | dev_err(adap->dev, "enumerate GPIO error\n"); | |
713 | goto err_kill; | |
714 | } | |
715 | ||
716 | ret = ljca_enumerate_i2c(adap); | |
717 | if (ret) { | |
718 | dev_err(adap->dev, "enumerate I2C error\n"); | |
719 | goto err_kill; | |
720 | } | |
721 | ||
722 | ret = ljca_enumerate_spi(adap); | |
723 | if (ret) { | |
724 | dev_err(adap->dev, "enumerate SPI error\n"); | |
725 | goto err_kill; | |
726 | } | |
727 | ||
728 | return 0; | |
729 | ||
730 | err_kill: | |
731 | adap->disconnect = true; | |
732 | ||
733 | usb_kill_urb(adap->rx_urb); | |
734 | ||
735 | list_for_each_entry_safe_reverse(client, next, &adap->client_list, link) { | |
736 | auxiliary_device_delete(&client->auxdev); | |
737 | auxiliary_device_uninit(&client->auxdev); | |
738 | ||
739 | list_del_init(&client->link); | |
740 | kfree(client); | |
741 | } | |
742 | ||
743 | return ret; | |
744 | } | |
745 | ||
746 | static int ljca_probe(struct usb_interface *interface, | |
747 | const struct usb_device_id *id) | |
748 | { | |
749 | struct usb_device *usb_dev = interface_to_usbdev(interface); | |
750 | struct usb_host_interface *alt = interface->cur_altsetting; | |
751 | struct usb_endpoint_descriptor *ep_in, *ep_out; | |
752 | struct device *dev = &interface->dev; | |
753 | struct ljca_adapter *adap; | |
754 | int ret; | |
755 | ||
756 | adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL); | |
757 | if (!adap) | |
758 | return -ENOMEM; | |
759 | ||
760 | /* separate tx buffer allocation for alignment */ | |
761 | adap->tx_buf = devm_kzalloc(dev, LJCA_MAX_PACKET_SIZE, GFP_KERNEL); | |
762 | if (!adap->tx_buf) | |
763 | return -ENOMEM; | |
764 | adap->tx_buf_len = LJCA_MAX_PACKET_SIZE; | |
765 | ||
766 | mutex_init(&adap->mutex); | |
767 | spin_lock_init(&adap->lock); | |
768 | init_completion(&adap->cmd_completion); | |
769 | INIT_LIST_HEAD(&adap->client_list); | |
770 | ||
771 | adap->intf = usb_get_intf(interface); | |
772 | adap->usb_dev = usb_dev; | |
773 | adap->dev = dev; | |
774 | ||
775 | /* | |
776 | * find the first bulk in and out endpoints. | |
777 | * ignore any others. | |
778 | */ | |
779 | ret = usb_find_common_endpoints(alt, &ep_in, &ep_out, NULL, NULL); | |
780 | if (ret) { | |
781 | dev_err(dev, "bulk endpoints not found\n"); | |
782 | goto err_put; | |
783 | } | |
784 | adap->rx_pipe = usb_rcvbulkpipe(usb_dev, usb_endpoint_num(ep_in)); | |
785 | adap->tx_pipe = usb_sndbulkpipe(usb_dev, usb_endpoint_num(ep_out)); | |
786 | ||
787 | /* setup rx buffer */ | |
788 | adap->rx_len = usb_endpoint_maxp(ep_in); | |
789 | adap->rx_buf = devm_kzalloc(dev, adap->rx_len, GFP_KERNEL); | |
790 | if (!adap->rx_buf) { | |
791 | ret = -ENOMEM; | |
792 | goto err_put; | |
793 | } | |
794 | ||
795 | /* alloc rx urb */ | |
796 | adap->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | |
797 | if (!adap->rx_urb) { | |
798 | ret = -ENOMEM; | |
799 | goto err_put; | |
800 | } | |
801 | usb_fill_bulk_urb(adap->rx_urb, usb_dev, adap->rx_pipe, | |
802 | adap->rx_buf, adap->rx_len, ljca_recv, adap); | |
803 | ||
804 | usb_set_intfdata(interface, adap); | |
805 | ||
806 | /* submit rx urb before enumerate clients */ | |
807 | ret = usb_submit_urb(adap->rx_urb, GFP_KERNEL); | |
808 | if (ret) { | |
809 | dev_err(dev, "submit rx urb failed: %d\n", ret); | |
810 | goto err_free; | |
811 | } | |
812 | ||
813 | ret = ljca_enumerate_clients(adap); | |
814 | if (ret) | |
815 | goto err_free; | |
816 | ||
817 | usb_enable_autosuspend(usb_dev); | |
818 | ||
819 | return 0; | |
820 | ||
821 | err_free: | |
822 | usb_free_urb(adap->rx_urb); | |
823 | ||
824 | err_put: | |
825 | usb_put_intf(adap->intf); | |
826 | ||
827 | mutex_destroy(&adap->mutex); | |
828 | ||
829 | return ret; | |
830 | } | |
831 | ||
832 | static void ljca_disconnect(struct usb_interface *interface) | |
833 | { | |
834 | struct ljca_adapter *adap = usb_get_intfdata(interface); | |
835 | struct ljca_client *client, *next; | |
836 | ||
837 | adap->disconnect = true; | |
838 | ||
839 | usb_kill_urb(adap->rx_urb); | |
840 | ||
841 | list_for_each_entry_safe_reverse(client, next, &adap->client_list, link) { | |
842 | auxiliary_device_delete(&client->auxdev); | |
843 | auxiliary_device_uninit(&client->auxdev); | |
844 | ||
845 | list_del_init(&client->link); | |
846 | kfree(client); | |
847 | } | |
848 | ||
849 | usb_free_urb(adap->rx_urb); | |
850 | ||
851 | usb_put_intf(adap->intf); | |
852 | ||
853 | mutex_destroy(&adap->mutex); | |
854 | } | |
855 | ||
856 | static int ljca_suspend(struct usb_interface *interface, pm_message_t message) | |
857 | { | |
858 | struct ljca_adapter *adap = usb_get_intfdata(interface); | |
859 | ||
860 | usb_kill_urb(adap->rx_urb); | |
861 | ||
862 | return 0; | |
863 | } | |
864 | ||
865 | static int ljca_resume(struct usb_interface *interface) | |
866 | { | |
867 | struct ljca_adapter *adap = usb_get_intfdata(interface); | |
868 | ||
869 | return usb_submit_urb(adap->rx_urb, GFP_KERNEL); | |
870 | } | |
871 | ||
872 | static const struct usb_device_id ljca_table[] = { | |
873 | { USB_DEVICE(0x8086, 0x0b63) }, | |
874 | { /* sentinel */ } | |
875 | }; | |
876 | MODULE_DEVICE_TABLE(usb, ljca_table); | |
877 | ||
878 | static struct usb_driver ljca_driver = { | |
879 | .name = "ljca", | |
880 | .id_table = ljca_table, | |
881 | .probe = ljca_probe, | |
882 | .disconnect = ljca_disconnect, | |
883 | .suspend = ljca_suspend, | |
884 | .resume = ljca_resume, | |
885 | .supports_autosuspend = 1, | |
886 | }; | |
887 | module_usb_driver(ljca_driver); | |
888 | ||
889 | MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>"); | |
890 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); | |
891 | MODULE_AUTHOR("Lixu Zhang <lixu.zhang@intel.com>"); | |
892 | MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB driver"); | |
893 | MODULE_LICENSE("GPL"); |