Commit 66f077dd authored by Archie Pusaka's avatar Archie Pusaka Committed by Marcel Holtmann
Browse files

Bluetooth: hci_h5: add WAKEUP_DISABLE flag



Some RTL chips resets the FW on suspend, so wakeup is disabled on
those chips. This patch introduces this WAKEUP_DISABLE flag so that
chips that doesn't reset FW on suspend can leave the flag unset and
is allowed to wake the host.

This patch also left RTL8822 WAKEUP_DISABLE flag unset, therefore
allowing it to wake the host, and preventing reprobing on resume.

Signed-off-by: default avatarArchie Pusaka <apusaka@chromium.org>
Reviewed-by: default avatarAbhishek Pandit-Subedi <abhishekpandit@chromium.org>
Reviewed-by: default avatarHilda Wu <hildawu@realtek.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 64832df2
Loading
Loading
Loading
Loading
+59 −24
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@
enum {
	H5_RX_ESC,		/* SLIP escape mode */
	H5_TX_ACK_REQ,		/* Pending ack to send */
	H5_WAKEUP_DISABLE,	/* Device cannot wake host */
};

struct h5 {
@@ -97,6 +98,10 @@ struct h5 {
	struct gpio_desc *device_wake_gpio;
};

enum h5_driver_info {
	H5_INFO_WAKEUP_DISABLE = BIT(0),
};

struct h5_vnd {
	int (*setup)(struct h5 *h5);
	void (*open)(struct h5 *h5);
@@ -106,6 +111,11 @@ struct h5_vnd {
	const struct acpi_gpio_mapping *acpi_gpio_map;
};

struct h5_device_data {
	uint32_t driver_info;
	struct h5_vnd *vnd;
};

static void h5_reset_rx(struct h5 *h5);

static void h5_link_control(struct hci_uart *hu, const void *data, size_t len)
@@ -791,6 +801,8 @@ static int h5_serdev_probe(struct serdev_device *serdev)
{
	struct device *dev = &serdev->dev;
	struct h5 *h5;
	const struct h5_device_data *data;
	int err;

	h5 = devm_kzalloc(dev, sizeof(*h5), GFP_KERNEL);
	if (!h5)
@@ -807,20 +819,19 @@ static int h5_serdev_probe(struct serdev_device *serdev)
		if (!match)
			return -ENODEV;

		h5->vnd = (const struct h5_vnd *)match->driver_data;
		data = (const struct h5_device_data *)match->driver_data;
		h5->vnd = data->vnd;
		h5->id  = (char *)match->id;

		if (h5->vnd->acpi_gpio_map)
			devm_acpi_dev_add_driver_gpios(dev,
						       h5->vnd->acpi_gpio_map);
	} else {
		const void *data;

		data = of_device_get_match_data(dev);
		if (!data)
			return -ENODEV;

		h5->vnd = (const struct h5_vnd *)data;
		h5->vnd = data->vnd;
	}


@@ -833,7 +844,14 @@ static int h5_serdev_probe(struct serdev_device *serdev)
	if (IS_ERR(h5->device_wake_gpio))
		return PTR_ERR(h5->device_wake_gpio);

	return hci_uart_register_device(&h5->serdev_hu, &h5p);
	err = hci_uart_register_device(&h5->serdev_hu, &h5p);
	if (err)
		return err;

	if (data->driver_info & H5_INFO_WAKEUP_DISABLE)
		set_bit(H5_WAKEUP_DISABLE, &h5->flags);

	return 0;
}

static void h5_serdev_remove(struct serdev_device *serdev)
@@ -921,6 +939,7 @@ static void h5_btrtl_open(struct h5 *h5)
	 * done by the hci_suspend_notifier is not necessary; it actually causes
	 * delays and a bunch of errors to get logged, so disable it.
	 */
	if (test_bit(H5_WAKEUP_DISABLE, &h5->flags))
		set_bit(HCI_UART_NO_SUSPEND_NOTIFIER, &h5->hu->flags);

	/* Devices always start with these fixed parameters */
@@ -943,14 +962,17 @@ static void h5_btrtl_close(struct h5 *h5)
/* Suspend/resume support. On many devices the RTL BT device loses power during
 * suspend/resume, causing it to lose its firmware and all state. So we simply
 * turn it off on suspend and reprobe on resume. This mirrors how RTL devices
 * are handled in the USB driver, where the USB_QUIRK_RESET_RESUME is used which
 * are handled in the USB driver, where the BTUSB_WAKEUP_DISABLE is used which
 * also causes a reprobe on resume.
 */
static int h5_btrtl_suspend(struct h5 *h5)
{
	serdev_device_set_flow_control(h5->hu->serdev, false);
	gpiod_set_value_cansleep(h5->device_wake_gpio, 0);

	if (test_bit(H5_WAKEUP_DISABLE, &h5->flags))
		gpiod_set_value_cansleep(h5->enable_gpio, 0);

	return 0;
}

@@ -976,6 +998,7 @@ static void h5_btrtl_reprobe_worker(struct work_struct *work)

static int h5_btrtl_resume(struct h5 *h5)
{
	if (test_bit(H5_WAKEUP_DISABLE, &h5->flags)) {
		struct h5_btrtl_reprobe *reprobe;

		reprobe = kzalloc(sizeof(*reprobe), GFP_KERNEL);
@@ -987,6 +1010,9 @@ static int h5_btrtl_resume(struct h5 *h5)
		INIT_WORK(&reprobe->work, h5_btrtl_reprobe_worker);
		reprobe->dev = get_device(&h5->hu->serdev->dev);
		queue_work(system_long_wq, &reprobe->work);
	} else {
		gpiod_set_value_cansleep(h5->device_wake_gpio, 1);
	}
	return 0;
}

@@ -1008,13 +1034,22 @@ static struct h5_vnd rtl_vnd = {
	.resume		= h5_btrtl_resume,
	.acpi_gpio_map	= acpi_btrtl_gpios,
};

static const struct h5_device_data h5_data_rtl8822cs = {
	.vnd = &rtl_vnd,
};

static const struct h5_device_data h5_data_rtl8723bs = {
	.driver_info = H5_INFO_WAKEUP_DISABLE,
	.vnd = &rtl_vnd,
};
#endif

#ifdef CONFIG_ACPI
static const struct acpi_device_id h5_acpi_match[] = {
#ifdef CONFIG_BT_HCIUART_RTL
	{ "OBDA0623", (kernel_ulong_t)&rtl_vnd },
	{ "OBDA8723", (kernel_ulong_t)&rtl_vnd },
	{ "OBDA0623", (kernel_ulong_t)&h5_data_rtl8723bs },
	{ "OBDA8723", (kernel_ulong_t)&h5_data_rtl8723bs },
#endif
	{ },
};
@@ -1028,11 +1063,11 @@ static const struct dev_pm_ops h5_serdev_pm_ops = {
static const struct of_device_id rtl_bluetooth_of_match[] = {
#ifdef CONFIG_BT_HCIUART_RTL
	{ .compatible = "realtek,rtl8822cs-bt",
	  .data = (const void *)&rtl_vnd },
	  .data = (const void *)&h5_data_rtl8822cs },
	{ .compatible = "realtek,rtl8723bs-bt",
	  .data = (const void *)&rtl_vnd },
	  .data = (const void *)&h5_data_rtl8723bs },
	{ .compatible = "realtek,rtl8723ds-bt",
	  .data = (const void *)&rtl_vnd },
	  .data = (const void *)&h5_data_rtl8723bs },
#endif
	{ },
};