.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * |
---|
3 | 4 | * Bluetooth HCI Three-wire UART driver |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2012 Intel Corporation |
---|
6 | | - * |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
11 | | - * (at your option) any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | | - * |
---|
18 | | - * You should have received a copy of the GNU General Public License |
---|
19 | | - * along with this program; if not, write to the Free Software |
---|
20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
21 | | - * |
---|
22 | 7 | */ |
---|
23 | 8 | |
---|
24 | 9 | #include <linux/acpi.h> |
---|
.. | .. |
---|
26 | 11 | #include <linux/gpio/consumer.h> |
---|
27 | 12 | #include <linux/kernel.h> |
---|
28 | 13 | #include <linux/mod_devicetable.h> |
---|
| 14 | +#include <linux/of_device.h> |
---|
29 | 15 | #include <linux/serdev.h> |
---|
30 | 16 | #include <linux/skbuff.h> |
---|
31 | 17 | |
---|
.. | .. |
---|
115 | 101 | int (*setup)(struct h5 *h5); |
---|
116 | 102 | void (*open)(struct h5 *h5); |
---|
117 | 103 | void (*close)(struct h5 *h5); |
---|
| 104 | + int (*suspend)(struct h5 *h5); |
---|
| 105 | + int (*resume)(struct h5 *h5); |
---|
118 | 106 | const struct acpi_gpio_mapping *acpi_gpio_map; |
---|
119 | 107 | }; |
---|
120 | 108 | |
---|
.. | .. |
---|
190 | 178 | { |
---|
191 | 179 | struct h5 *h5 = hu->priv; |
---|
192 | 180 | |
---|
193 | | - BT_ERR("Peer device has reset"); |
---|
| 181 | + bt_dev_err(hu->hdev, "Peer device has reset"); |
---|
194 | 182 | |
---|
195 | 183 | h5->state = H5_UNINITIALIZED; |
---|
196 | 184 | |
---|
.. | .. |
---|
311 | 299 | break; |
---|
312 | 300 | |
---|
313 | 301 | __skb_unlink(skb, &h5->unack); |
---|
314 | | - kfree_skb(skb); |
---|
| 302 | + dev_kfree_skb_irq(skb); |
---|
315 | 303 | } |
---|
316 | 304 | |
---|
317 | 305 | if (skb_queue_empty(&h5->unack)) |
---|
.. | .. |
---|
401 | 389 | case HCI_EVENT_PKT: |
---|
402 | 390 | case HCI_ACLDATA_PKT: |
---|
403 | 391 | case HCI_SCODATA_PKT: |
---|
| 392 | + case HCI_ISODATA_PKT: |
---|
404 | 393 | hci_skb_pkt_type(h5->rx_skb) = H5_HDR_PKT_TYPE(hdr); |
---|
405 | 394 | |
---|
406 | 395 | /* Remove Three-wire header */ |
---|
.. | .. |
---|
452 | 441 | H5_HDR_LEN(hdr)); |
---|
453 | 442 | |
---|
454 | 443 | if (((hdr[0] + hdr[1] + hdr[2] + hdr[3]) & 0xff) != 0xff) { |
---|
455 | | - BT_ERR("Invalid header checksum"); |
---|
| 444 | + bt_dev_err(hu->hdev, "Invalid header checksum"); |
---|
456 | 445 | h5_reset_rx(h5); |
---|
457 | 446 | return 0; |
---|
458 | 447 | } |
---|
459 | 448 | |
---|
460 | 449 | if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_ack) { |
---|
461 | | - BT_ERR("Out-of-order packet arrived (%u != %u)", |
---|
462 | | - H5_HDR_SEQ(hdr), h5->tx_ack); |
---|
| 450 | + bt_dev_err(hu->hdev, "Out-of-order packet arrived (%u != %u)", |
---|
| 451 | + H5_HDR_SEQ(hdr), h5->tx_ack); |
---|
463 | 452 | h5_reset_rx(h5); |
---|
464 | 453 | return 0; |
---|
465 | 454 | } |
---|
466 | 455 | |
---|
467 | 456 | if (h5->state != H5_ACTIVE && |
---|
468 | 457 | H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) { |
---|
469 | | - BT_ERR("Non-link packet received in non-active state"); |
---|
| 458 | + bt_dev_err(hu->hdev, "Non-link packet received in non-active state"); |
---|
470 | 459 | h5_reset_rx(h5); |
---|
471 | 460 | return 0; |
---|
472 | 461 | } |
---|
.. | .. |
---|
489 | 478 | |
---|
490 | 479 | h5->rx_skb = bt_skb_alloc(H5_MAX_LEN, GFP_ATOMIC); |
---|
491 | 480 | if (!h5->rx_skb) { |
---|
492 | | - BT_ERR("Can't allocate mem for new packet"); |
---|
| 481 | + bt_dev_err(hu->hdev, "Can't allocate mem for new packet"); |
---|
493 | 482 | h5_reset_rx(h5); |
---|
494 | 483 | return -ENOMEM; |
---|
495 | 484 | } |
---|
.. | .. |
---|
537 | 526 | skb_put_data(h5->rx_skb, byte, 1); |
---|
538 | 527 | h5->rx_pending--; |
---|
539 | 528 | |
---|
540 | | - BT_DBG("unsliped 0x%02hhx, rx_pending %zu", *byte, h5->rx_pending); |
---|
| 529 | + BT_DBG("unslipped 0x%02hhx, rx_pending %zu", *byte, h5->rx_pending); |
---|
541 | 530 | } |
---|
542 | 531 | |
---|
543 | 532 | static void h5_reset_rx(struct h5 *h5) |
---|
.. | .. |
---|
565 | 554 | |
---|
566 | 555 | if (h5->rx_pending > 0) { |
---|
567 | 556 | if (*ptr == SLIP_DELIMITER) { |
---|
568 | | - BT_ERR("Too short H5 packet"); |
---|
| 557 | + bt_dev_err(hu->hdev, "Too short H5 packet"); |
---|
569 | 558 | h5_reset_rx(h5); |
---|
570 | 559 | continue; |
---|
571 | 560 | } |
---|
.. | .. |
---|
592 | 581 | struct h5 *h5 = hu->priv; |
---|
593 | 582 | |
---|
594 | 583 | if (skb->len > 0xfff) { |
---|
595 | | - BT_ERR("Packet too long (%u bytes)", skb->len); |
---|
| 584 | + bt_dev_err(hu->hdev, "Packet too long (%u bytes)", skb->len); |
---|
596 | 585 | kfree_skb(skb); |
---|
597 | 586 | return 0; |
---|
598 | 587 | } |
---|
599 | 588 | |
---|
600 | 589 | if (h5->state != H5_ACTIVE) { |
---|
601 | | - BT_ERR("Ignoring HCI data in non-active state"); |
---|
| 590 | + bt_dev_err(hu->hdev, "Ignoring HCI data in non-active state"); |
---|
602 | 591 | kfree_skb(skb); |
---|
603 | 592 | return 0; |
---|
604 | 593 | } |
---|
.. | .. |
---|
610 | 599 | break; |
---|
611 | 600 | |
---|
612 | 601 | case HCI_SCODATA_PKT: |
---|
| 602 | + case HCI_ISODATA_PKT: |
---|
613 | 603 | skb_queue_tail(&h5->unrel, skb); |
---|
614 | 604 | break; |
---|
615 | 605 | |
---|
616 | 606 | default: |
---|
617 | | - BT_ERR("Unknown packet type %u", hci_skb_pkt_type(skb)); |
---|
| 607 | + bt_dev_err(hu->hdev, "Unknown packet type %u", hci_skb_pkt_type(skb)); |
---|
618 | 608 | kfree_skb(skb); |
---|
619 | 609 | break; |
---|
620 | 610 | } |
---|
.. | .. |
---|
652 | 642 | case HCI_ACLDATA_PKT: |
---|
653 | 643 | case HCI_COMMAND_PKT: |
---|
654 | 644 | case HCI_SCODATA_PKT: |
---|
| 645 | + case HCI_ISODATA_PKT: |
---|
655 | 646 | case HCI_3WIRE_LINK_PKT: |
---|
656 | 647 | case HCI_3WIRE_ACK_PKT: |
---|
657 | 648 | return true; |
---|
.. | .. |
---|
669 | 660 | int i; |
---|
670 | 661 | |
---|
671 | 662 | if (!valid_packet_type(pkt_type)) { |
---|
672 | | - BT_ERR("Unknown packet type %u", pkt_type); |
---|
| 663 | + bt_dev_err(hu->hdev, "Unknown packet type %u", pkt_type); |
---|
673 | 664 | return NULL; |
---|
674 | 665 | } |
---|
675 | 666 | |
---|
.. | .. |
---|
746 | 737 | } |
---|
747 | 738 | |
---|
748 | 739 | skb_queue_head(&h5->unrel, skb); |
---|
749 | | - BT_ERR("Could not dequeue pkt because alloc_skb failed"); |
---|
| 740 | + bt_dev_err(hu->hdev, "Could not dequeue pkt because alloc_skb failed"); |
---|
750 | 741 | } |
---|
751 | 742 | |
---|
752 | 743 | spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); |
---|
.. | .. |
---|
766 | 757 | } |
---|
767 | 758 | |
---|
768 | 759 | skb_queue_head(&h5->rel, skb); |
---|
769 | | - BT_ERR("Could not dequeue pkt because alloc_skb failed"); |
---|
| 760 | + bt_dev_err(hu->hdev, "Could not dequeue pkt because alloc_skb failed"); |
---|
770 | 761 | } |
---|
771 | 762 | |
---|
772 | 763 | unlock: |
---|
.. | .. |
---|
798 | 789 | |
---|
799 | 790 | static int h5_serdev_probe(struct serdev_device *serdev) |
---|
800 | 791 | { |
---|
801 | | - const struct acpi_device_id *match; |
---|
802 | 792 | struct device *dev = &serdev->dev; |
---|
803 | 793 | struct h5 *h5; |
---|
804 | 794 | |
---|
.. | .. |
---|
806 | 796 | if (!h5) |
---|
807 | 797 | return -ENOMEM; |
---|
808 | 798 | |
---|
809 | | - set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.hdev_flags); |
---|
810 | | - |
---|
811 | 799 | h5->hu = &h5->serdev_hu; |
---|
812 | 800 | h5->serdev_hu.serdev = serdev; |
---|
813 | 801 | serdev_device_set_drvdata(serdev, h5); |
---|
814 | 802 | |
---|
815 | 803 | if (has_acpi_companion(dev)) { |
---|
| 804 | + const struct acpi_device_id *match; |
---|
| 805 | + |
---|
816 | 806 | match = acpi_match_device(dev->driver->acpi_match_table, dev); |
---|
817 | 807 | if (!match) |
---|
818 | 808 | return -ENODEV; |
---|
.. | .. |
---|
823 | 813 | if (h5->vnd->acpi_gpio_map) |
---|
824 | 814 | devm_acpi_dev_add_driver_gpios(dev, |
---|
825 | 815 | h5->vnd->acpi_gpio_map); |
---|
| 816 | + } else { |
---|
| 817 | + const void *data; |
---|
| 818 | + |
---|
| 819 | + data = of_device_get_match_data(dev); |
---|
| 820 | + if (!data) |
---|
| 821 | + return -ENODEV; |
---|
| 822 | + |
---|
| 823 | + h5->vnd = (const struct h5_vnd *)data; |
---|
826 | 824 | } |
---|
| 825 | + |
---|
827 | 826 | |
---|
828 | 827 | h5->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); |
---|
829 | 828 | if (IS_ERR(h5->enable_gpio)) |
---|
.. | .. |
---|
842 | 841 | struct h5 *h5 = serdev_device_get_drvdata(serdev); |
---|
843 | 842 | |
---|
844 | 843 | hci_uart_unregister_device(&h5->serdev_hu); |
---|
| 844 | +} |
---|
| 845 | + |
---|
| 846 | +static int __maybe_unused h5_serdev_suspend(struct device *dev) |
---|
| 847 | +{ |
---|
| 848 | + struct h5 *h5 = dev_get_drvdata(dev); |
---|
| 849 | + int ret = 0; |
---|
| 850 | + |
---|
| 851 | + if (h5->vnd && h5->vnd->suspend) |
---|
| 852 | + ret = h5->vnd->suspend(h5); |
---|
| 853 | + |
---|
| 854 | + return ret; |
---|
| 855 | +} |
---|
| 856 | + |
---|
| 857 | +static int __maybe_unused h5_serdev_resume(struct device *dev) |
---|
| 858 | +{ |
---|
| 859 | + struct h5 *h5 = dev_get_drvdata(dev); |
---|
| 860 | + int ret = 0; |
---|
| 861 | + |
---|
| 862 | + if (h5->vnd && h5->vnd->resume) |
---|
| 863 | + ret = h5->vnd->resume(h5); |
---|
| 864 | + |
---|
| 865 | + return ret; |
---|
845 | 866 | } |
---|
846 | 867 | |
---|
847 | 868 | #ifdef CONFIG_BT_HCIUART_RTL |
---|
.. | .. |
---|
915 | 936 | gpiod_set_value_cansleep(h5->enable_gpio, 0); |
---|
916 | 937 | } |
---|
917 | 938 | |
---|
| 939 | +/* Suspend/resume support. On many devices the RTL BT device loses power during |
---|
| 940 | + * suspend/resume, causing it to lose its firmware and all state. So we simply |
---|
| 941 | + * turn it off on suspend and reprobe on resume. This mirrors how RTL devices |
---|
| 942 | + * are handled in the USB driver, where the USB_QUIRK_RESET_RESUME is used which |
---|
| 943 | + * also causes a reprobe on resume. |
---|
| 944 | + */ |
---|
| 945 | +static int h5_btrtl_suspend(struct h5 *h5) |
---|
| 946 | +{ |
---|
| 947 | + serdev_device_set_flow_control(h5->hu->serdev, false); |
---|
| 948 | + gpiod_set_value_cansleep(h5->device_wake_gpio, 0); |
---|
| 949 | + gpiod_set_value_cansleep(h5->enable_gpio, 0); |
---|
| 950 | + return 0; |
---|
| 951 | +} |
---|
| 952 | + |
---|
| 953 | +struct h5_btrtl_reprobe { |
---|
| 954 | + struct device *dev; |
---|
| 955 | + struct work_struct work; |
---|
| 956 | +}; |
---|
| 957 | + |
---|
| 958 | +static void h5_btrtl_reprobe_worker(struct work_struct *work) |
---|
| 959 | +{ |
---|
| 960 | + struct h5_btrtl_reprobe *reprobe = |
---|
| 961 | + container_of(work, struct h5_btrtl_reprobe, work); |
---|
| 962 | + int ret; |
---|
| 963 | + |
---|
| 964 | + ret = device_reprobe(reprobe->dev); |
---|
| 965 | + if (ret && ret != -EPROBE_DEFER) |
---|
| 966 | + dev_err(reprobe->dev, "Reprobe error %d\n", ret); |
---|
| 967 | + |
---|
| 968 | + put_device(reprobe->dev); |
---|
| 969 | + kfree(reprobe); |
---|
| 970 | + module_put(THIS_MODULE); |
---|
| 971 | +} |
---|
| 972 | + |
---|
| 973 | +static int h5_btrtl_resume(struct h5 *h5) |
---|
| 974 | +{ |
---|
| 975 | + struct h5_btrtl_reprobe *reprobe; |
---|
| 976 | + |
---|
| 977 | + reprobe = kzalloc(sizeof(*reprobe), GFP_KERNEL); |
---|
| 978 | + if (!reprobe) |
---|
| 979 | + return -ENOMEM; |
---|
| 980 | + |
---|
| 981 | + __module_get(THIS_MODULE); |
---|
| 982 | + |
---|
| 983 | + INIT_WORK(&reprobe->work, h5_btrtl_reprobe_worker); |
---|
| 984 | + reprobe->dev = get_device(&h5->hu->serdev->dev); |
---|
| 985 | + queue_work(system_long_wq, &reprobe->work); |
---|
| 986 | + return 0; |
---|
| 987 | +} |
---|
| 988 | + |
---|
918 | 989 | static const struct acpi_gpio_params btrtl_device_wake_gpios = { 0, 0, false }; |
---|
919 | 990 | static const struct acpi_gpio_params btrtl_enable_gpios = { 1, 0, false }; |
---|
920 | 991 | static const struct acpi_gpio_params btrtl_host_wake_gpios = { 2, 0, false }; |
---|
.. | .. |
---|
929 | 1000 | .setup = h5_btrtl_setup, |
---|
930 | 1001 | .open = h5_btrtl_open, |
---|
931 | 1002 | .close = h5_btrtl_close, |
---|
| 1003 | + .suspend = h5_btrtl_suspend, |
---|
| 1004 | + .resume = h5_btrtl_resume, |
---|
932 | 1005 | .acpi_gpio_map = acpi_btrtl_gpios, |
---|
933 | 1006 | }; |
---|
934 | 1007 | #endif |
---|
.. | .. |
---|
943 | 1016 | MODULE_DEVICE_TABLE(acpi, h5_acpi_match); |
---|
944 | 1017 | #endif |
---|
945 | 1018 | |
---|
| 1019 | +static const struct dev_pm_ops h5_serdev_pm_ops = { |
---|
| 1020 | + SET_SYSTEM_SLEEP_PM_OPS(h5_serdev_suspend, h5_serdev_resume) |
---|
| 1021 | +}; |
---|
| 1022 | + |
---|
| 1023 | +static const struct of_device_id rtl_bluetooth_of_match[] = { |
---|
| 1024 | +#ifdef CONFIG_BT_HCIUART_RTL |
---|
| 1025 | + { .compatible = "realtek,rtl8822cs-bt", |
---|
| 1026 | + .data = (const void *)&rtl_vnd }, |
---|
| 1027 | + { .compatible = "realtek,rtl8723bs-bt", |
---|
| 1028 | + .data = (const void *)&rtl_vnd }, |
---|
| 1029 | +#endif |
---|
| 1030 | + { }, |
---|
| 1031 | +}; |
---|
| 1032 | +MODULE_DEVICE_TABLE(of, rtl_bluetooth_of_match); |
---|
| 1033 | + |
---|
946 | 1034 | static struct serdev_device_driver h5_serdev_driver = { |
---|
947 | 1035 | .probe = h5_serdev_probe, |
---|
948 | 1036 | .remove = h5_serdev_remove, |
---|
949 | 1037 | .driver = { |
---|
950 | 1038 | .name = "hci_uart_h5", |
---|
951 | 1039 | .acpi_match_table = ACPI_PTR(h5_acpi_match), |
---|
| 1040 | + .pm = &h5_serdev_pm_ops, |
---|
| 1041 | + .of_match_table = rtl_bluetooth_of_match, |
---|
952 | 1042 | }, |
---|
953 | 1043 | }; |
---|
954 | 1044 | |
---|