#define BTNXPUART_CHECK_BOOT_SIGNATURE 3
 #define BTNXPUART_SERDEV_OPEN          4
 #define BTNXPUART_IR_IN_PROGRESS       5
+#define BTNXPUART_FW_DOWNLOAD_ABORT    6
 
 /* NXP HW err codes */
 #define BTNXPUART_IR_HW_ERR            0xb0
        u8 fw_name[MAX_FW_FILE_NAME_LEN];
        u32 fw_dnld_v1_offset;
        u32 fw_v1_sent_bytes;
+       u32 fw_dnld_v3_offset;
        u32 fw_v3_offset_correction;
        u32 fw_v1_expected_len;
        u32 boot_reg_offset;
        nxpdev->fw_v1_sent_bytes = 0;
        nxpdev->fw_v1_expected_len = HDR_LEN;
        nxpdev->boot_reg_offset = 0;
+       nxpdev->fw_dnld_v3_offset = 0;
        nxpdev->fw_v3_offset_correction = 0;
        nxpdev->baudrate_changed = false;
        nxpdev->timeout_changed = false;
                                               !test_bit(BTNXPUART_FW_DOWNLOADING,
                                                         &nxpdev->tx_state),
                                               msecs_to_jiffies(60000));
+
+       release_firmware(nxpdev->fw);
+       memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
+
        if (err == 0) {
-               bt_dev_err(hdev, "FW Download Timeout.");
+               bt_dev_err(hdev, "FW Download Timeout. offset: %d",
+                               nxpdev->fw_dnld_v1_offset ?
+                               nxpdev->fw_dnld_v1_offset :
+                               nxpdev->fw_dnld_v3_offset);
                return -ETIMEDOUT;
        }
+       if (test_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state)) {
+               bt_dev_err(hdev, "FW Download Aborted");
+               return -EINTR;
+       }
 
        serdev_device_set_flow_control(nxpdev->serdev, true);
-       release_firmware(nxpdev->fw);
-       memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
 
        /* Allow the downloaded FW to initialize */
        msleep(1200);
                goto free_skb;
        }
 
-       serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + offset -
-                               nxpdev->fw_v3_offset_correction, len);
+       nxpdev->fw_dnld_v3_offset = offset - nxpdev->fw_v3_offset_correction;
+       serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data +
+                               nxpdev->fw_dnld_v3_offset, len);
 
 free_skb:
        kfree_skb(skb);
        struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);
        struct hci_dev *hdev = nxpdev->hdev;
 
-       /* Restore FW baudrate to fw_init_baudrate if changed.
-        * This will ensure FW baudrate is in sync with
-        * driver baudrate in case this driver is re-inserted.
-        */
-       if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
-               nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
-               nxp_set_baudrate_cmd(hdev, NULL);
+       if (is_fw_downloading(nxpdev)) {
+               set_bit(BTNXPUART_FW_DOWNLOAD_ABORT, &nxpdev->tx_state);
+               clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
+               wake_up_interruptible(&nxpdev->check_boot_sign_wait_q);
+               wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q);
+       } else {
+               /* Restore FW baudrate to fw_init_baudrate if changed.
+                * This will ensure FW baudrate is in sync with
+                * driver baudrate in case this driver is re-inserted.
+                */
+               if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
+                       nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
+                       nxp_set_baudrate_cmd(hdev, NULL);
+               }
+               ps_cancel_timer(nxpdev);
        }
-
-       ps_cancel_timer(nxpdev);
        hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 }