diff options
Diffstat (limited to 'drivers/bluetooth/btusb.c')
| -rw-r--r-- | drivers/bluetooth/btusb.c | 64 | 
1 files changed, 57 insertions, 7 deletions
| diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 60d2fce59a71..75c83768c257 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -384,6 +384,12 @@ static const struct usb_device_id blacklist_table[] = {  	/* Realtek 8852AE Bluetooth devices */  	{ USB_DEVICE(0x0bda, 0xc852), .driver_info = BTUSB_REALTEK |  						     BTUSB_WIDEBAND_SPEECH }, +	{ USB_DEVICE(0x0bda, 0x4852), .driver_info = BTUSB_REALTEK | +						     BTUSB_WIDEBAND_SPEECH }, +	{ USB_DEVICE(0x04c5, 0x165c), .driver_info = BTUSB_REALTEK | +						     BTUSB_WIDEBAND_SPEECH }, +	{ USB_DEVICE(0x04ca, 0x4006), .driver_info = BTUSB_REALTEK | +						     BTUSB_WIDEBAND_SPEECH },  	/* Realtek Bluetooth devices */  	{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), @@ -410,6 +416,9 @@ static const struct usb_device_id blacklist_table[] = {  	{ USB_DEVICE(0x13d3, 0x3563), .driver_info = BTUSB_MEDIATEK |  						     BTUSB_WIDEBAND_SPEECH |  						     BTUSB_VALID_LE_STATES }, +	{ USB_DEVICE(0x13d3, 0x3564), .driver_info = BTUSB_MEDIATEK | +						     BTUSB_WIDEBAND_SPEECH | +						     BTUSB_VALID_LE_STATES },  	{ USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK |  						     BTUSB_WIDEBAND_SPEECH |  						     BTUSB_VALID_LE_STATES }, @@ -433,6 +442,10 @@ static const struct usb_device_id blacklist_table[] = {  	{ USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },  	{ USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK }, +	/* Additional Realtek 8761B Bluetooth devices */ +	{ USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK | +						     BTUSB_WIDEBAND_SPEECH }, +  	/* Additional Realtek 8761BU Bluetooth devices */  	{ USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |  	  					     BTUSB_WIDEBAND_SPEECH }, @@ -451,10 +464,6 @@ static const struct usb_device_id blacklist_table[] = {  	/* Additional Realtek 8822CE Bluetooth devices */  	{ USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK |  						     BTUSB_WIDEBAND_SPEECH }, -	/* Bluetooth component of Realtek 8852AE device */ -	{ USB_DEVICE(0x04ca, 0x4006), .driver_info = BTUSB_REALTEK | -						     BTUSB_WIDEBAND_SPEECH }, -  	{ USB_DEVICE(0x04c5, 0x161f), .driver_info = BTUSB_REALTEK |  						     BTUSB_WIDEBAND_SPEECH },  	{ USB_DEVICE(0x0b05, 0x18ef), .driver_info = BTUSB_REALTEK | @@ -652,11 +661,33 @@ static void btusb_rtl_cmd_timeout(struct hci_dev *hdev)  static void btusb_qca_cmd_timeout(struct hci_dev *hdev)  {  	struct btusb_data *data = hci_get_drvdata(hdev); +	struct gpio_desc *reset_gpio = data->reset_gpio;  	int err;  	if (++data->cmd_timeout_cnt < 5)  		return; +	if (reset_gpio) { +		bt_dev_err(hdev, "Reset qca device via bt_en gpio"); + +		/* Toggle the hard reset line. The qca bt device is going to +		 * yank itself off the USB and then replug. The cleanup is handled +		 * correctly on the way out (standard USB disconnect), and the new +		 * device is detected cleanly and bound to the driver again like +		 * it should be. +		 */ +		if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) { +			bt_dev_err(hdev, "last reset failed? Not resetting again"); +			return; +		} + +		gpiod_set_value_cansleep(reset_gpio, 0); +		msleep(200); +		gpiod_set_value_cansleep(reset_gpio, 1); + +		return; +	} +  	bt_dev_err(hdev, "Multiple cmd timeouts seen. Resetting usb device.");  	/* This is not an unbalanced PM reference since the device will reset */  	err = usb_autopm_get_interface(data->intf); @@ -2200,6 +2231,23 @@ struct btmtk_section_map {  	};  } __packed; +static int btusb_set_bdaddr_mtk(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ +	struct sk_buff *skb; +	long ret; + +	skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr), bdaddr, HCI_INIT_TIMEOUT); +	if (IS_ERR(skb)) { +		ret = PTR_ERR(skb); +		bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", +			   ret); +		return ret; +	} +	kfree_skb(skb); + +	return 0; +} +  static void btusb_mtk_wmt_recv(struct urb *urb)  {  	struct hci_dev *hdev = urb->context; @@ -2804,6 +2852,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev)  	case 0x7668:  		fwname = FIRMWARE_MT7668;  		break; +	case 0x7922:  	case 0x7961:  		snprintf(fw_bin_name, sizeof(fw_bin_name),  			"mediatek/BT_RAM_CODE_MT%04x_1_%x_hdr.bin", @@ -3591,11 +3640,11 @@ static void btusb_check_needs_reset_resume(struct usb_interface *intf)  		interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;  } -static bool btusb_prevent_wake(struct hci_dev *hdev) +static bool btusb_wakeup(struct hci_dev *hdev)  {  	struct btusb_data *data = hci_get_drvdata(hdev); -	return !device_may_wakeup(&data->udev->dev); +	return device_may_wakeup(&data->udev->dev);  }  static int btusb_shutdown_qca(struct hci_dev *hdev) @@ -3752,7 +3801,7 @@ static int btusb_probe(struct usb_interface *intf,  	hdev->flush  = btusb_flush;  	hdev->send   = btusb_send_frame;  	hdev->notify = btusb_notify; -	hdev->prevent_wake = btusb_prevent_wake; +	hdev->wakeup = btusb_wakeup;  #ifdef CONFIG_PM  	err = btusb_config_oob_wake(hdev); @@ -3819,6 +3868,7 @@ static int btusb_probe(struct usb_interface *intf,  		hdev->shutdown = btusb_mtk_shutdown;  		hdev->manufacturer = 70;  		hdev->cmd_timeout = btusb_mtk_cmd_timeout; +		hdev->set_bdaddr = btusb_set_bdaddr_mtk;  		set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);  		data->recv_acl = btusb_recv_acl_mtk;  	} |