Skip to content

Commit dc786b2

Browse files
Rajat Jainholtmann
authored andcommitted
Bluetooth: btusb: Use the cmd_timeout method to reset the Intel BT chip
If the platform provides it, use the reset gpio to reset the Intel BT chip, as part of cmd_timeout handling. This has been found helpful on Intel bluetooth controllers where the firmware gets stuck and the only way out is a hard reset pin provided by the platform. Signed-off-by: Rajat Jain <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent e2bef38 commit dc786b2

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

drivers/bluetooth/btusb.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/of_device.h>
3030
#include <linux/of_irq.h>
3131
#include <linux/suspend.h>
32+
#include <linux/gpio/consumer.h>
3233
#include <asm/unaligned.h>
3334

3435
#include <net/bluetooth/bluetooth.h>
@@ -439,6 +440,7 @@ static const struct dmi_system_id btusb_needs_reset_resume_table[] = {
439440
#define BTUSB_BOOTING 9
440441
#define BTUSB_DIAG_RUNNING 10
441442
#define BTUSB_OOB_WAKE_ENABLED 11
443+
#define BTUSB_HW_RESET_ACTIVE 12
442444

443445
struct btusb_data {
444446
struct hci_dev *hdev;
@@ -476,6 +478,8 @@ struct btusb_data {
476478
struct usb_endpoint_descriptor *diag_tx_ep;
477479
struct usb_endpoint_descriptor *diag_rx_ep;
478480

481+
struct gpio_desc *reset_gpio;
482+
479483
__u8 cmdreq_type;
480484
__u8 cmdreq;
481485

@@ -489,8 +493,41 @@ struct btusb_data {
489493
int (*setup_on_usb)(struct hci_dev *hdev);
490494

491495
int oob_wake_irq; /* irq for out-of-band wake-on-bt */
496+
unsigned cmd_timeout_cnt;
492497
};
493498

499+
500+
static void btusb_intel_cmd_timeout(struct hci_dev *hdev)
501+
{
502+
struct btusb_data *data = hci_get_drvdata(hdev);
503+
struct gpio_desc *reset_gpio = data->reset_gpio;
504+
505+
if (++data->cmd_timeout_cnt < 5)
506+
return;
507+
508+
if (!reset_gpio) {
509+
bt_dev_err(hdev, "No way to reset. Ignoring and continuing");
510+
return;
511+
}
512+
513+
/*
514+
* Toggle the hard reset line if the platform provides one. The reset
515+
* is going to yank the device off the USB and then replug. So doing
516+
* once is enough. The cleanup is handled correctly on the way out
517+
* (standard USB disconnect), and the new device is detected cleanly
518+
* and bound to the driver again like it should be.
519+
*/
520+
if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
521+
bt_dev_err(hdev, "last reset failed? Not resetting again");
522+
return;
523+
}
524+
525+
bt_dev_err(hdev, "Initiating HW reset via gpio");
526+
gpiod_set_value(reset_gpio, 1);
527+
mdelay(100);
528+
gpiod_set_value(reset_gpio, 0);
529+
}
530+
494531
static inline void btusb_free_frags(struct btusb_data *data)
495532
{
496533
unsigned long flags;
@@ -2915,6 +2952,7 @@ static int btusb_probe(struct usb_interface *intf,
29152952
const struct usb_device_id *id)
29162953
{
29172954
struct usb_endpoint_descriptor *ep_desc;
2955+
struct gpio_desc *reset_gpio;
29182956
struct btusb_data *data;
29192957
struct hci_dev *hdev;
29202958
unsigned ifnum_base;
@@ -3028,6 +3066,15 @@ static int btusb_probe(struct usb_interface *intf,
30283066

30293067
SET_HCIDEV_DEV(hdev, &intf->dev);
30303068

3069+
reset_gpio = gpiod_get_optional(&data->udev->dev, "reset",
3070+
GPIOD_OUT_LOW);
3071+
if (IS_ERR(reset_gpio)) {
3072+
err = PTR_ERR(reset_gpio);
3073+
goto out_free_dev;
3074+
} else if (reset_gpio) {
3075+
data->reset_gpio = reset_gpio;
3076+
}
3077+
30313078
hdev->open = btusb_open;
30323079
hdev->close = btusb_close;
30333080
hdev->flush = btusb_flush;
@@ -3082,6 +3129,7 @@ static int btusb_probe(struct usb_interface *intf,
30823129
hdev->shutdown = btusb_shutdown_intel;
30833130
hdev->set_diag = btintel_set_diag_mfg;
30843131
hdev->set_bdaddr = btintel_set_bdaddr;
3132+
hdev->cmd_timeout = btusb_intel_cmd_timeout;
30853133
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
30863134
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
30873135
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
@@ -3094,6 +3142,7 @@ static int btusb_probe(struct usb_interface *intf,
30943142
hdev->hw_error = btintel_hw_error;
30953143
hdev->set_diag = btintel_set_diag;
30963144
hdev->set_bdaddr = btintel_set_bdaddr;
3145+
hdev->cmd_timeout = btusb_intel_cmd_timeout;
30973146
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
30983147
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
30993148
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
@@ -3226,6 +3275,8 @@ static int btusb_probe(struct usb_interface *intf,
32263275
return 0;
32273276

32283277
out_free_dev:
3278+
if (data->reset_gpio)
3279+
gpiod_put(data->reset_gpio);
32293280
hci_free_dev(hdev);
32303281
return err;
32313282
}
@@ -3269,6 +3320,9 @@ static void btusb_disconnect(struct usb_interface *intf)
32693320
if (data->oob_wake_irq)
32703321
device_init_wakeup(&data->udev->dev, false);
32713322

3323+
if (data->reset_gpio)
3324+
gpiod_put(data->reset_gpio);
3325+
32723326
hci_free_dev(hdev);
32733327
}
32743328

0 commit comments

Comments
 (0)