162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Bluetooth driver 462306a36Sopenharmony_ci * Copyright 2023 NXP 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/serdev.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/skbuff.h> 1362306a36Sopenharmony_ci#include <asm/unaligned.h> 1462306a36Sopenharmony_ci#include <linux/firmware.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/crc8.h> 1762306a36Sopenharmony_ci#include <linux/crc32.h> 1862306a36Sopenharmony_ci#include <linux/string_helpers.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 2162306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "h4_recv.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define MANUFACTURER_NXP 37 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define BTNXPUART_TX_STATE_ACTIVE 1 2862306a36Sopenharmony_ci#define BTNXPUART_FW_DOWNLOADING 2 2962306a36Sopenharmony_ci#define BTNXPUART_CHECK_BOOT_SIGNATURE 3 3062306a36Sopenharmony_ci#define BTNXPUART_SERDEV_OPEN 4 3162306a36Sopenharmony_ci#define BTNXPUART_IR_IN_PROGRESS 5 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* NXP HW err codes */ 3462306a36Sopenharmony_ci#define BTNXPUART_IR_HW_ERR 0xb0 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin" 3762306a36Sopenharmony_ci#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin" 3862306a36Sopenharmony_ci#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin" 3962306a36Sopenharmony_ci#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin" 4062306a36Sopenharmony_ci#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se" 4162306a36Sopenharmony_ci#define FIRMWARE_IW624 "nxp/uartiw624_bt.bin" 4262306a36Sopenharmony_ci#define FIRMWARE_SECURE_IW624 "nxp/uartiw624_bt.bin.se" 4362306a36Sopenharmony_ci#define FIRMWARE_AW693 "nxp/uartaw693_bt.bin" 4462306a36Sopenharmony_ci#define FIRMWARE_SECURE_AW693 "nxp/uartaw693_bt.bin.se" 4562306a36Sopenharmony_ci#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define CHIP_ID_W9098 0x5c03 4862306a36Sopenharmony_ci#define CHIP_ID_IW416 0x7201 4962306a36Sopenharmony_ci#define CHIP_ID_IW612 0x7601 5062306a36Sopenharmony_ci#define CHIP_ID_IW624a 0x8000 5162306a36Sopenharmony_ci#define CHIP_ID_IW624c 0x8001 5262306a36Sopenharmony_ci#define CHIP_ID_AW693 0x8200 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define FW_SECURE_MASK 0xc0 5562306a36Sopenharmony_ci#define FW_OPEN 0x00 5662306a36Sopenharmony_ci#define FW_AUTH_ILLEGAL 0x40 5762306a36Sopenharmony_ci#define FW_AUTH_PLAIN 0x80 5862306a36Sopenharmony_ci#define FW_AUTH_ENC 0xc0 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define HCI_NXP_PRI_BAUDRATE 115200 6162306a36Sopenharmony_ci#define HCI_NXP_SEC_BAUDRATE 3000000 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define MAX_FW_FILE_NAME_LEN 50 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Default ps timeout period in milliseconds */ 6662306a36Sopenharmony_ci#define PS_DEFAULT_TIMEOUT_PERIOD_MS 2000 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* wakeup methods */ 6962306a36Sopenharmony_ci#define WAKEUP_METHOD_DTR 0 7062306a36Sopenharmony_ci#define WAKEUP_METHOD_BREAK 1 7162306a36Sopenharmony_ci#define WAKEUP_METHOD_EXT_BREAK 2 7262306a36Sopenharmony_ci#define WAKEUP_METHOD_RTS 3 7362306a36Sopenharmony_ci#define WAKEUP_METHOD_INVALID 0xff 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* power save mode status */ 7662306a36Sopenharmony_ci#define PS_MODE_DISABLE 0 7762306a36Sopenharmony_ci#define PS_MODE_ENABLE 1 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* Power Save Commands to ps_work_func */ 8062306a36Sopenharmony_ci#define PS_CMD_EXIT_PS 1 8162306a36Sopenharmony_ci#define PS_CMD_ENTER_PS 2 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* power save state */ 8462306a36Sopenharmony_ci#define PS_STATE_AWAKE 0 8562306a36Sopenharmony_ci#define PS_STATE_SLEEP 1 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Bluetooth vendor command : Sleep mode */ 8862306a36Sopenharmony_ci#define HCI_NXP_AUTO_SLEEP_MODE 0xfc23 8962306a36Sopenharmony_ci/* Bluetooth vendor command : Wakeup method */ 9062306a36Sopenharmony_ci#define HCI_NXP_WAKEUP_METHOD 0xfc53 9162306a36Sopenharmony_ci/* Bluetooth vendor command : Set operational baudrate */ 9262306a36Sopenharmony_ci#define HCI_NXP_SET_OPER_SPEED 0xfc09 9362306a36Sopenharmony_ci/* Bluetooth vendor command: Independent Reset */ 9462306a36Sopenharmony_ci#define HCI_NXP_IND_RESET 0xfcfc 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Bluetooth Power State : Vendor cmd params */ 9762306a36Sopenharmony_ci#define BT_PS_ENABLE 0x02 9862306a36Sopenharmony_ci#define BT_PS_DISABLE 0x03 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Bluetooth Host Wakeup Methods */ 10162306a36Sopenharmony_ci#define BT_HOST_WAKEUP_METHOD_NONE 0x00 10262306a36Sopenharmony_ci#define BT_HOST_WAKEUP_METHOD_DTR 0x01 10362306a36Sopenharmony_ci#define BT_HOST_WAKEUP_METHOD_BREAK 0x02 10462306a36Sopenharmony_ci#define BT_HOST_WAKEUP_METHOD_GPIO 0x03 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* Bluetooth Chip Wakeup Methods */ 10762306a36Sopenharmony_ci#define BT_CTRL_WAKEUP_METHOD_DSR 0x00 10862306a36Sopenharmony_ci#define BT_CTRL_WAKEUP_METHOD_BREAK 0x01 10962306a36Sopenharmony_ci#define BT_CTRL_WAKEUP_METHOD_GPIO 0x02 11062306a36Sopenharmony_ci#define BT_CTRL_WAKEUP_METHOD_EXT_BREAK 0x04 11162306a36Sopenharmony_ci#define BT_CTRL_WAKEUP_METHOD_RTS 0x05 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistruct ps_data { 11462306a36Sopenharmony_ci u8 target_ps_mode; /* ps mode to be set */ 11562306a36Sopenharmony_ci u8 cur_psmode; /* current ps_mode */ 11662306a36Sopenharmony_ci u8 ps_state; /* controller's power save state */ 11762306a36Sopenharmony_ci u8 ps_cmd; 11862306a36Sopenharmony_ci u8 h2c_wakeupmode; 11962306a36Sopenharmony_ci u8 cur_h2c_wakeupmode; 12062306a36Sopenharmony_ci u8 c2h_wakeupmode; 12162306a36Sopenharmony_ci u8 c2h_wakeup_gpio; 12262306a36Sopenharmony_ci u8 h2c_wakeup_gpio; 12362306a36Sopenharmony_ci bool driver_sent_cmd; 12462306a36Sopenharmony_ci u16 h2c_ps_interval; 12562306a36Sopenharmony_ci u16 c2h_ps_interval; 12662306a36Sopenharmony_ci struct hci_dev *hdev; 12762306a36Sopenharmony_ci struct work_struct work; 12862306a36Sopenharmony_ci struct timer_list ps_timer; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct wakeup_cmd_payload { 13262306a36Sopenharmony_ci u8 c2h_wakeupmode; 13362306a36Sopenharmony_ci u8 c2h_wakeup_gpio; 13462306a36Sopenharmony_ci u8 h2c_wakeupmode; 13562306a36Sopenharmony_ci u8 h2c_wakeup_gpio; 13662306a36Sopenharmony_ci} __packed; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistruct psmode_cmd_payload { 13962306a36Sopenharmony_ci u8 ps_cmd; 14062306a36Sopenharmony_ci __le16 c2h_ps_interval; 14162306a36Sopenharmony_ci} __packed; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistruct btnxpuart_data { 14462306a36Sopenharmony_ci const char *helper_fw_name; 14562306a36Sopenharmony_ci const char *fw_name; 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistruct btnxpuart_dev { 14962306a36Sopenharmony_ci struct hci_dev *hdev; 15062306a36Sopenharmony_ci struct serdev_device *serdev; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci struct work_struct tx_work; 15362306a36Sopenharmony_ci unsigned long tx_state; 15462306a36Sopenharmony_ci struct sk_buff_head txq; 15562306a36Sopenharmony_ci struct sk_buff *rx_skb; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci const struct firmware *fw; 15862306a36Sopenharmony_ci u8 fw_name[MAX_FW_FILE_NAME_LEN]; 15962306a36Sopenharmony_ci u32 fw_dnld_v1_offset; 16062306a36Sopenharmony_ci u32 fw_v1_sent_bytes; 16162306a36Sopenharmony_ci u32 fw_v3_offset_correction; 16262306a36Sopenharmony_ci u32 fw_v1_expected_len; 16362306a36Sopenharmony_ci u32 boot_reg_offset; 16462306a36Sopenharmony_ci wait_queue_head_t fw_dnld_done_wait_q; 16562306a36Sopenharmony_ci wait_queue_head_t check_boot_sign_wait_q; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci u32 new_baudrate; 16862306a36Sopenharmony_ci u32 current_baudrate; 16962306a36Sopenharmony_ci u32 fw_init_baudrate; 17062306a36Sopenharmony_ci bool timeout_changed; 17162306a36Sopenharmony_ci bool baudrate_changed; 17262306a36Sopenharmony_ci bool helper_downloaded; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci struct ps_data psdata; 17562306a36Sopenharmony_ci struct btnxpuart_data *nxp_data; 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#define NXP_V1_FW_REQ_PKT 0xa5 17962306a36Sopenharmony_ci#define NXP_V1_CHIP_VER_PKT 0xaa 18062306a36Sopenharmony_ci#define NXP_V3_FW_REQ_PKT 0xa7 18162306a36Sopenharmony_ci#define NXP_V3_CHIP_VER_PKT 0xab 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci#define NXP_ACK_V1 0x5a 18462306a36Sopenharmony_ci#define NXP_NAK_V1 0xbf 18562306a36Sopenharmony_ci#define NXP_ACK_V3 0x7a 18662306a36Sopenharmony_ci#define NXP_NAK_V3 0x7b 18762306a36Sopenharmony_ci#define NXP_CRC_ERROR_V3 0x7c 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci#define HDR_LEN 16 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci#define NXP_RECV_CHIP_VER_V1 \ 19262306a36Sopenharmony_ci .type = NXP_V1_CHIP_VER_PKT, \ 19362306a36Sopenharmony_ci .hlen = 4, \ 19462306a36Sopenharmony_ci .loff = 0, \ 19562306a36Sopenharmony_ci .lsize = 0, \ 19662306a36Sopenharmony_ci .maxlen = 4 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci#define NXP_RECV_FW_REQ_V1 \ 19962306a36Sopenharmony_ci .type = NXP_V1_FW_REQ_PKT, \ 20062306a36Sopenharmony_ci .hlen = 4, \ 20162306a36Sopenharmony_ci .loff = 0, \ 20262306a36Sopenharmony_ci .lsize = 0, \ 20362306a36Sopenharmony_ci .maxlen = 4 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#define NXP_RECV_CHIP_VER_V3 \ 20662306a36Sopenharmony_ci .type = NXP_V3_CHIP_VER_PKT, \ 20762306a36Sopenharmony_ci .hlen = 4, \ 20862306a36Sopenharmony_ci .loff = 0, \ 20962306a36Sopenharmony_ci .lsize = 0, \ 21062306a36Sopenharmony_ci .maxlen = 4 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#define NXP_RECV_FW_REQ_V3 \ 21362306a36Sopenharmony_ci .type = NXP_V3_FW_REQ_PKT, \ 21462306a36Sopenharmony_ci .hlen = 9, \ 21562306a36Sopenharmony_ci .loff = 0, \ 21662306a36Sopenharmony_ci .lsize = 0, \ 21762306a36Sopenharmony_ci .maxlen = 9 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistruct v1_data_req { 22062306a36Sopenharmony_ci __le16 len; 22162306a36Sopenharmony_ci __le16 len_comp; 22262306a36Sopenharmony_ci} __packed; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistruct v1_start_ind { 22562306a36Sopenharmony_ci __le16 chip_id; 22662306a36Sopenharmony_ci __le16 chip_id_comp; 22762306a36Sopenharmony_ci} __packed; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistruct v3_data_req { 23062306a36Sopenharmony_ci __le16 len; 23162306a36Sopenharmony_ci __le32 offset; 23262306a36Sopenharmony_ci __le16 error; 23362306a36Sopenharmony_ci u8 crc; 23462306a36Sopenharmony_ci} __packed; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistruct v3_start_ind { 23762306a36Sopenharmony_ci __le16 chip_id; 23862306a36Sopenharmony_ci u8 loader_ver; 23962306a36Sopenharmony_ci u8 crc; 24062306a36Sopenharmony_ci} __packed; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* UART register addresses of BT chip */ 24362306a36Sopenharmony_ci#define CLKDIVADDR 0x7f00008f 24462306a36Sopenharmony_ci#define UARTDIVADDR 0x7f000090 24562306a36Sopenharmony_ci#define UARTMCRADDR 0x7f000091 24662306a36Sopenharmony_ci#define UARTREINITADDR 0x7f000092 24762306a36Sopenharmony_ci#define UARTICRADDR 0x7f000093 24862306a36Sopenharmony_ci#define UARTFCRADDR 0x7f000094 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci#define MCR 0x00000022 25162306a36Sopenharmony_ci#define INIT 0x00000001 25262306a36Sopenharmony_ci#define ICR 0x000000c7 25362306a36Sopenharmony_ci#define FCR 0x000000c7 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci#define POLYNOMIAL8 0x07 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistruct uart_reg { 25862306a36Sopenharmony_ci __le32 address; 25962306a36Sopenharmony_ci __le32 value; 26062306a36Sopenharmony_ci} __packed; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistruct uart_config { 26362306a36Sopenharmony_ci struct uart_reg clkdiv; 26462306a36Sopenharmony_ci struct uart_reg uartdiv; 26562306a36Sopenharmony_ci struct uart_reg mcr; 26662306a36Sopenharmony_ci struct uart_reg re_init; 26762306a36Sopenharmony_ci struct uart_reg icr; 26862306a36Sopenharmony_ci struct uart_reg fcr; 26962306a36Sopenharmony_ci __be32 crc; 27062306a36Sopenharmony_ci} __packed; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistruct nxp_bootloader_cmd { 27362306a36Sopenharmony_ci __le32 header; 27462306a36Sopenharmony_ci __le32 arg; 27562306a36Sopenharmony_ci __le32 payload_len; 27662306a36Sopenharmony_ci __be32 crc; 27762306a36Sopenharmony_ci} __packed; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic u8 crc8_table[CRC8_TABLE_SIZE]; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* Default configurations */ 28262306a36Sopenharmony_ci#define DEFAULT_H2C_WAKEUP_MODE WAKEUP_METHOD_BREAK 28362306a36Sopenharmony_ci#define DEFAULT_PS_MODE PS_MODE_DISABLE 28462306a36Sopenharmony_ci#define FW_INIT_BAUDRATE HCI_NXP_PRI_BAUDRATE 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic struct sk_buff *nxp_drv_send_cmd(struct hci_dev *hdev, u16 opcode, 28762306a36Sopenharmony_ci u32 plen, 28862306a36Sopenharmony_ci void *param) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 29162306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 29262306a36Sopenharmony_ci struct sk_buff *skb; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* set flag to prevent nxp_enqueue from parsing values from this command and 29562306a36Sopenharmony_ci * calling hci_cmd_sync_queue() again. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci psdata->driver_sent_cmd = true; 29862306a36Sopenharmony_ci skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_CMD_TIMEOUT); 29962306a36Sopenharmony_ci psdata->driver_sent_cmd = false; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return skb; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void btnxpuart_tx_wakeup(struct btnxpuart_dev *nxpdev) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci if (schedule_work(&nxpdev->tx_work)) 30762306a36Sopenharmony_ci set_bit(BTNXPUART_TX_STATE_ACTIVE, &nxpdev->tx_state); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* NXP Power Save Feature */ 31162306a36Sopenharmony_cistatic void ps_start_timer(struct btnxpuart_dev *nxpdev) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!psdata) 31662306a36Sopenharmony_ci return; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (psdata->cur_psmode == PS_MODE_ENABLE) 31962306a36Sopenharmony_ci mod_timer(&psdata->ps_timer, jiffies + msecs_to_jiffies(psdata->h2c_ps_interval)); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void ps_cancel_timer(struct btnxpuart_dev *nxpdev) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci flush_work(&psdata->work); 32762306a36Sopenharmony_ci del_timer_sync(&psdata->ps_timer); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic void ps_control(struct hci_dev *hdev, u8 ps_state) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 33362306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 33462306a36Sopenharmony_ci int status; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (psdata->ps_state == ps_state || 33762306a36Sopenharmony_ci !test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state)) 33862306a36Sopenharmony_ci return; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci switch (psdata->cur_h2c_wakeupmode) { 34162306a36Sopenharmony_ci case WAKEUP_METHOD_DTR: 34262306a36Sopenharmony_ci if (ps_state == PS_STATE_AWAKE) 34362306a36Sopenharmony_ci status = serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0); 34462306a36Sopenharmony_ci else 34562306a36Sopenharmony_ci status = serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR); 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci case WAKEUP_METHOD_BREAK: 34862306a36Sopenharmony_ci default: 34962306a36Sopenharmony_ci if (ps_state == PS_STATE_AWAKE) 35062306a36Sopenharmony_ci status = serdev_device_break_ctl(nxpdev->serdev, 0); 35162306a36Sopenharmony_ci else 35262306a36Sopenharmony_ci status = serdev_device_break_ctl(nxpdev->serdev, -1); 35362306a36Sopenharmony_ci bt_dev_dbg(hdev, "Set UART break: %s, status=%d", 35462306a36Sopenharmony_ci str_on_off(ps_state == PS_STATE_SLEEP), status); 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci if (!status) 35862306a36Sopenharmony_ci psdata->ps_state = ps_state; 35962306a36Sopenharmony_ci if (ps_state == PS_STATE_AWAKE) 36062306a36Sopenharmony_ci btnxpuart_tx_wakeup(nxpdev); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void ps_work_func(struct work_struct *work) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct ps_data *data = container_of(work, struct ps_data, work); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (data->ps_cmd == PS_CMD_ENTER_PS && data->cur_psmode == PS_MODE_ENABLE) 36862306a36Sopenharmony_ci ps_control(data->hdev, PS_STATE_SLEEP); 36962306a36Sopenharmony_ci else if (data->ps_cmd == PS_CMD_EXIT_PS) 37062306a36Sopenharmony_ci ps_control(data->hdev, PS_STATE_AWAKE); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void ps_timeout_func(struct timer_list *t) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct ps_data *data = from_timer(data, t, ps_timer); 37662306a36Sopenharmony_ci struct hci_dev *hdev = data->hdev; 37762306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (test_bit(BTNXPUART_TX_STATE_ACTIVE, &nxpdev->tx_state)) { 38062306a36Sopenharmony_ci ps_start_timer(nxpdev); 38162306a36Sopenharmony_ci } else { 38262306a36Sopenharmony_ci data->ps_cmd = PS_CMD_ENTER_PS; 38362306a36Sopenharmony_ci schedule_work(&data->work); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void ps_setup(struct hci_dev *hdev) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 39062306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci psdata->hdev = hdev; 39362306a36Sopenharmony_ci INIT_WORK(&psdata->work, ps_work_func); 39462306a36Sopenharmony_ci timer_setup(&psdata->ps_timer, ps_timeout_func, 0); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic void ps_wakeup(struct btnxpuart_dev *nxpdev) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (psdata->ps_state != PS_STATE_AWAKE) { 40262306a36Sopenharmony_ci psdata->ps_cmd = PS_CMD_EXIT_PS; 40362306a36Sopenharmony_ci schedule_work(&psdata->work); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int send_ps_cmd(struct hci_dev *hdev, void *data) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 41062306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 41162306a36Sopenharmony_ci struct psmode_cmd_payload pcmd; 41262306a36Sopenharmony_ci struct sk_buff *skb; 41362306a36Sopenharmony_ci u8 *status; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (psdata->target_ps_mode == PS_MODE_ENABLE) 41662306a36Sopenharmony_ci pcmd.ps_cmd = BT_PS_ENABLE; 41762306a36Sopenharmony_ci else 41862306a36Sopenharmony_ci pcmd.ps_cmd = BT_PS_DISABLE; 41962306a36Sopenharmony_ci pcmd.c2h_ps_interval = __cpu_to_le16(psdata->c2h_ps_interval); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci skb = nxp_drv_send_cmd(hdev, HCI_NXP_AUTO_SLEEP_MODE, sizeof(pcmd), &pcmd); 42262306a36Sopenharmony_ci if (IS_ERR(skb)) { 42362306a36Sopenharmony_ci bt_dev_err(hdev, "Setting Power Save mode failed (%ld)", PTR_ERR(skb)); 42462306a36Sopenharmony_ci return PTR_ERR(skb); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci status = skb_pull_data(skb, 1); 42862306a36Sopenharmony_ci if (status) { 42962306a36Sopenharmony_ci if (!*status) 43062306a36Sopenharmony_ci psdata->cur_psmode = psdata->target_ps_mode; 43162306a36Sopenharmony_ci else 43262306a36Sopenharmony_ci psdata->target_ps_mode = psdata->cur_psmode; 43362306a36Sopenharmony_ci if (psdata->cur_psmode == PS_MODE_ENABLE) 43462306a36Sopenharmony_ci ps_start_timer(nxpdev); 43562306a36Sopenharmony_ci else 43662306a36Sopenharmony_ci ps_wakeup(nxpdev); 43762306a36Sopenharmony_ci bt_dev_dbg(hdev, "Power Save mode response: status=%d, ps_mode=%d", 43862306a36Sopenharmony_ci *status, psdata->cur_psmode); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci kfree_skb(skb); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int send_wakeup_method_cmd(struct hci_dev *hdev, void *data) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 44862306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 44962306a36Sopenharmony_ci struct wakeup_cmd_payload pcmd; 45062306a36Sopenharmony_ci struct sk_buff *skb; 45162306a36Sopenharmony_ci u8 *status; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci pcmd.c2h_wakeupmode = psdata->c2h_wakeupmode; 45462306a36Sopenharmony_ci pcmd.c2h_wakeup_gpio = psdata->c2h_wakeup_gpio; 45562306a36Sopenharmony_ci switch (psdata->h2c_wakeupmode) { 45662306a36Sopenharmony_ci case WAKEUP_METHOD_DTR: 45762306a36Sopenharmony_ci pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_DSR; 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci case WAKEUP_METHOD_BREAK: 46062306a36Sopenharmony_ci default: 46162306a36Sopenharmony_ci pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_BREAK; 46262306a36Sopenharmony_ci break; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci pcmd.h2c_wakeup_gpio = 0xff; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd), &pcmd); 46762306a36Sopenharmony_ci if (IS_ERR(skb)) { 46862306a36Sopenharmony_ci bt_dev_err(hdev, "Setting wake-up method failed (%ld)", PTR_ERR(skb)); 46962306a36Sopenharmony_ci return PTR_ERR(skb); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci status = skb_pull_data(skb, 1); 47362306a36Sopenharmony_ci if (status) { 47462306a36Sopenharmony_ci if (*status == 0) 47562306a36Sopenharmony_ci psdata->cur_h2c_wakeupmode = psdata->h2c_wakeupmode; 47662306a36Sopenharmony_ci else 47762306a36Sopenharmony_ci psdata->h2c_wakeupmode = psdata->cur_h2c_wakeupmode; 47862306a36Sopenharmony_ci bt_dev_dbg(hdev, "Set Wakeup Method response: status=%d, h2c_wakeupmode=%d", 47962306a36Sopenharmony_ci *status, psdata->cur_h2c_wakeupmode); 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci kfree_skb(skb); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void ps_init(struct hci_dev *hdev) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 48962306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_RTS); 49262306a36Sopenharmony_ci usleep_range(5000, 10000); 49362306a36Sopenharmony_ci serdev_device_set_tiocm(nxpdev->serdev, TIOCM_RTS, 0); 49462306a36Sopenharmony_ci usleep_range(5000, 10000); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci psdata->ps_state = PS_STATE_AWAKE; 49762306a36Sopenharmony_ci psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE; 49862306a36Sopenharmony_ci psdata->c2h_wakeup_gpio = 0xff; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID; 50162306a36Sopenharmony_ci psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS; 50262306a36Sopenharmony_ci switch (DEFAULT_H2C_WAKEUP_MODE) { 50362306a36Sopenharmony_ci case WAKEUP_METHOD_DTR: 50462306a36Sopenharmony_ci psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR; 50562306a36Sopenharmony_ci serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR); 50662306a36Sopenharmony_ci serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0); 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case WAKEUP_METHOD_BREAK: 50962306a36Sopenharmony_ci default: 51062306a36Sopenharmony_ci psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK; 51162306a36Sopenharmony_ci serdev_device_break_ctl(nxpdev->serdev, -1); 51262306a36Sopenharmony_ci usleep_range(5000, 10000); 51362306a36Sopenharmony_ci serdev_device_break_ctl(nxpdev->serdev, 0); 51462306a36Sopenharmony_ci usleep_range(5000, 10000); 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci psdata->cur_psmode = PS_MODE_DISABLE; 51962306a36Sopenharmony_ci psdata->target_ps_mode = DEFAULT_PS_MODE; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode) 52262306a36Sopenharmony_ci hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL); 52362306a36Sopenharmony_ci if (psdata->cur_psmode != psdata->target_ps_mode) 52462306a36Sopenharmony_ci hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/* NXP Firmware Download Feature */ 52862306a36Sopenharmony_cistatic int nxp_download_firmware(struct hci_dev *hdev) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 53162306a36Sopenharmony_ci int err = 0; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci nxpdev->fw_dnld_v1_offset = 0; 53462306a36Sopenharmony_ci nxpdev->fw_v1_sent_bytes = 0; 53562306a36Sopenharmony_ci nxpdev->fw_v1_expected_len = HDR_LEN; 53662306a36Sopenharmony_ci nxpdev->boot_reg_offset = 0; 53762306a36Sopenharmony_ci nxpdev->fw_v3_offset_correction = 0; 53862306a36Sopenharmony_ci nxpdev->baudrate_changed = false; 53962306a36Sopenharmony_ci nxpdev->timeout_changed = false; 54062306a36Sopenharmony_ci nxpdev->helper_downloaded = false; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE); 54362306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, false); 54462306a36Sopenharmony_ci nxpdev->current_baudrate = HCI_NXP_PRI_BAUDRATE; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Wait till FW is downloaded */ 54762306a36Sopenharmony_ci err = wait_event_interruptible_timeout(nxpdev->fw_dnld_done_wait_q, 54862306a36Sopenharmony_ci !test_bit(BTNXPUART_FW_DOWNLOADING, 54962306a36Sopenharmony_ci &nxpdev->tx_state), 55062306a36Sopenharmony_ci msecs_to_jiffies(60000)); 55162306a36Sopenharmony_ci if (err == 0) { 55262306a36Sopenharmony_ci bt_dev_err(hdev, "FW Download Timeout."); 55362306a36Sopenharmony_ci return -ETIMEDOUT; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, true); 55762306a36Sopenharmony_ci release_firmware(nxpdev->fw); 55862306a36Sopenharmony_ci memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Allow the downloaded FW to initialize */ 56162306a36Sopenharmony_ci msleep(1200); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return 0; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic void nxp_send_ack(u8 ack, struct hci_dev *hdev) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 56962306a36Sopenharmony_ci u8 ack_nak[2]; 57062306a36Sopenharmony_ci int len = 1; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci ack_nak[0] = ack; 57362306a36Sopenharmony_ci if (ack == NXP_ACK_V3) { 57462306a36Sopenharmony_ci ack_nak[1] = crc8(crc8_table, ack_nak, 1, 0xff); 57562306a36Sopenharmony_ci len = 2; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci serdev_device_write_buf(nxpdev->serdev, ack_nak, len); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 58362306a36Sopenharmony_ci struct nxp_bootloader_cmd nxp_cmd5; 58462306a36Sopenharmony_ci struct uart_config uart_config; 58562306a36Sopenharmony_ci u32 clkdivaddr = CLKDIVADDR - nxpdev->boot_reg_offset; 58662306a36Sopenharmony_ci u32 uartdivaddr = UARTDIVADDR - nxpdev->boot_reg_offset; 58762306a36Sopenharmony_ci u32 uartmcraddr = UARTMCRADDR - nxpdev->boot_reg_offset; 58862306a36Sopenharmony_ci u32 uartreinitaddr = UARTREINITADDR - nxpdev->boot_reg_offset; 58962306a36Sopenharmony_ci u32 uarticraddr = UARTICRADDR - nxpdev->boot_reg_offset; 59062306a36Sopenharmony_ci u32 uartfcraddr = UARTFCRADDR - nxpdev->boot_reg_offset; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (req_len == sizeof(nxp_cmd5)) { 59362306a36Sopenharmony_ci nxp_cmd5.header = __cpu_to_le32(5); 59462306a36Sopenharmony_ci nxp_cmd5.arg = 0; 59562306a36Sopenharmony_ci nxp_cmd5.payload_len = __cpu_to_le32(sizeof(uart_config)); 59662306a36Sopenharmony_ci /* FW expects swapped CRC bytes */ 59762306a36Sopenharmony_ci nxp_cmd5.crc = __cpu_to_be32(crc32_be(0UL, (char *)&nxp_cmd5, 59862306a36Sopenharmony_ci sizeof(nxp_cmd5) - 4)); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci serdev_device_write_buf(nxpdev->serdev, (u8 *)&nxp_cmd5, sizeof(nxp_cmd5)); 60162306a36Sopenharmony_ci nxpdev->fw_v3_offset_correction += req_len; 60262306a36Sopenharmony_ci } else if (req_len == sizeof(uart_config)) { 60362306a36Sopenharmony_ci uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr); 60462306a36Sopenharmony_ci uart_config.clkdiv.value = __cpu_to_le32(0x00c00000); 60562306a36Sopenharmony_ci uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr); 60662306a36Sopenharmony_ci uart_config.uartdiv.value = __cpu_to_le32(1); 60762306a36Sopenharmony_ci uart_config.mcr.address = __cpu_to_le32(uartmcraddr); 60862306a36Sopenharmony_ci uart_config.mcr.value = __cpu_to_le32(MCR); 60962306a36Sopenharmony_ci uart_config.re_init.address = __cpu_to_le32(uartreinitaddr); 61062306a36Sopenharmony_ci uart_config.re_init.value = __cpu_to_le32(INIT); 61162306a36Sopenharmony_ci uart_config.icr.address = __cpu_to_le32(uarticraddr); 61262306a36Sopenharmony_ci uart_config.icr.value = __cpu_to_le32(ICR); 61362306a36Sopenharmony_ci uart_config.fcr.address = __cpu_to_le32(uartfcraddr); 61462306a36Sopenharmony_ci uart_config.fcr.value = __cpu_to_le32(FCR); 61562306a36Sopenharmony_ci /* FW expects swapped CRC bytes */ 61662306a36Sopenharmony_ci uart_config.crc = __cpu_to_be32(crc32_be(0UL, (char *)&uart_config, 61762306a36Sopenharmony_ci sizeof(uart_config) - 4)); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci serdev_device_write_buf(nxpdev->serdev, (u8 *)&uart_config, sizeof(uart_config)); 62062306a36Sopenharmony_ci serdev_device_wait_until_sent(nxpdev->serdev, 0); 62162306a36Sopenharmony_ci nxpdev->fw_v3_offset_correction += req_len; 62262306a36Sopenharmony_ci return true; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci return false; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic bool nxp_fw_change_timeout(struct hci_dev *hdev, u16 req_len) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 63062306a36Sopenharmony_ci struct nxp_bootloader_cmd nxp_cmd7; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (req_len != sizeof(nxp_cmd7)) 63362306a36Sopenharmony_ci return false; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci nxp_cmd7.header = __cpu_to_le32(7); 63662306a36Sopenharmony_ci nxp_cmd7.arg = __cpu_to_le32(0x70); 63762306a36Sopenharmony_ci nxp_cmd7.payload_len = 0; 63862306a36Sopenharmony_ci /* FW expects swapped CRC bytes */ 63962306a36Sopenharmony_ci nxp_cmd7.crc = __cpu_to_be32(crc32_be(0UL, (char *)&nxp_cmd7, 64062306a36Sopenharmony_ci sizeof(nxp_cmd7) - 4)); 64162306a36Sopenharmony_ci serdev_device_write_buf(nxpdev->serdev, (u8 *)&nxp_cmd7, sizeof(nxp_cmd7)); 64262306a36Sopenharmony_ci serdev_device_wait_until_sent(nxpdev->serdev, 0); 64362306a36Sopenharmony_ci nxpdev->fw_v3_offset_correction += req_len; 64462306a36Sopenharmony_ci return true; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic u32 nxp_get_data_len(const u8 *buf) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct nxp_bootloader_cmd *hdr = (struct nxp_bootloader_cmd *)buf; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return __le32_to_cpu(hdr->payload_len); 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic bool is_fw_downloading(struct btnxpuart_dev *nxpdev) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci return test_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic bool process_boot_signature(struct btnxpuart_dev *nxpdev) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci if (test_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state)) { 66262306a36Sopenharmony_ci clear_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state); 66362306a36Sopenharmony_ci wake_up_interruptible(&nxpdev->check_boot_sign_wait_q); 66462306a36Sopenharmony_ci return false; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci return is_fw_downloading(nxpdev); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic int nxp_request_firmware(struct hci_dev *hdev, const char *fw_name) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 67262306a36Sopenharmony_ci int err = 0; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (!fw_name) 67562306a36Sopenharmony_ci return -ENOENT; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (!strlen(nxpdev->fw_name)) { 67862306a36Sopenharmony_ci snprintf(nxpdev->fw_name, MAX_FW_FILE_NAME_LEN, "%s", fw_name); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci bt_dev_dbg(hdev, "Request Firmware: %s", nxpdev->fw_name); 68162306a36Sopenharmony_ci err = request_firmware(&nxpdev->fw, nxpdev->fw_name, &hdev->dev); 68262306a36Sopenharmony_ci if (err < 0) { 68362306a36Sopenharmony_ci bt_dev_err(hdev, "Firmware file %s not found", nxpdev->fw_name); 68462306a36Sopenharmony_ci clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci return err; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci/* for legacy chipsets with V1 bootloader */ 69162306a36Sopenharmony_cistatic int nxp_recv_chip_ver_v1(struct hci_dev *hdev, struct sk_buff *skb) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 69462306a36Sopenharmony_ci struct v1_start_ind *req; 69562306a36Sopenharmony_ci __u16 chip_id; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci req = skb_pull_data(skb, sizeof(*req)); 69862306a36Sopenharmony_ci if (!req) 69962306a36Sopenharmony_ci goto free_skb; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci chip_id = le16_to_cpu(req->chip_id ^ req->chip_id_comp); 70262306a36Sopenharmony_ci if (chip_id == 0xffff && nxpdev->fw_dnld_v1_offset) { 70362306a36Sopenharmony_ci nxpdev->fw_dnld_v1_offset = 0; 70462306a36Sopenharmony_ci nxpdev->fw_v1_sent_bytes = 0; 70562306a36Sopenharmony_ci nxpdev->fw_v1_expected_len = HDR_LEN; 70662306a36Sopenharmony_ci release_firmware(nxpdev->fw); 70762306a36Sopenharmony_ci memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name)); 70862306a36Sopenharmony_ci nxp_send_ack(NXP_ACK_V1, hdev); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cifree_skb: 71262306a36Sopenharmony_ci kfree_skb(skb); 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 71962306a36Sopenharmony_ci struct btnxpuart_data *nxp_data = nxpdev->nxp_data; 72062306a36Sopenharmony_ci struct v1_data_req *req; 72162306a36Sopenharmony_ci __u16 len; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (!process_boot_signature(nxpdev)) 72462306a36Sopenharmony_ci goto free_skb; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci req = skb_pull_data(skb, sizeof(*req)); 72762306a36Sopenharmony_ci if (!req) 72862306a36Sopenharmony_ci goto free_skb; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci len = __le16_to_cpu(req->len ^ req->len_comp); 73162306a36Sopenharmony_ci if (len != 0xffff) { 73262306a36Sopenharmony_ci bt_dev_dbg(hdev, "ERR: Send NAK"); 73362306a36Sopenharmony_ci nxp_send_ack(NXP_NAK_V1, hdev); 73462306a36Sopenharmony_ci goto free_skb; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci nxp_send_ack(NXP_ACK_V1, hdev); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci len = __le16_to_cpu(req->len); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (!nxp_data->helper_fw_name) { 74162306a36Sopenharmony_ci if (!nxpdev->timeout_changed) { 74262306a36Sopenharmony_ci nxpdev->timeout_changed = nxp_fw_change_timeout(hdev, 74362306a36Sopenharmony_ci len); 74462306a36Sopenharmony_ci goto free_skb; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci if (!nxpdev->baudrate_changed) { 74762306a36Sopenharmony_ci nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev, 74862306a36Sopenharmony_ci len); 74962306a36Sopenharmony_ci if (nxpdev->baudrate_changed) { 75062306a36Sopenharmony_ci serdev_device_set_baudrate(nxpdev->serdev, 75162306a36Sopenharmony_ci HCI_NXP_SEC_BAUDRATE); 75262306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, true); 75362306a36Sopenharmony_ci nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci goto free_skb; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (!nxp_data->helper_fw_name || nxpdev->helper_downloaded) { 76062306a36Sopenharmony_ci if (nxp_request_firmware(hdev, nxp_data->fw_name)) 76162306a36Sopenharmony_ci goto free_skb; 76262306a36Sopenharmony_ci } else if (nxp_data->helper_fw_name && !nxpdev->helper_downloaded) { 76362306a36Sopenharmony_ci if (nxp_request_firmware(hdev, nxp_data->helper_fw_name)) 76462306a36Sopenharmony_ci goto free_skb; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (!len) { 76862306a36Sopenharmony_ci bt_dev_dbg(hdev, "FW Downloaded Successfully: %zu bytes", 76962306a36Sopenharmony_ci nxpdev->fw->size); 77062306a36Sopenharmony_ci if (nxp_data->helper_fw_name && !nxpdev->helper_downloaded) { 77162306a36Sopenharmony_ci nxpdev->helper_downloaded = true; 77262306a36Sopenharmony_ci serdev_device_wait_until_sent(nxpdev->serdev, 0); 77362306a36Sopenharmony_ci serdev_device_set_baudrate(nxpdev->serdev, 77462306a36Sopenharmony_ci HCI_NXP_SEC_BAUDRATE); 77562306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, true); 77662306a36Sopenharmony_ci } else { 77762306a36Sopenharmony_ci clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 77862306a36Sopenharmony_ci wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci goto free_skb; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci if (len & 0x01) { 78362306a36Sopenharmony_ci /* The CRC did not match at the other end. 78462306a36Sopenharmony_ci * Simply send the same bytes again. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci len = nxpdev->fw_v1_sent_bytes; 78762306a36Sopenharmony_ci bt_dev_dbg(hdev, "CRC error. Resend %d bytes of FW.", len); 78862306a36Sopenharmony_ci } else { 78962306a36Sopenharmony_ci nxpdev->fw_dnld_v1_offset += nxpdev->fw_v1_sent_bytes; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* The FW bin file is made up of many blocks of 79262306a36Sopenharmony_ci * 16 byte header and payload data chunks. If the 79362306a36Sopenharmony_ci * FW has requested a header, read the payload length 79462306a36Sopenharmony_ci * info from the header, before sending the header. 79562306a36Sopenharmony_ci * In the next iteration, the FW should request the 79662306a36Sopenharmony_ci * payload data chunk, which should be equal to the 79762306a36Sopenharmony_ci * payload length read from header. If there is a 79862306a36Sopenharmony_ci * mismatch, clearly the driver and FW are out of sync, 79962306a36Sopenharmony_ci * and we need to re-send the previous header again. 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci if (len == nxpdev->fw_v1_expected_len) { 80262306a36Sopenharmony_ci if (len == HDR_LEN) 80362306a36Sopenharmony_ci nxpdev->fw_v1_expected_len = nxp_get_data_len(nxpdev->fw->data + 80462306a36Sopenharmony_ci nxpdev->fw_dnld_v1_offset); 80562306a36Sopenharmony_ci else 80662306a36Sopenharmony_ci nxpdev->fw_v1_expected_len = HDR_LEN; 80762306a36Sopenharmony_ci } else if (len == HDR_LEN) { 80862306a36Sopenharmony_ci /* FW download out of sync. Send previous chunk again */ 80962306a36Sopenharmony_ci nxpdev->fw_dnld_v1_offset -= nxpdev->fw_v1_sent_bytes; 81062306a36Sopenharmony_ci nxpdev->fw_v1_expected_len = HDR_LEN; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (nxpdev->fw_dnld_v1_offset + len <= nxpdev->fw->size) 81562306a36Sopenharmony_ci serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + 81662306a36Sopenharmony_ci nxpdev->fw_dnld_v1_offset, len); 81762306a36Sopenharmony_ci nxpdev->fw_v1_sent_bytes = len; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cifree_skb: 82062306a36Sopenharmony_ci kfree_skb(skb); 82162306a36Sopenharmony_ci return 0; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid, 82562306a36Sopenharmony_ci u8 loader_ver) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 82862306a36Sopenharmony_ci char *fw_name = NULL; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci switch (chipid) { 83162306a36Sopenharmony_ci case CHIP_ID_W9098: 83262306a36Sopenharmony_ci fw_name = FIRMWARE_W9098; 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci case CHIP_ID_IW416: 83562306a36Sopenharmony_ci fw_name = FIRMWARE_IW416; 83662306a36Sopenharmony_ci break; 83762306a36Sopenharmony_ci case CHIP_ID_IW612: 83862306a36Sopenharmony_ci fw_name = FIRMWARE_IW612; 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci case CHIP_ID_IW624a: 84162306a36Sopenharmony_ci case CHIP_ID_IW624c: 84262306a36Sopenharmony_ci nxpdev->boot_reg_offset = 1; 84362306a36Sopenharmony_ci if ((loader_ver & FW_SECURE_MASK) == FW_OPEN) 84462306a36Sopenharmony_ci fw_name = FIRMWARE_IW624; 84562306a36Sopenharmony_ci else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL) 84662306a36Sopenharmony_ci fw_name = FIRMWARE_SECURE_IW624; 84762306a36Sopenharmony_ci else 84862306a36Sopenharmony_ci bt_dev_err(hdev, "Illegal loader version %02x", loader_ver); 84962306a36Sopenharmony_ci break; 85062306a36Sopenharmony_ci case CHIP_ID_AW693: 85162306a36Sopenharmony_ci if ((loader_ver & FW_SECURE_MASK) == FW_OPEN) 85262306a36Sopenharmony_ci fw_name = FIRMWARE_AW693; 85362306a36Sopenharmony_ci else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL) 85462306a36Sopenharmony_ci fw_name = FIRMWARE_SECURE_AW693; 85562306a36Sopenharmony_ci else 85662306a36Sopenharmony_ci bt_dev_err(hdev, "Illegal loader version %02x", loader_ver); 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci default: 85962306a36Sopenharmony_ci bt_dev_err(hdev, "Unknown chip signature %04x", chipid); 86062306a36Sopenharmony_ci break; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci return fw_name; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int nxp_recv_chip_ver_v3(struct hci_dev *hdev, struct sk_buff *skb) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct v3_start_ind *req = skb_pull_data(skb, sizeof(*req)); 86862306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 86962306a36Sopenharmony_ci u16 chip_id; 87062306a36Sopenharmony_ci u8 loader_ver; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (!process_boot_signature(nxpdev)) 87362306a36Sopenharmony_ci goto free_skb; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci chip_id = le16_to_cpu(req->chip_id); 87662306a36Sopenharmony_ci loader_ver = req->loader_ver; 87762306a36Sopenharmony_ci if (!nxp_request_firmware(hdev, nxp_get_fw_name_from_chipid(hdev, 87862306a36Sopenharmony_ci chip_id, loader_ver))) 87962306a36Sopenharmony_ci nxp_send_ack(NXP_ACK_V3, hdev); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cifree_skb: 88262306a36Sopenharmony_ci kfree_skb(skb); 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 88962306a36Sopenharmony_ci struct v3_data_req *req; 89062306a36Sopenharmony_ci __u16 len; 89162306a36Sopenharmony_ci __u32 offset; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (!process_boot_signature(nxpdev)) 89462306a36Sopenharmony_ci goto free_skb; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci req = skb_pull_data(skb, sizeof(*req)); 89762306a36Sopenharmony_ci if (!req || !nxpdev->fw) 89862306a36Sopenharmony_ci goto free_skb; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci nxp_send_ack(NXP_ACK_V3, hdev); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci len = __le16_to_cpu(req->len); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (!nxpdev->timeout_changed) { 90562306a36Sopenharmony_ci nxpdev->timeout_changed = nxp_fw_change_timeout(hdev, len); 90662306a36Sopenharmony_ci goto free_skb; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (!nxpdev->baudrate_changed) { 91062306a36Sopenharmony_ci nxpdev->baudrate_changed = nxp_fw_change_baudrate(hdev, len); 91162306a36Sopenharmony_ci if (nxpdev->baudrate_changed) { 91262306a36Sopenharmony_ci serdev_device_set_baudrate(nxpdev->serdev, 91362306a36Sopenharmony_ci HCI_NXP_SEC_BAUDRATE); 91462306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, true); 91562306a36Sopenharmony_ci nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci goto free_skb; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (req->len == 0) { 92162306a36Sopenharmony_ci bt_dev_dbg(hdev, "FW Downloaded Successfully: %zu bytes", 92262306a36Sopenharmony_ci nxpdev->fw->size); 92362306a36Sopenharmony_ci clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 92462306a36Sopenharmony_ci wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q); 92562306a36Sopenharmony_ci goto free_skb; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci if (req->error) 92862306a36Sopenharmony_ci bt_dev_dbg(hdev, "FW Download received err 0x%02x from chip", 92962306a36Sopenharmony_ci req->error); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci offset = __le32_to_cpu(req->offset); 93262306a36Sopenharmony_ci if (offset < nxpdev->fw_v3_offset_correction) { 93362306a36Sopenharmony_ci /* This scenario should ideally never occur. But if it ever does, 93462306a36Sopenharmony_ci * FW is out of sync and needs a power cycle. 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_ci bt_dev_err(hdev, "Something went wrong during FW download"); 93762306a36Sopenharmony_ci bt_dev_err(hdev, "Please power cycle and try again"); 93862306a36Sopenharmony_ci goto free_skb; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci serdev_device_write_buf(nxpdev->serdev, nxpdev->fw->data + offset - 94262306a36Sopenharmony_ci nxpdev->fw_v3_offset_correction, len); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_cifree_skb: 94562306a36Sopenharmony_ci kfree_skb(skb); 94662306a36Sopenharmony_ci return 0; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 95262306a36Sopenharmony_ci __le32 new_baudrate = __cpu_to_le32(nxpdev->new_baudrate); 95362306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 95462306a36Sopenharmony_ci struct sk_buff *skb; 95562306a36Sopenharmony_ci u8 *status; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (!psdata) 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci skb = nxp_drv_send_cmd(hdev, HCI_NXP_SET_OPER_SPEED, 4, (u8 *)&new_baudrate); 96162306a36Sopenharmony_ci if (IS_ERR(skb)) { 96262306a36Sopenharmony_ci bt_dev_err(hdev, "Setting baudrate failed (%ld)", PTR_ERR(skb)); 96362306a36Sopenharmony_ci return PTR_ERR(skb); 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci status = (u8 *)skb_pull_data(skb, 1); 96762306a36Sopenharmony_ci if (status) { 96862306a36Sopenharmony_ci if (*status == 0) { 96962306a36Sopenharmony_ci serdev_device_set_baudrate(nxpdev->serdev, nxpdev->new_baudrate); 97062306a36Sopenharmony_ci nxpdev->current_baudrate = nxpdev->new_baudrate; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci bt_dev_dbg(hdev, "Set baudrate response: status=%d, baudrate=%d", 97362306a36Sopenharmony_ci *status, nxpdev->new_baudrate); 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci kfree_skb(skb); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return 0; 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE); 98362306a36Sopenharmony_ci if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) 98462306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, false); 98562306a36Sopenharmony_ci else 98662306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, true); 98762306a36Sopenharmony_ci set_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci return wait_event_interruptible_timeout(nxpdev->check_boot_sign_wait_q, 99062306a36Sopenharmony_ci !test_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, 99162306a36Sopenharmony_ci &nxpdev->tx_state), 99262306a36Sopenharmony_ci msecs_to_jiffies(1000)); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic int nxp_set_ind_reset(struct hci_dev *hdev, void *data) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR, 99862306a36Sopenharmony_ci 0x01, BTNXPUART_IR_HW_ERR }; 99962306a36Sopenharmony_ci struct sk_buff *skb; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci skb = bt_skb_alloc(3, GFP_ATOMIC); 100262306a36Sopenharmony_ci if (!skb) 100362306a36Sopenharmony_ci return -ENOMEM; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci hci_skb_pkt_type(skb) = HCI_EVENT_PKT; 100662306a36Sopenharmony_ci skb_put_data(skb, ir_hw_err, 3); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* Inject Hardware Error to upper stack */ 100962306a36Sopenharmony_ci return hci_recv_frame(hdev, skb); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci/* NXP protocol */ 101362306a36Sopenharmony_cistatic int nxp_setup(struct hci_dev *hdev) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 101662306a36Sopenharmony_ci int err = 0; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (nxp_check_boot_sign(nxpdev)) { 101962306a36Sopenharmony_ci bt_dev_dbg(hdev, "Need FW Download."); 102062306a36Sopenharmony_ci err = nxp_download_firmware(hdev); 102162306a36Sopenharmony_ci if (err < 0) 102262306a36Sopenharmony_ci return err; 102362306a36Sopenharmony_ci } else { 102462306a36Sopenharmony_ci bt_dev_dbg(hdev, "FW already running."); 102562306a36Sopenharmony_ci clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate); 102962306a36Sopenharmony_ci nxpdev->current_baudrate = nxpdev->fw_init_baudrate; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) { 103262306a36Sopenharmony_ci nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE; 103362306a36Sopenharmony_ci hci_cmd_sync_queue(hdev, nxp_set_baudrate_cmd, NULL, NULL); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci ps_init(hdev); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) 103962306a36Sopenharmony_ci hci_dev_clear_flag(hdev, HCI_SETUP); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci return 0; 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic void nxp_hw_err(struct hci_dev *hdev, u8 code) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci switch (code) { 104962306a36Sopenharmony_ci case BTNXPUART_IR_HW_ERR: 105062306a36Sopenharmony_ci set_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state); 105162306a36Sopenharmony_ci hci_dev_set_flag(hdev, HCI_SETUP); 105262306a36Sopenharmony_ci break; 105362306a36Sopenharmony_ci default: 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic int nxp_shutdown(struct hci_dev *hdev) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 106162306a36Sopenharmony_ci struct sk_buff *skb; 106262306a36Sopenharmony_ci u8 *status; 106362306a36Sopenharmony_ci u8 pcmd = 0; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) { 106662306a36Sopenharmony_ci skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd); 106762306a36Sopenharmony_ci if (IS_ERR(skb)) 106862306a36Sopenharmony_ci return PTR_ERR(skb); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci status = skb_pull_data(skb, 1); 107162306a36Sopenharmony_ci if (status) { 107262306a36Sopenharmony_ci serdev_device_set_flow_control(nxpdev->serdev, false); 107362306a36Sopenharmony_ci set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci kfree_skb(skb); 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci return 0; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic int btnxpuart_queue_skb(struct hci_dev *hdev, struct sk_buff *skb) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* Prepend skb with frame type */ 108662306a36Sopenharmony_ci memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1); 108762306a36Sopenharmony_ci skb_queue_tail(&nxpdev->txq, skb); 108862306a36Sopenharmony_ci btnxpuart_tx_wakeup(nxpdev); 108962306a36Sopenharmony_ci return 0; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic int nxp_enqueue(struct hci_dev *hdev, struct sk_buff *skb) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 109562306a36Sopenharmony_ci struct ps_data *psdata = &nxpdev->psdata; 109662306a36Sopenharmony_ci struct hci_command_hdr *hdr; 109762306a36Sopenharmony_ci struct psmode_cmd_payload ps_parm; 109862306a36Sopenharmony_ci struct wakeup_cmd_payload wakeup_parm; 109962306a36Sopenharmony_ci __le32 baudrate_parm; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci /* if vendor commands are received from user space (e.g. hcitool), update 110262306a36Sopenharmony_ci * driver flags accordingly and ask driver to re-send the command to FW. 110362306a36Sopenharmony_ci * In case the payload for any command does not match expected payload 110462306a36Sopenharmony_ci * length, let the firmware and user space program handle it, or throw 110562306a36Sopenharmony_ci * an error. 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ci if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT && !psdata->driver_sent_cmd) { 110862306a36Sopenharmony_ci hdr = (struct hci_command_hdr *)skb->data; 110962306a36Sopenharmony_ci if (hdr->plen != (skb->len - HCI_COMMAND_HDR_SIZE)) 111062306a36Sopenharmony_ci return btnxpuart_queue_skb(hdev, skb); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci switch (__le16_to_cpu(hdr->opcode)) { 111362306a36Sopenharmony_ci case HCI_NXP_AUTO_SLEEP_MODE: 111462306a36Sopenharmony_ci if (hdr->plen == sizeof(ps_parm)) { 111562306a36Sopenharmony_ci memcpy(&ps_parm, skb->data + HCI_COMMAND_HDR_SIZE, hdr->plen); 111662306a36Sopenharmony_ci if (ps_parm.ps_cmd == BT_PS_ENABLE) 111762306a36Sopenharmony_ci psdata->target_ps_mode = PS_MODE_ENABLE; 111862306a36Sopenharmony_ci else if (ps_parm.ps_cmd == BT_PS_DISABLE) 111962306a36Sopenharmony_ci psdata->target_ps_mode = PS_MODE_DISABLE; 112062306a36Sopenharmony_ci psdata->c2h_ps_interval = __le16_to_cpu(ps_parm.c2h_ps_interval); 112162306a36Sopenharmony_ci hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL); 112262306a36Sopenharmony_ci goto free_skb; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci break; 112562306a36Sopenharmony_ci case HCI_NXP_WAKEUP_METHOD: 112662306a36Sopenharmony_ci if (hdr->plen == sizeof(wakeup_parm)) { 112762306a36Sopenharmony_ci memcpy(&wakeup_parm, skb->data + HCI_COMMAND_HDR_SIZE, hdr->plen); 112862306a36Sopenharmony_ci psdata->c2h_wakeupmode = wakeup_parm.c2h_wakeupmode; 112962306a36Sopenharmony_ci psdata->c2h_wakeup_gpio = wakeup_parm.c2h_wakeup_gpio; 113062306a36Sopenharmony_ci psdata->h2c_wakeup_gpio = wakeup_parm.h2c_wakeup_gpio; 113162306a36Sopenharmony_ci switch (wakeup_parm.h2c_wakeupmode) { 113262306a36Sopenharmony_ci case BT_CTRL_WAKEUP_METHOD_DSR: 113362306a36Sopenharmony_ci psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR; 113462306a36Sopenharmony_ci break; 113562306a36Sopenharmony_ci case BT_CTRL_WAKEUP_METHOD_BREAK: 113662306a36Sopenharmony_ci default: 113762306a36Sopenharmony_ci psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK; 113862306a36Sopenharmony_ci break; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL); 114162306a36Sopenharmony_ci goto free_skb; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci break; 114462306a36Sopenharmony_ci case HCI_NXP_SET_OPER_SPEED: 114562306a36Sopenharmony_ci if (hdr->plen == sizeof(baudrate_parm)) { 114662306a36Sopenharmony_ci memcpy(&baudrate_parm, skb->data + HCI_COMMAND_HDR_SIZE, hdr->plen); 114762306a36Sopenharmony_ci nxpdev->new_baudrate = __le32_to_cpu(baudrate_parm); 114862306a36Sopenharmony_ci hci_cmd_sync_queue(hdev, nxp_set_baudrate_cmd, NULL, NULL); 114962306a36Sopenharmony_ci goto free_skb; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci break; 115262306a36Sopenharmony_ci case HCI_NXP_IND_RESET: 115362306a36Sopenharmony_ci if (hdr->plen == 1) { 115462306a36Sopenharmony_ci hci_cmd_sync_queue(hdev, nxp_set_ind_reset, NULL, NULL); 115562306a36Sopenharmony_ci goto free_skb; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci default: 115962306a36Sopenharmony_ci break; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci return btnxpuart_queue_skb(hdev, skb); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cifree_skb: 116662306a36Sopenharmony_ci kfree_skb(skb); 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic struct sk_buff *nxp_dequeue(void *data) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = (struct btnxpuart_dev *)data; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci ps_wakeup(nxpdev); 117562306a36Sopenharmony_ci ps_start_timer(nxpdev); 117662306a36Sopenharmony_ci return skb_dequeue(&nxpdev->txq); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci/* btnxpuart based on serdev */ 118062306a36Sopenharmony_cistatic void btnxpuart_tx_work(struct work_struct *work) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = container_of(work, struct btnxpuart_dev, 118362306a36Sopenharmony_ci tx_work); 118462306a36Sopenharmony_ci struct serdev_device *serdev = nxpdev->serdev; 118562306a36Sopenharmony_ci struct hci_dev *hdev = nxpdev->hdev; 118662306a36Sopenharmony_ci struct sk_buff *skb; 118762306a36Sopenharmony_ci int len; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci while ((skb = nxp_dequeue(nxpdev))) { 119062306a36Sopenharmony_ci len = serdev_device_write_buf(serdev, skb->data, skb->len); 119162306a36Sopenharmony_ci hdev->stat.byte_tx += len; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci skb_pull(skb, len); 119462306a36Sopenharmony_ci if (skb->len > 0) { 119562306a36Sopenharmony_ci skb_queue_head(&nxpdev->txq, skb); 119662306a36Sopenharmony_ci break; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci switch (hci_skb_pkt_type(skb)) { 120062306a36Sopenharmony_ci case HCI_COMMAND_PKT: 120162306a36Sopenharmony_ci hdev->stat.cmd_tx++; 120262306a36Sopenharmony_ci break; 120362306a36Sopenharmony_ci case HCI_ACLDATA_PKT: 120462306a36Sopenharmony_ci hdev->stat.acl_tx++; 120562306a36Sopenharmony_ci break; 120662306a36Sopenharmony_ci case HCI_SCODATA_PKT: 120762306a36Sopenharmony_ci hdev->stat.sco_tx++; 120862306a36Sopenharmony_ci break; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci kfree_skb(skb); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci clear_bit(BTNXPUART_TX_STATE_ACTIVE, &nxpdev->tx_state); 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic int btnxpuart_open(struct hci_dev *hdev) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 121962306a36Sopenharmony_ci int err = 0; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci err = serdev_device_open(nxpdev->serdev); 122262306a36Sopenharmony_ci if (err) { 122362306a36Sopenharmony_ci bt_dev_err(hdev, "Unable to open UART device %s", 122462306a36Sopenharmony_ci dev_name(&nxpdev->serdev->dev)); 122562306a36Sopenharmony_ci } else { 122662306a36Sopenharmony_ci set_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state); 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci return err; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int btnxpuart_close(struct hci_dev *hdev) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci ps_wakeup(nxpdev); 123662306a36Sopenharmony_ci serdev_device_close(nxpdev->serdev); 123762306a36Sopenharmony_ci skb_queue_purge(&nxpdev->txq); 123862306a36Sopenharmony_ci kfree_skb(nxpdev->rx_skb); 123962306a36Sopenharmony_ci nxpdev->rx_skb = NULL; 124062306a36Sopenharmony_ci clear_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state); 124162306a36Sopenharmony_ci return 0; 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic int btnxpuart_flush(struct hci_dev *hdev) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* Flush any pending characters */ 124962306a36Sopenharmony_ci serdev_device_write_flush(nxpdev->serdev); 125062306a36Sopenharmony_ci skb_queue_purge(&nxpdev->txq); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci cancel_work_sync(&nxpdev->tx_work); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci kfree_skb(nxpdev->rx_skb); 125562306a36Sopenharmony_ci nxpdev->rx_skb = NULL; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci return 0; 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic const struct h4_recv_pkt nxp_recv_pkts[] = { 126162306a36Sopenharmony_ci { H4_RECV_ACL, .recv = hci_recv_frame }, 126262306a36Sopenharmony_ci { H4_RECV_SCO, .recv = hci_recv_frame }, 126362306a36Sopenharmony_ci { H4_RECV_EVENT, .recv = hci_recv_frame }, 126462306a36Sopenharmony_ci { NXP_RECV_CHIP_VER_V1, .recv = nxp_recv_chip_ver_v1 }, 126562306a36Sopenharmony_ci { NXP_RECV_FW_REQ_V1, .recv = nxp_recv_fw_req_v1 }, 126662306a36Sopenharmony_ci { NXP_RECV_CHIP_VER_V3, .recv = nxp_recv_chip_ver_v3 }, 126762306a36Sopenharmony_ci { NXP_RECV_FW_REQ_V3, .recv = nxp_recv_fw_req_v3 }, 126862306a36Sopenharmony_ci}; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data, 127162306a36Sopenharmony_ci size_t count) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci ps_start_timer(nxpdev); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci nxpdev->rx_skb = h4_recv_buf(nxpdev->hdev, nxpdev->rx_skb, data, count, 127862306a36Sopenharmony_ci nxp_recv_pkts, ARRAY_SIZE(nxp_recv_pkts)); 127962306a36Sopenharmony_ci if (IS_ERR(nxpdev->rx_skb)) { 128062306a36Sopenharmony_ci int err = PTR_ERR(nxpdev->rx_skb); 128162306a36Sopenharmony_ci /* Safe to ignore out-of-sync bootloader signatures */ 128262306a36Sopenharmony_ci if (!is_fw_downloading(nxpdev)) 128362306a36Sopenharmony_ci bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err); 128462306a36Sopenharmony_ci nxpdev->rx_skb = NULL; 128562306a36Sopenharmony_ci return count; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci if (!is_fw_downloading(nxpdev)) 128862306a36Sopenharmony_ci nxpdev->hdev->stat.byte_rx += count; 128962306a36Sopenharmony_ci return count; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic void btnxpuart_write_wakeup(struct serdev_device *serdev) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci serdev_device_write_wakeup(serdev); 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic const struct serdev_device_ops btnxpuart_client_ops = { 129862306a36Sopenharmony_ci .receive_buf = btnxpuart_receive_buf, 129962306a36Sopenharmony_ci .write_wakeup = btnxpuart_write_wakeup, 130062306a36Sopenharmony_ci}; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cistatic int nxp_serdev_probe(struct serdev_device *serdev) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci struct hci_dev *hdev; 130562306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL); 130862306a36Sopenharmony_ci if (!nxpdev) 130962306a36Sopenharmony_ci return -ENOMEM; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci nxpdev->nxp_data = (struct btnxpuart_data *)device_get_match_data(&serdev->dev); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci nxpdev->serdev = serdev; 131462306a36Sopenharmony_ci serdev_device_set_drvdata(serdev, nxpdev); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci serdev_device_set_client_ops(serdev, &btnxpuart_client_ops); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci INIT_WORK(&nxpdev->tx_work, btnxpuart_tx_work); 131962306a36Sopenharmony_ci skb_queue_head_init(&nxpdev->txq); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q); 132262306a36Sopenharmony_ci init_waitqueue_head(&nxpdev->check_boot_sign_wait_q); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate", 132562306a36Sopenharmony_ci &nxpdev->fw_init_baudrate); 132662306a36Sopenharmony_ci if (!nxpdev->fw_init_baudrate) 132762306a36Sopenharmony_ci nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci crc8_populate_msb(crc8_table, POLYNOMIAL8); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci /* Initialize and register HCI device */ 133462306a36Sopenharmony_ci hdev = hci_alloc_dev(); 133562306a36Sopenharmony_ci if (!hdev) { 133662306a36Sopenharmony_ci dev_err(&serdev->dev, "Can't allocate HCI device\n"); 133762306a36Sopenharmony_ci return -ENOMEM; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci nxpdev->hdev = hdev; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci hdev->bus = HCI_UART; 134362306a36Sopenharmony_ci hci_set_drvdata(hdev, nxpdev); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci hdev->manufacturer = MANUFACTURER_NXP; 134662306a36Sopenharmony_ci hdev->open = btnxpuart_open; 134762306a36Sopenharmony_ci hdev->close = btnxpuart_close; 134862306a36Sopenharmony_ci hdev->flush = btnxpuart_flush; 134962306a36Sopenharmony_ci hdev->setup = nxp_setup; 135062306a36Sopenharmony_ci hdev->send = nxp_enqueue; 135162306a36Sopenharmony_ci hdev->hw_error = nxp_hw_err; 135262306a36Sopenharmony_ci hdev->shutdown = nxp_shutdown; 135362306a36Sopenharmony_ci SET_HCIDEV_DEV(hdev, &serdev->dev); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci if (hci_register_dev(hdev) < 0) { 135662306a36Sopenharmony_ci dev_err(&serdev->dev, "Can't register HCI device\n"); 135762306a36Sopenharmony_ci hci_free_dev(hdev); 135862306a36Sopenharmony_ci return -ENODEV; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci ps_setup(hdev); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci return 0; 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic void nxp_serdev_remove(struct serdev_device *serdev) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); 136962306a36Sopenharmony_ci struct hci_dev *hdev = nxpdev->hdev; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* Restore FW baudrate to fw_init_baudrate if changed. 137262306a36Sopenharmony_ci * This will ensure FW baudrate is in sync with 137362306a36Sopenharmony_ci * driver baudrate in case this driver is re-inserted. 137462306a36Sopenharmony_ci */ 137562306a36Sopenharmony_ci if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) { 137662306a36Sopenharmony_ci nxpdev->new_baudrate = nxpdev->fw_init_baudrate; 137762306a36Sopenharmony_ci nxp_set_baudrate_cmd(hdev, NULL); 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci ps_cancel_timer(nxpdev); 138162306a36Sopenharmony_ci hci_unregister_dev(hdev); 138262306a36Sopenharmony_ci hci_free_dev(hdev); 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic struct btnxpuart_data w8987_data __maybe_unused = { 138662306a36Sopenharmony_ci .helper_fw_name = NULL, 138762306a36Sopenharmony_ci .fw_name = FIRMWARE_W8987, 138862306a36Sopenharmony_ci}; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_cistatic struct btnxpuart_data w8997_data __maybe_unused = { 139162306a36Sopenharmony_ci .helper_fw_name = FIRMWARE_HELPER, 139262306a36Sopenharmony_ci .fw_name = FIRMWARE_W8997, 139362306a36Sopenharmony_ci}; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_cistatic const struct of_device_id nxpuart_of_match_table[] __maybe_unused = { 139662306a36Sopenharmony_ci { .compatible = "nxp,88w8987-bt", .data = &w8987_data }, 139762306a36Sopenharmony_ci { .compatible = "nxp,88w8997-bt", .data = &w8997_data }, 139862306a36Sopenharmony_ci { } 139962306a36Sopenharmony_ci}; 140062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, nxpuart_of_match_table); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic struct serdev_device_driver nxp_serdev_driver = { 140362306a36Sopenharmony_ci .probe = nxp_serdev_probe, 140462306a36Sopenharmony_ci .remove = nxp_serdev_remove, 140562306a36Sopenharmony_ci .driver = { 140662306a36Sopenharmony_ci .name = "btnxpuart", 140762306a36Sopenharmony_ci .of_match_table = of_match_ptr(nxpuart_of_match_table), 140862306a36Sopenharmony_ci }, 140962306a36Sopenharmony_ci}; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_cimodule_serdev_device_driver(nxp_serdev_driver); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ciMODULE_AUTHOR("Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>"); 141462306a36Sopenharmony_ciMODULE_DESCRIPTION("NXP Bluetooth Serial driver"); 141562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1416