Skip to content

Commit

Permalink
Bluetooth: hci_h5: add WAKEUP_DISABLE flag
Browse files Browse the repository at this point in the history
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: Archie Pusaka <[email protected]>
Reviewed-by: Abhishek Pandit-Subedi <[email protected]>
Reviewed-by: Hilda Wu <[email protected]>
Signed-off-by: Marcel Holtmann <[email protected]>
  • Loading branch information
apusaka authored and holtmann committed Jul 23, 2021
1 parent 64832df commit 66f077d
Showing 1 changed file with 59 additions and 24 deletions.
83 changes: 59 additions & 24 deletions drivers/bluetooth/hci_h5.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@

/* H5 state flags */
enum {
H5_RX_ESC, /* SLIP escape mode */
H5_TX_ACK_REQ, /* Pending ack to send */
H5_RX_ESC, /* SLIP escape mode */
H5_TX_ACK_REQ, /* Pending ack to send */
H5_WAKEUP_DISABLE, /* Device cannot wake host */
};

struct h5 {
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}


Expand All @@ -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)
Expand Down Expand Up @@ -921,7 +939,8 @@ 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.
*/
set_bit(HCI_UART_NO_SUSPEND_NOTIFIER, &h5->hu->flags);
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 */
serdev_device_set_flow_control(h5->hu->serdev, false);
Expand All @@ -942,15 +961,18 @@ 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
* turn it off on suspend and reprobe on resume. This mirrors how RTL devices
* 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);
gpiod_set_value_cansleep(h5->enable_gpio, 0);

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

return 0;
}

Expand All @@ -976,17 +998,21 @@ static void h5_btrtl_reprobe_worker(struct work_struct *work)

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

reprobe = kzalloc(sizeof(*reprobe), GFP_KERNEL);
if (!reprobe)
return -ENOMEM;
reprobe = kzalloc(sizeof(*reprobe), GFP_KERNEL);
if (!reprobe)
return -ENOMEM;

__module_get(THIS_MODULE);
__module_get(THIS_MODULE);

INIT_WORK(&reprobe->work, h5_btrtl_reprobe_worker);
reprobe->dev = get_device(&h5->hu->serdev->dev);
queue_work(system_long_wq, &reprobe->work);
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;
}

Expand All @@ -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
{ },
};
Expand All @@ -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
{ },
};
Expand Down

0 comments on commit 66f077d

Please sign in to comment.