#include <linux/kernel.h>
 #include <linux/clk.h>
+#include <linux/completion.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 
 enum qca_flags {
        QCA_IBS_ENABLED,
+       QCA_DROP_VENDOR_EVENT,
 };
 
 /* HCI_IBS transmit side sleep protocol states */
        struct work_struct ws_rx_vote_off;
        struct work_struct ws_tx_vote_off;
        unsigned long flags;
+       struct completion drop_ev_comp;
 
        /* For debugging purpose */
        u64 ibs_sent_wacks;
        INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off);
 
        qca->hu = hu;
+       init_completion(&qca->drop_ev_comp);
 
        /* Assume we start with both sides asleep -- extra wakes OK */
        qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
        return hci_recv_frame(hdev, skb);
 }
 
+static int qca_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_uart *hu = hci_get_drvdata(hdev);
+       struct qca_data *qca = hu->priv;
+
+       if (test_bit(QCA_DROP_VENDOR_EVENT, &qca->flags)) {
+               struct hci_event_hdr *hdr = (void *)skb->data;
+
+               /* For the WCN3990 the vendor command for a baudrate change
+                * isn't sent as synchronous HCI command, because the
+                * controller sends the corresponding vendor event with the
+                * new baudrate. The event is received and properly decoded
+                * after changing the baudrate of the host port. It needs to
+                * be dropped, otherwise it can be misinterpreted as
+                * response to a later firmware download command (also a
+                * vendor command).
+                */
+
+               if (hdr->evt == HCI_EV_VENDOR)
+                       complete(&qca->drop_ev_comp);
+
+               kfree(skb);
+
+               return 0;
+       }
+
+       return hci_recv_frame(hdev, skb);
+}
+
 #define QCA_IBS_SLEEP_IND_EVENT \
        .type = HCI_IBS_SLEEP_IND, \
        .hlen = 0, \
 static const struct h4_recv_pkt qca_recv_pkts[] = {
        { H4_RECV_ACL,             .recv = qca_recv_acl_data },
        { H4_RECV_SCO,             .recv = hci_recv_frame    },
-       { H4_RECV_EVENT,           .recv = hci_recv_frame    },
+       { H4_RECV_EVENT,           .recv = qca_recv_event    },
        { QCA_IBS_WAKE_IND_EVENT,  .recv = qca_ibs_wake_ind  },
        { QCA_IBS_WAKE_ACK_EVENT,  .recv = qca_ibs_wake_ack  },
        { QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind },
 static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
 {
        unsigned int speed, qca_baudrate;
+       struct qca_data *qca = hu->priv;
        int ret = 0;
 
        if (speed_type == QCA_INIT_SPEED) {
                if (qca_is_wcn399x(soc_type))
                        hci_uart_set_flow_control(hu, true);
 
+               if (soc_type == QCA_WCN3990) {
+                       reinit_completion(&qca->drop_ev_comp);
+                       set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
+               }
+
                qca_baudrate = qca_get_baudrate_value(speed);
                bt_dev_dbg(hu->hdev, "Set UART speed to %d", speed);
                ret = qca_set_baudrate(hu->hdev, qca_baudrate);
 error:
                if (qca_is_wcn399x(soc_type))
                        hci_uart_set_flow_control(hu, false);
+
+               if (soc_type == QCA_WCN3990) {
+                       /* Wait for the controller to send the vendor event
+                        * for the baudrate change command.
+                        */
+                       if (!wait_for_completion_timeout(&qca->drop_ev_comp,
+                                                msecs_to_jiffies(100))) {
+                               bt_dev_err(hu->hdev,
+                                          "Failed to change controller baudrate\n");
+                               ret = -ETIMEDOUT;
+                       }
+
+                       clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
+               }
        }
 
        return ret;