#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 {
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,
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);
* 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);
* 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);
/* 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);
if (on)
msleep(100);
else
- msleep(10);
+ usleep_range(1000, 10000);
return 0;
}
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
}
}
+ clear_bit(QCA_BT_OFF, &qca->flags);
return ret;
}
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.
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)
goto out;
} else {
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)
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;
* 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);
} 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)
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);