diff options
Diffstat (limited to 'drivers/bluetooth/hci_serdev.c')
-rw-r--r-- | drivers/bluetooth/hci_serdev.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 7b233312e723..ef96ad06fa54 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -113,8 +113,22 @@ static int hci_uart_flush(struct hci_dev *hdev) /* Initialize device */ static int hci_uart_open(struct hci_dev *hdev) { + struct hci_uart *hu = hci_get_drvdata(hdev); + int err; + BT_DBG("%s %p", hdev->name, hdev); + /* When Quirk HCI_QUIRK_NON_PERSISTENT_SETUP is set by + * driver, BT SoC is completely turned OFF during + * BT OFF. Upon next BT ON UART port should be opened. + */ + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + err = serdev_device_open(hu->serdev); + if (err) + return err; + set_bit(HCI_UART_PROTO_READY, &hu->flags); + } + /* Undo clearing this from hci_uart_close() */ hdev->flush = hci_uart_flush; @@ -124,11 +138,25 @@ static int hci_uart_open(struct hci_dev *hdev) /* Close device */ static int hci_uart_close(struct hci_dev *hdev) { + struct hci_uart *hu = hci_get_drvdata(hdev); + BT_DBG("hdev %p", hdev); + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + return 0; + hci_uart_flush(hdev); hdev->flush = NULL; + /* When QUIRK HCI_QUIRK_NON_PERSISTENT_SETUP is set by driver, + * BT SOC is completely powered OFF during BT OFF, holding port + * open may drain the battery. + */ + if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) { + clear_bit(HCI_UART_PROTO_READY, &hu->flags); + serdev_device_close(hu->serdev); + } + return 0; } @@ -354,7 +382,7 @@ void hci_uart_unregister_device(struct hci_uart *hu) { struct hci_dev *hdev = hu->hdev; - clear_bit(HCI_UART_PROTO_READY, &hu->flags); + cancel_work_sync(&hu->init_ready); if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); hci_free_dev(hdev); @@ -362,6 +390,10 @@ void hci_uart_unregister_device(struct hci_uart *hu) cancel_work_sync(&hu->write_work); hu->proto->close(hu); - serdev_device_close(hu->serdev); + + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + clear_bit(HCI_UART_PROTO_READY, &hu->flags); + serdev_device_close(hu->serdev); + } } EXPORT_SYMBOL_GPL(hci_uart_unregister_device); |