.. | .. |
---|
15 | 15 | #include <linux/of_device.h> |
---|
16 | 16 | #include <linux/pm_domain.h> |
---|
17 | 17 | #include <linux/pm_runtime.h> |
---|
| 18 | +#include <linux/sched.h> |
---|
18 | 19 | #include <linux/serdev.h> |
---|
19 | 20 | #include <linux/slab.h> |
---|
| 21 | +#include <linux/platform_data/x86/apple.h> |
---|
20 | 22 | |
---|
21 | 23 | static bool is_registered; |
---|
22 | 24 | static DEFINE_IDA(ctrl_ida); |
---|
.. | .. |
---|
136 | 138 | |
---|
137 | 139 | err = device_add(&serdev->dev); |
---|
138 | 140 | if (err < 0) { |
---|
139 | | - dev_err(&serdev->dev, "Can't add %s, status %d\n", |
---|
140 | | - dev_name(&serdev->dev), err); |
---|
| 141 | + dev_err(&serdev->dev, "Can't add %s, status %pe\n", |
---|
| 142 | + dev_name(&serdev->dev), ERR_PTR(err)); |
---|
141 | 143 | goto err_clear_serdev; |
---|
142 | 144 | } |
---|
143 | 145 | |
---|
.. | .. |
---|
238 | 240 | } |
---|
239 | 241 | EXPORT_SYMBOL_GPL(serdev_device_write_wakeup); |
---|
240 | 242 | |
---|
| 243 | +/** |
---|
| 244 | + * serdev_device_write_buf() - write data asynchronously |
---|
| 245 | + * @serdev: serdev device |
---|
| 246 | + * @buf: data to be written |
---|
| 247 | + * @count: number of bytes to write |
---|
| 248 | + * |
---|
| 249 | + * Write data to the device asynchronously. |
---|
| 250 | + * |
---|
| 251 | + * Note that any accepted data has only been buffered by the controller; use |
---|
| 252 | + * serdev_device_wait_until_sent() to make sure the controller write buffer |
---|
| 253 | + * has actually been emptied. |
---|
| 254 | + * |
---|
| 255 | + * Return: The number of bytes written (less than count if not enough room in |
---|
| 256 | + * the write buffer), or a negative errno on errors. |
---|
| 257 | + */ |
---|
241 | 258 | int serdev_device_write_buf(struct serdev_device *serdev, |
---|
242 | 259 | const unsigned char *buf, size_t count) |
---|
243 | 260 | { |
---|
.. | .. |
---|
250 | 267 | } |
---|
251 | 268 | EXPORT_SYMBOL_GPL(serdev_device_write_buf); |
---|
252 | 269 | |
---|
| 270 | +/** |
---|
| 271 | + * serdev_device_write() - write data synchronously |
---|
| 272 | + * @serdev: serdev device |
---|
| 273 | + * @buf: data to be written |
---|
| 274 | + * @count: number of bytes to write |
---|
| 275 | + * @timeout: timeout in jiffies, or 0 to wait indefinitely |
---|
| 276 | + * |
---|
| 277 | + * Write data to the device synchronously by repeatedly calling |
---|
| 278 | + * serdev_device_write() until the controller has accepted all data (unless |
---|
| 279 | + * interrupted by a timeout or a signal). |
---|
| 280 | + * |
---|
| 281 | + * Note that any accepted data has only been buffered by the controller; use |
---|
| 282 | + * serdev_device_wait_until_sent() to make sure the controller write buffer |
---|
| 283 | + * has actually been emptied. |
---|
| 284 | + * |
---|
| 285 | + * Note that this function depends on serdev_device_write_wakeup() being |
---|
| 286 | + * called in the serdev driver write_wakeup() callback. |
---|
| 287 | + * |
---|
| 288 | + * Return: The number of bytes written (less than count if interrupted), |
---|
| 289 | + * -ETIMEDOUT or -ERESTARTSYS if interrupted before any bytes were written, or |
---|
| 290 | + * a negative errno on errors. |
---|
| 291 | + */ |
---|
253 | 292 | int serdev_device_write(struct serdev_device *serdev, |
---|
254 | 293 | const unsigned char *buf, size_t count, |
---|
255 | | - unsigned long timeout) |
---|
| 294 | + long timeout) |
---|
256 | 295 | { |
---|
257 | 296 | struct serdev_controller *ctrl = serdev->ctrl; |
---|
| 297 | + int written = 0; |
---|
258 | 298 | int ret; |
---|
259 | 299 | |
---|
260 | | - if (!ctrl || !ctrl->ops->write_buf || |
---|
261 | | - (timeout && !serdev->ops->write_wakeup)) |
---|
| 300 | + if (!ctrl || !ctrl->ops->write_buf || !serdev->ops->write_wakeup) |
---|
262 | 301 | return -EINVAL; |
---|
| 302 | + |
---|
| 303 | + if (timeout == 0) |
---|
| 304 | + timeout = MAX_SCHEDULE_TIMEOUT; |
---|
263 | 305 | |
---|
264 | 306 | mutex_lock(&serdev->write_lock); |
---|
265 | 307 | do { |
---|
.. | .. |
---|
269 | 311 | if (ret < 0) |
---|
270 | 312 | break; |
---|
271 | 313 | |
---|
| 314 | + written += ret; |
---|
272 | 315 | buf += ret; |
---|
273 | 316 | count -= ret; |
---|
274 | 317 | |
---|
275 | | - } while (count && |
---|
276 | | - (timeout = wait_for_completion_timeout(&serdev->write_comp, |
---|
277 | | - timeout))); |
---|
| 318 | + if (count == 0) |
---|
| 319 | + break; |
---|
| 320 | + |
---|
| 321 | + timeout = wait_for_completion_interruptible_timeout(&serdev->write_comp, |
---|
| 322 | + timeout); |
---|
| 323 | + } while (timeout > 0); |
---|
278 | 324 | mutex_unlock(&serdev->write_lock); |
---|
279 | | - return ret < 0 ? ret : (count ? -ETIMEDOUT : 0); |
---|
| 325 | + |
---|
| 326 | + if (ret < 0) |
---|
| 327 | + return ret; |
---|
| 328 | + |
---|
| 329 | + if (timeout <= 0 && written == 0) { |
---|
| 330 | + if (timeout == -ERESTARTSYS) |
---|
| 331 | + return -ERESTARTSYS; |
---|
| 332 | + else |
---|
| 333 | + return -ETIMEDOUT; |
---|
| 334 | + } |
---|
| 335 | + |
---|
| 336 | + return written; |
---|
280 | 337 | } |
---|
281 | 338 | EXPORT_SYMBOL_GPL(serdev_device_write); |
---|
282 | 339 | |
---|
.. | .. |
---|
506 | 563 | err = serdev_device_add(serdev); |
---|
507 | 564 | if (err) { |
---|
508 | 565 | dev_err(&serdev->dev, |
---|
509 | | - "failure adding device. status %d\n", err); |
---|
| 566 | + "failure adding device. status %pe\n", |
---|
| 567 | + ERR_PTR(err)); |
---|
510 | 568 | serdev_device_put(serdev); |
---|
511 | 569 | } else |
---|
512 | 570 | found = true; |
---|
.. | .. |
---|
518 | 576 | } |
---|
519 | 577 | |
---|
520 | 578 | #ifdef CONFIG_ACPI |
---|
521 | | -static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl, |
---|
522 | | - struct acpi_device *adev) |
---|
523 | | -{ |
---|
524 | | - struct serdev_device *serdev = NULL; |
---|
525 | | - int err; |
---|
526 | 579 | |
---|
527 | | - if (acpi_bus_get_status(adev) || !adev->status.present || |
---|
528 | | - acpi_device_enumerated(adev)) |
---|
529 | | - return AE_OK; |
---|
| 580 | +#define SERDEV_ACPI_MAX_SCAN_DEPTH 32 |
---|
| 581 | + |
---|
| 582 | +struct acpi_serdev_lookup { |
---|
| 583 | + acpi_handle device_handle; |
---|
| 584 | + acpi_handle controller_handle; |
---|
| 585 | + int n; |
---|
| 586 | + int index; |
---|
| 587 | +}; |
---|
| 588 | + |
---|
| 589 | +static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data) |
---|
| 590 | +{ |
---|
| 591 | + struct acpi_serdev_lookup *lookup = data; |
---|
| 592 | + struct acpi_resource_uart_serialbus *sb; |
---|
| 593 | + acpi_status status; |
---|
| 594 | + |
---|
| 595 | + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) |
---|
| 596 | + return 1; |
---|
| 597 | + |
---|
| 598 | + if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART) |
---|
| 599 | + return 1; |
---|
| 600 | + |
---|
| 601 | + if (lookup->index != -1 && lookup->n++ != lookup->index) |
---|
| 602 | + return 1; |
---|
| 603 | + |
---|
| 604 | + sb = &ares->data.uart_serial_bus; |
---|
| 605 | + |
---|
| 606 | + status = acpi_get_handle(lookup->device_handle, |
---|
| 607 | + sb->resource_source.string_ptr, |
---|
| 608 | + &lookup->controller_handle); |
---|
| 609 | + if (ACPI_FAILURE(status)) |
---|
| 610 | + return 1; |
---|
| 611 | + |
---|
| 612 | + /* |
---|
| 613 | + * NOTE: Ideally, we would also want to retreive other properties here, |
---|
| 614 | + * once setting them before opening the device is supported by serdev. |
---|
| 615 | + */ |
---|
| 616 | + |
---|
| 617 | + return 1; |
---|
| 618 | +} |
---|
| 619 | + |
---|
| 620 | +static int acpi_serdev_do_lookup(struct acpi_device *adev, |
---|
| 621 | + struct acpi_serdev_lookup *lookup) |
---|
| 622 | +{ |
---|
| 623 | + struct list_head resource_list; |
---|
| 624 | + int ret; |
---|
| 625 | + |
---|
| 626 | + lookup->device_handle = acpi_device_handle(adev); |
---|
| 627 | + lookup->controller_handle = NULL; |
---|
| 628 | + lookup->n = 0; |
---|
| 629 | + |
---|
| 630 | + INIT_LIST_HEAD(&resource_list); |
---|
| 631 | + ret = acpi_dev_get_resources(adev, &resource_list, |
---|
| 632 | + acpi_serdev_parse_resource, lookup); |
---|
| 633 | + acpi_dev_free_resource_list(&resource_list); |
---|
| 634 | + |
---|
| 635 | + if (ret < 0) |
---|
| 636 | + return -EINVAL; |
---|
| 637 | + |
---|
| 638 | + return 0; |
---|
| 639 | +} |
---|
| 640 | + |
---|
| 641 | +static int acpi_serdev_check_resources(struct serdev_controller *ctrl, |
---|
| 642 | + struct acpi_device *adev) |
---|
| 643 | +{ |
---|
| 644 | + struct acpi_serdev_lookup lookup; |
---|
| 645 | + int ret; |
---|
| 646 | + |
---|
| 647 | + if (acpi_bus_get_status(adev) || !adev->status.present) |
---|
| 648 | + return -EINVAL; |
---|
| 649 | + |
---|
| 650 | + /* Look for UARTSerialBusV2 resource */ |
---|
| 651 | + lookup.index = -1; // we only care for the last device |
---|
| 652 | + |
---|
| 653 | + ret = acpi_serdev_do_lookup(adev, &lookup); |
---|
| 654 | + if (ret) |
---|
| 655 | + return ret; |
---|
| 656 | + |
---|
| 657 | + /* |
---|
| 658 | + * Apple machines provide an empty resource template, so on those |
---|
| 659 | + * machines just look for immediate children with a "baud" property |
---|
| 660 | + * (from the _DSM method) instead. |
---|
| 661 | + */ |
---|
| 662 | + if (!lookup.controller_handle && x86_apple_machine && |
---|
| 663 | + !acpi_dev_get_property(adev, "baud", ACPI_TYPE_BUFFER, NULL)) |
---|
| 664 | + acpi_get_parent(adev->handle, &lookup.controller_handle); |
---|
| 665 | + |
---|
| 666 | + /* Make sure controller and ResourceSource handle match */ |
---|
| 667 | + if (ACPI_HANDLE(ctrl->dev.parent) != lookup.controller_handle) |
---|
| 668 | + return -ENODEV; |
---|
| 669 | + |
---|
| 670 | + return 0; |
---|
| 671 | +} |
---|
| 672 | + |
---|
| 673 | +static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl, |
---|
| 674 | + struct acpi_device *adev) |
---|
| 675 | +{ |
---|
| 676 | + struct serdev_device *serdev; |
---|
| 677 | + int err; |
---|
530 | 678 | |
---|
531 | 679 | serdev = serdev_device_alloc(ctrl); |
---|
532 | 680 | if (!serdev) { |
---|
.. | .. |
---|
541 | 689 | err = serdev_device_add(serdev); |
---|
542 | 690 | if (err) { |
---|
543 | 691 | dev_err(&serdev->dev, |
---|
544 | | - "failure adding ACPI serdev device. status %d\n", err); |
---|
| 692 | + "failure adding ACPI serdev device. status %pe\n", |
---|
| 693 | + ERR_PTR(err)); |
---|
545 | 694 | serdev_device_put(serdev); |
---|
546 | 695 | } |
---|
547 | 696 | |
---|
.. | .. |
---|
555 | 704 | }; |
---|
556 | 705 | |
---|
557 | 706 | static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, |
---|
558 | | - void *data, void **return_value) |
---|
| 707 | + void *data, void **return_value) |
---|
559 | 708 | { |
---|
560 | 709 | struct serdev_controller *ctrl = data; |
---|
561 | 710 | struct acpi_device *adev; |
---|
.. | .. |
---|
563 | 712 | if (acpi_bus_get_device(handle, &adev)) |
---|
564 | 713 | return AE_OK; |
---|
565 | 714 | |
---|
| 715 | + if (acpi_device_enumerated(adev)) |
---|
| 716 | + return AE_OK; |
---|
| 717 | + |
---|
566 | 718 | /* Skip if black listed */ |
---|
567 | 719 | if (!acpi_match_device_ids(adev, serdev_acpi_devices_blacklist)) |
---|
| 720 | + return AE_OK; |
---|
| 721 | + |
---|
| 722 | + if (acpi_serdev_check_resources(ctrl, adev)) |
---|
568 | 723 | return AE_OK; |
---|
569 | 724 | |
---|
570 | 725 | return acpi_serdev_register_device(ctrl, adev); |
---|
571 | 726 | } |
---|
572 | 727 | |
---|
| 728 | + |
---|
573 | 729 | static int acpi_serdev_register_devices(struct serdev_controller *ctrl) |
---|
574 | 730 | { |
---|
575 | 731 | acpi_status status; |
---|
576 | | - acpi_handle handle; |
---|
577 | 732 | |
---|
578 | | - handle = ACPI_HANDLE(ctrl->dev.parent); |
---|
579 | | - if (!handle) |
---|
| 733 | + if (!has_acpi_companion(ctrl->dev.parent)) |
---|
580 | 734 | return -ENODEV; |
---|
581 | 735 | |
---|
582 | | - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, |
---|
| 736 | + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
---|
| 737 | + SERDEV_ACPI_MAX_SCAN_DEPTH, |
---|
583 | 738 | acpi_serdev_add_device, NULL, ctrl, NULL); |
---|
584 | 739 | if (ACPI_FAILURE(status)) |
---|
585 | | - dev_dbg(&ctrl->dev, "failed to enumerate serdev slaves\n"); |
---|
| 740 | + dev_warn(&ctrl->dev, "failed to enumerate serdev slaves\n"); |
---|
586 | 741 | |
---|
587 | 742 | if (!ctrl->serdev) |
---|
588 | 743 | return -ENODEV; |
---|
.. | .. |
---|
651 | 806 | if (platform) |
---|
652 | 807 | ret_platform = platform_serdev_register_devices(ctrl); |
---|
653 | 808 | if (ret_of && ret_acpi && ret_platform) { |
---|
654 | | - dev_dbg(&ctrl->dev, "no devices registered: of:%d acpi:%d " |
---|
655 | | - "platform:%d\n", |
---|
656 | | - ret_of, ret_acpi, ret_platform); |
---|
| 809 | + dev_dbg(&ctrl->dev, |
---|
| 810 | + "no devices registered: of:%pe acpi:%pe platform:%pe\n", |
---|
| 811 | + ERR_PTR(ret_of), ERR_PTR(ret_acpi), |
---|
| 812 | + ERR_PTR(ret_platform)); |
---|
657 | 813 | ret = -ENODEV; |
---|
658 | 814 | goto err_rpm_disable; |
---|
659 | 815 | } |
---|