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