Merge tag 'gcc-plugins-v5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / bluetooth / hci_qca.c
index 244b8fe..4a96368 100644 (file)
@@ -50,6 +50,8 @@
 #define IBS_HOST_TX_IDLE_TIMEOUT_MS    2000
 #define CMD_TRANS_TIMEOUT_MS           100
 #define MEMDUMP_TIMEOUT_MS             8000
+#define IBS_DISABLE_SSR_TIMEOUT_MS     (MEMDUMP_TIMEOUT_MS + 1000)
+#define FW_DOWNLOAD_TIMEOUT_MS         3000
 
 /* susclk rate */
 #define SUSCLK_RATE_32KHZ      32768
 #define QCA_MEMDUMP_BYTE               0xFB
 
 enum qca_flags {
-       QCA_IBS_ENABLED,
+       QCA_IBS_DISABLED,
        QCA_DROP_VENDOR_EVENT,
        QCA_SUSPENDING,
        QCA_MEMDUMP_COLLECTION,
        QCA_HW_ERROR_EVENT,
-       QCA_SSR_TRIGGERED
+       QCA_SSR_TRIGGERED,
+       QCA_BT_OFF
 };
 
 enum qca_capabilities {
        QCA_CAP_WIDEBAND_SPEECH = BIT(0),
+       QCA_CAP_VALID_LE_STATES = BIT(1),
 };
 
 /* HCI_IBS transmit side sleep protocol states */
@@ -630,7 +634,7 @@ static void qca_debugfs_init(struct hci_dev *hdev)
        ibs_dir = debugfs_create_dir("ibs", hdev->debugfs);
 
        /* read only */
-       mode = S_IRUGO;
+       mode = 0444;
        debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state);
        debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state);
        debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir,
@@ -657,7 +661,7 @@ static void qca_debugfs_init(struct hci_dev *hdev)
        debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms);
 
        /* read/write */
-       mode = S_IRUGO | S_IWUSR;
+       mode = 0644;
        debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans);
        debugfs_create_u32("tx_idle_delay", mode, ibs_dir,
                           &qca->tx_idle_delay);
@@ -869,7 +873,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
         * Out-Of-Band(GPIOs control) sleep is selected.
         * Don't wake the device up when suspending.
         */
-       if (!test_bit(QCA_IBS_ENABLED, &qca->flags) ||
+       if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
            test_bit(QCA_SUSPENDING, &qca->flags)) {
                skb_queue_tail(&qca->txq, skb);
                spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
@@ -1014,7 +1018,7 @@ static void qca_controller_memdump(struct work_struct *work)
                         * the controller to send the dump is 8 seconds. let us
                         * start timer to handle this asynchronous activity.
                         */
-                       clear_bit(QCA_IBS_ENABLED, &qca->flags);
+                       set_bit(QCA_IBS_DISABLED, &qca->flags);
                        set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
                        dump = (void *) skb->data;
                        dump_size = __le32_to_cpu(dump->dump_size);
@@ -1301,7 +1305,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
 
        /* Give the controller time to process the request */
        if (qca_is_wcn399x(qca_soc_type(hu)))
-               msleep(10);
+               usleep_range(1000, 10000);
        else
                msleep(300);
 
@@ -1349,7 +1353,7 @@ static int qca_send_power_pulse(struct hci_uart *hu, bool on)
        if (on)
                msleep(100);
        else
-               msleep(10);
+               usleep_range(1000, 10000);
 
        return 0;
 }
@@ -1618,6 +1622,7 @@ static int qca_power_on(struct hci_dev *hdev)
        struct hci_uart *hu = hci_get_drvdata(hdev);
        enum qca_btsoc_type soc_type = qca_soc_type(hu);
        struct qca_serdev *qcadev;
+       struct qca_data *qca = hu->priv;
        int ret = 0;
 
        /* Non-serdev device usually is powered by external power
@@ -1637,6 +1642,7 @@ static int qca_power_on(struct hci_dev *hdev)
                }
        }
 
+       clear_bit(QCA_BT_OFF, &qca->flags);
        return ret;
 }
 
@@ -1649,14 +1655,14 @@ static int qca_setup(struct hci_uart *hu)
        enum qca_btsoc_type soc_type = qca_soc_type(hu);
        const char *firmware_name = qca_get_firmware_name(hu);
        int ret;
-       int soc_ver = 0;
+       struct qca_btsoc_version ver;
 
        ret = qca_check_speeds(hu);
        if (ret)
                return ret;
 
        /* Patch downloading has to be done without IBS mode */
-       clear_bit(QCA_IBS_ENABLED, &qca->flags);
+       set_bit(QCA_IBS_DISABLED, &qca->flags);
 
        /* Enable controller to do both LE scan and BR/EDR inquiry
         * simultaneously.
@@ -1671,16 +1677,16 @@ static int qca_setup(struct hci_uart *hu)
 retry:
        ret = qca_power_on(hdev);
        if (ret)
-               return ret;
+               goto out;
 
        clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
 
        if (qca_is_wcn399x(soc_type)) {
                set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
 
-               ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
+               ret = qca_read_soc_version(hdev, &ver, soc_type);
                if (ret)
-                       return ret;
+                       goto out;
        } else {
                qca_set_speed(hu, QCA_INIT_SPEED);
        }
@@ -1690,24 +1696,23 @@ retry:
        if (speed) {
                ret = qca_set_speed(hu, QCA_OPER_SPEED);
                if (ret)
-                       return ret;
+                       goto out;
 
                qca_baudrate = qca_get_baudrate_value(speed);
        }
 
        if (!qca_is_wcn399x(soc_type)) {
                /* Get QCA version information */
-               ret = qca_read_soc_version(hdev, &soc_ver, soc_type);
+               ret = qca_read_soc_version(hdev, &ver, soc_type);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
-       bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
        /* Setup patch / NVM configurations */
-       ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver,
+       ret = qca_uart_setup(hdev, qca_baudrate, soc_type, ver,
                        firmware_name);
        if (!ret) {
-               set_bit(QCA_IBS_ENABLED, &qca->flags);
+               clear_bit(QCA_IBS_DISABLED, &qca->flags);
                qca_debugfs_init(hdev);
                hu->hdev->hw_error = qca_hw_error;
                hu->hdev->cmd_timeout = qca_cmd_timeout;
@@ -1720,20 +1725,22 @@ retry:
                 * patch/nvm-config is found, so run with original fw/config.
                 */
                ret = 0;
-       } else {
-               if (retries < MAX_INIT_RETRIES) {
-                       qca_power_shutdown(hu);
-                       if (hu->serdev) {
-                               serdev_device_close(hu->serdev);
-                               ret = serdev_device_open(hu->serdev);
-                               if (ret) {
-                                       bt_dev_err(hdev, "failed to open port");
-                                       return ret;
-                               }
+       }
+
+out:
+       if (ret && retries < MAX_INIT_RETRIES) {
+               bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
+               qca_power_shutdown(hu);
+               if (hu->serdev) {
+                       serdev_device_close(hu->serdev);
+                       ret = serdev_device_open(hu->serdev);
+                       if (ret) {
+                               bt_dev_err(hdev, "failed to open port");
+                               return ret;
                        }
-                       retries++;
-                       goto retry;
                }
+               retries++;
+               goto retry;
        }
 
        /* Setup bdaddr */
@@ -1780,7 +1787,7 @@ static const struct qca_device_data qca_soc_data_wcn3991 = {
                { "vddch0", 450000 },
        },
        .num_vregs = 4,
-       .capabilities = QCA_CAP_WIDEBAND_SPEECH,
+       .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
 };
 
 static const struct qca_device_data qca_soc_data_wcn3998 = {
@@ -1813,7 +1820,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
         * data in skb's.
         */
        spin_lock_irqsave(&qca->hci_ibs_lock, flags);
-       clear_bit(QCA_IBS_ENABLED, &qca->flags);
+       set_bit(QCA_IBS_DISABLED, &qca->flags);
        qca_flush(hu);
        spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
 
@@ -1830,6 +1837,8 @@ static void qca_power_shutdown(struct hci_uart *hu)
        } else if (qcadev->bt_en) {
                gpiod_set_value_cansleep(qcadev->bt_en, 0);
        }
+
+       set_bit(QCA_BT_OFF, &qca->flags);
 }
 
 static int qca_power_off(struct hci_dev *hdev)
@@ -2017,11 +2026,17 @@ static int qca_serdev_probe(struct serdev_device *serdev)
                hdev->shutdown = qca_power_off;
        }
 
-       /* Wideband speech support must be set per driver since it can't be
-        * queried via hci.
-        */
-       if (data && (data->capabilities & QCA_CAP_WIDEBAND_SPEECH))
-               set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
+       if (data) {
+               /* Wideband speech support must be set per driver since it can't
+                * be queried via hci. Same with the valid le states quirk.
+                */
+               if (data->capabilities & QCA_CAP_WIDEBAND_SPEECH)
+                       set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
+                               &hdev->quirks);
+
+               if (data->capabilities & QCA_CAP_VALID_LE_STATES)
+                       set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
+       }
 
        return 0;
 }
@@ -2081,11 +2096,34 @@ static int __maybe_unused qca_suspend(struct device *dev)
        bool tx_pending = false;
        int ret = 0;
        u8 cmd;
+       u32 wait_timeout = 0;
 
        set_bit(QCA_SUSPENDING, &qca->flags);
 
-       /* Device is downloading patch or doesn't support in-band sleep. */
-       if (!test_bit(QCA_IBS_ENABLED, &qca->flags))
+       if (test_bit(QCA_BT_OFF, &qca->flags))
+               return 0;
+
+       if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
+               wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
+                                       IBS_DISABLE_SSR_TIMEOUT_MS :
+                                       FW_DOWNLOAD_TIMEOUT_MS;
+
+               /* QCA_IBS_DISABLED flag is set to true, During FW download
+                * and during memory dump collection. It is reset to false,
+                * After FW download complete and after memory dump collections.
+                */
+               wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
+                           TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
+
+               if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
+                       bt_dev_err(hu->hdev, "SSR or FW download time out");
+                       ret = -ETIMEDOUT;
+                       goto error;
+               }
+       }
+
+       /* After memory dump collection, Controller is powered off.*/
+       if (test_bit(QCA_BT_OFF, &qca->flags))
                return 0;
 
        cancel_work_sync(&qca->ws_awake_device);