diff options
Diffstat (limited to 'drivers/bluetooth/hci_qca.c')
-rw-r--r-- | drivers/bluetooth/hci_qca.c | 50 |
1 files changed, 30 insertions, 20 deletions
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 5e03504c4e0c..237aea34b69f 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -59,8 +59,7 @@ #define IBS_WAKE_RETRANS_TIMEOUT_MS 100 #define IBS_TX_IDLE_TIMEOUT_MS 2000 -#define BAUDRATE_SETTLE_TIMEOUT_MS 300 -#define POWER_PULSE_TRANS_TIMEOUT_MS 100 +#define CMD_TRANS_TIMEOUT_MS 100 /* susclk rate */ #define SUSCLK_RATE_32KHZ 32768 @@ -964,6 +963,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) { struct hci_uart *hu = hci_get_drvdata(hdev); struct qca_data *qca = hu->priv; + struct qca_serdev *qcadev; struct sk_buff *skb; u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 }; @@ -985,13 +985,21 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) skb_queue_tail(&qca->txq, skb); hci_uart_tx_wakeup(hu); - /* wait 300ms to change new baudrate on controller side - * controller will come back after they receive this HCI command - * then host can communicate with new baudrate to controller - */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS)); - set_current_state(TASK_RUNNING); + qcadev = serdev_device_get_drvdata(hu->serdev); + + /* Wait for the baudrate change request to be sent */ + + while (!skb_queue_empty(&qca->txq)) + usleep_range(100, 200); + + serdev_device_wait_until_sent(hu->serdev, + msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); + + /* Give the controller time to process the request */ + if (qcadev->btsoc_type == QCA_WCN3990) + msleep(10); + else + msleep(300); return 0; } @@ -1004,10 +1012,11 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) hci_uart_set_baudrate(hu, speed); } -static int qca_send_power_pulse(struct hci_uart *hu, u8 cmd) +static int qca_send_power_pulse(struct hci_uart *hu, bool on) { int ret; - int timeout = msecs_to_jiffies(POWER_PULSE_TRANS_TIMEOUT_MS); + int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); + u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE; /* These power pulses are single byte command which are sent * at required baudrate to wcn3990. On wcn3990, we have an external @@ -1030,11 +1039,14 @@ static int qca_send_power_pulse(struct hci_uart *hu, u8 cmd) } serdev_device_wait_until_sent(hu->serdev, timeout); - - /* Wait for 100 uS for SoC to settle down */ - usleep_range(100, 200); hci_uart_set_flow_control(hu, false); + /* Give to controller time to boot/shutdown */ + if (on) + msleep(100); + else + msleep(10); + return 0; } @@ -1138,18 +1150,15 @@ static int qca_wcn3990_init(struct hci_uart *hu) /* Forcefully enable wcn3990 to enter in to boot mode. */ host_set_baudrate(hu, 2400); - ret = qca_send_power_pulse(hu, QCA_WCN3990_POWEROFF_PULSE); + ret = qca_send_power_pulse(hu, false); if (ret) return ret; qca_set_speed(hu, QCA_INIT_SPEED); - ret = qca_send_power_pulse(hu, QCA_WCN3990_POWERON_PULSE); + ret = qca_send_power_pulse(hu, true); if (ret) return ret; - /* Wait for 100 ms for SoC to boot */ - msleep(100); - /* Now the device is in ready state to communicate with host. * To sync host with device we need to reopen port. * Without this, we will have RTS and CTS synchronization @@ -1192,6 +1201,7 @@ static int qca_setup(struct hci_uart *hu) * setup for every hci up. */ set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); + set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); hu->hdev->shutdown = qca_power_off; ret = qca_wcn3990_init(hu); if (ret) @@ -1289,7 +1299,7 @@ static void qca_power_shutdown(struct hci_uart *hu) spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); host_set_baudrate(hu, 2400); - qca_send_power_pulse(hu, QCA_WCN3990_POWEROFF_PULSE); + qca_send_power_pulse(hu, false); qca_power_setup(hu, false); } |