Bluetooth: hci_h5: add WAKEUP_DISABLE flag
[linux-2.6-microblaze.git] / drivers / bluetooth / hci_h5.c
index 7b985c7..fd67211 100644 (file)
@@ -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 {
@@ -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,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);
@@ -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;
 }
 
@@ -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;
 }
 
@@ -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
        { },
 };