162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * I2C Link Layer for PN544 HCI based Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012  Intel Corporation. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/crc-ccitt.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/i2c.h>
1362306a36Sopenharmony_ci#include <linux/acpi.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/nfc.h>
1762306a36Sopenharmony_ci#include <linux/firmware.h>
1862306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <asm/unaligned.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <net/nfc/hci.h>
2362306a36Sopenharmony_ci#include <net/nfc/llc.h>
2462306a36Sopenharmony_ci#include <net/nfc/nfc.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "pn544.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define PN544_I2C_FRAME_HEADROOM 1
2962306a36Sopenharmony_ci#define PN544_I2C_FRAME_TAILROOM 2
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* GPIO names */
3262306a36Sopenharmony_ci#define PN544_GPIO_NAME_IRQ "pn544_irq"
3362306a36Sopenharmony_ci#define PN544_GPIO_NAME_FW  "pn544_fw"
3462306a36Sopenharmony_ci#define PN544_GPIO_NAME_EN  "pn544_en"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* framing in HCI mode */
3762306a36Sopenharmony_ci#define PN544_HCI_I2C_LLC_LEN		1
3862306a36Sopenharmony_ci#define PN544_HCI_I2C_LLC_CRC		2
3962306a36Sopenharmony_ci#define PN544_HCI_I2C_LLC_LEN_CRC	(PN544_HCI_I2C_LLC_LEN + \
4062306a36Sopenharmony_ci					 PN544_HCI_I2C_LLC_CRC)
4162306a36Sopenharmony_ci#define PN544_HCI_I2C_LLC_MIN_SIZE	(1 + PN544_HCI_I2C_LLC_LEN_CRC)
4262306a36Sopenharmony_ci#define PN544_HCI_I2C_LLC_MAX_PAYLOAD	29
4362306a36Sopenharmony_ci#define PN544_HCI_I2C_LLC_MAX_SIZE	(PN544_HCI_I2C_LLC_LEN_CRC + 1 + \
4462306a36Sopenharmony_ci					 PN544_HCI_I2C_LLC_MAX_PAYLOAD)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic const struct i2c_device_id pn544_hci_i2c_id_table[] = {
4762306a36Sopenharmony_ci	{"pn544", 0},
4862306a36Sopenharmony_ci	{}
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const struct acpi_device_id pn544_hci_i2c_acpi_match[] __maybe_unused = {
5462306a36Sopenharmony_ci	{"NXP5440", 0},
5562306a36Sopenharmony_ci	{}
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, pn544_hci_i2c_acpi_match);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * Exposed through the 4 most significant bytes
6462306a36Sopenharmony_ci * from the HCI SW_VERSION first byte, a.k.a.
6562306a36Sopenharmony_ci * SW RomLib.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_ci#define PN544_HW_VARIANT_C2 0xa
6862306a36Sopenharmony_ci#define PN544_HW_VARIANT_C3 0xb
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define PN544_FW_CMD_RESET 0x01
7162306a36Sopenharmony_ci#define PN544_FW_CMD_WRITE 0x08
7262306a36Sopenharmony_ci#define PN544_FW_CMD_CHECK 0x06
7362306a36Sopenharmony_ci#define PN544_FW_CMD_SECURE_WRITE 0x0C
7462306a36Sopenharmony_ci#define PN544_FW_CMD_SECURE_CHUNK_WRITE 0x0D
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistruct pn544_i2c_fw_frame_write {
7762306a36Sopenharmony_ci	u8 cmd;
7862306a36Sopenharmony_ci	u16 be_length;
7962306a36Sopenharmony_ci	u8 be_dest_addr[3];
8062306a36Sopenharmony_ci	u16 be_datalen;
8162306a36Sopenharmony_ci	u8 data[];
8262306a36Sopenharmony_ci} __packed;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct pn544_i2c_fw_frame_check {
8562306a36Sopenharmony_ci	u8 cmd;
8662306a36Sopenharmony_ci	u16 be_length;
8762306a36Sopenharmony_ci	u8 be_start_addr[3];
8862306a36Sopenharmony_ci	u16 be_datalen;
8962306a36Sopenharmony_ci	u16 be_crc;
9062306a36Sopenharmony_ci} __packed;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistruct pn544_i2c_fw_frame_response {
9362306a36Sopenharmony_ci	u8 status;
9462306a36Sopenharmony_ci	u16 be_length;
9562306a36Sopenharmony_ci} __packed;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistruct pn544_i2c_fw_blob {
9862306a36Sopenharmony_ci	u32 be_size;
9962306a36Sopenharmony_ci	u32 be_destaddr;
10062306a36Sopenharmony_ci	u8 data[];
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistruct pn544_i2c_fw_secure_frame {
10462306a36Sopenharmony_ci	u8 cmd;
10562306a36Sopenharmony_ci	u16 be_datalen;
10662306a36Sopenharmony_ci	u8 data[];
10762306a36Sopenharmony_ci} __packed;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistruct pn544_i2c_fw_secure_blob {
11062306a36Sopenharmony_ci	u64 header;
11162306a36Sopenharmony_ci	u8 data[];
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_TIMEOUT 0x01
11562306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_BAD_CRC 0x02
11662306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08
11762306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B
11862306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11
11962306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND 0x13
12062306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18
12162306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR 0x19
12262306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR 0x1D
12362306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_MEMORY_ERROR 0x20
12462306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_CHUNK_OK 0x21
12562306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74
12662306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_COMMAND_REJECTED 0xE0
12762306a36Sopenharmony_ci#define PN544_FW_CMD_RESULT_CHUNK_ERROR 0xE6
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci#define PN544_FW_WRITE_BUFFER_MAX_LEN 0x9f7
13262306a36Sopenharmony_ci#define PN544_FW_I2C_MAX_PAYLOAD PN544_HCI_I2C_LLC_MAX_SIZE
13362306a36Sopenharmony_ci#define PN544_FW_I2C_WRITE_FRAME_HEADER_LEN 8
13462306a36Sopenharmony_ci#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\
13562306a36Sopenharmony_ci					 PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\
13662306a36Sopenharmony_ci					 PN544_FW_WRITE_BUFFER_MAX_LEN)
13762306a36Sopenharmony_ci#define PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN 3
13862306a36Sopenharmony_ci#define PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN (PN544_FW_I2C_MAX_PAYLOAD -\
13962306a36Sopenharmony_ci			PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN)
14062306a36Sopenharmony_ci#define PN544_FW_SECURE_FRAME_HEADER_LEN 3
14162306a36Sopenharmony_ci#define PN544_FW_SECURE_BLOB_HEADER_LEN 8
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define FW_WORK_STATE_IDLE 1
14462306a36Sopenharmony_ci#define FW_WORK_STATE_START 2
14562306a36Sopenharmony_ci#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3
14662306a36Sopenharmony_ci#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4
14762306a36Sopenharmony_ci#define FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER 5
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistruct pn544_i2c_phy {
15062306a36Sopenharmony_ci	struct i2c_client *i2c_dev;
15162306a36Sopenharmony_ci	struct nfc_hci_dev *hdev;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	struct gpio_desc *gpiod_en;
15462306a36Sopenharmony_ci	struct gpio_desc *gpiod_fw;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	unsigned int en_polarity;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	u8 hw_variant;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	struct work_struct fw_work;
16162306a36Sopenharmony_ci	int fw_work_state;
16262306a36Sopenharmony_ci	char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
16362306a36Sopenharmony_ci	const struct firmware *fw;
16462306a36Sopenharmony_ci	u32 fw_blob_dest_addr;
16562306a36Sopenharmony_ci	size_t fw_blob_size;
16662306a36Sopenharmony_ci	const u8 *fw_blob_data;
16762306a36Sopenharmony_ci	size_t fw_written;
16862306a36Sopenharmony_ci	size_t fw_size;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	int fw_cmd_result;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	int powered;
17362306a36Sopenharmony_ci	int run_mode;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	int hard_fault;		/*
17662306a36Sopenharmony_ci				 * < 0 if hardware error occured (e.g. i2c err)
17762306a36Sopenharmony_ci				 * and prevents normal operation.
17862306a36Sopenharmony_ci				 */
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define I2C_DUMP_SKB(info, skb)					\
18262306a36Sopenharmony_cido {								\
18362306a36Sopenharmony_ci	pr_debug("%s:\n", info);				\
18462306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET,	\
18562306a36Sopenharmony_ci		       16, 1, (skb)->data, (skb)->len, 0);	\
18662306a36Sopenharmony_ci} while (0)
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	int polarity, retry, ret;
19162306a36Sopenharmony_ci	static const char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 };
19262306a36Sopenharmony_ci	int count = sizeof(rset_cmd);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* Disable fw download */
19762306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_fw, 0);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	for (polarity = 0; polarity < 2; polarity++) {
20062306a36Sopenharmony_ci		phy->en_polarity = polarity;
20162306a36Sopenharmony_ci		retry = 3;
20262306a36Sopenharmony_ci		while (retry--) {
20362306a36Sopenharmony_ci			/* power off */
20462306a36Sopenharmony_ci			gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
20562306a36Sopenharmony_ci			usleep_range(10000, 15000);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci			/* power on */
20862306a36Sopenharmony_ci			gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity);
20962306a36Sopenharmony_ci			usleep_range(10000, 15000);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci			/* send reset */
21262306a36Sopenharmony_ci			dev_dbg(&phy->i2c_dev->dev, "Sending reset cmd\n");
21362306a36Sopenharmony_ci			ret = i2c_master_send(phy->i2c_dev, rset_cmd, count);
21462306a36Sopenharmony_ci			if (ret == count) {
21562306a36Sopenharmony_ci				nfc_info(&phy->i2c_dev->dev,
21662306a36Sopenharmony_ci					 "nfc_en polarity : active %s\n",
21762306a36Sopenharmony_ci					 (polarity == 0 ? "low" : "high"));
21862306a36Sopenharmony_ci				goto out;
21962306a36Sopenharmony_ci			}
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	nfc_err(&phy->i2c_dev->dev,
22462306a36Sopenharmony_ci		"Could not detect nfc_en polarity, fallback to active high\n");
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ciout:
22762306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
22862306a36Sopenharmony_ci	usleep_range(10000, 15000);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_fw, run_mode == PN544_FW_MODE ? 1 : 0);
23462306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity);
23562306a36Sopenharmony_ci	usleep_range(10000, 15000);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	phy->run_mode = run_mode;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic int pn544_hci_i2c_enable(void *phy_id)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct pn544_i2c_phy *phy = phy_id;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	pn544_hci_i2c_enable_mode(phy, PN544_HCI_MODE);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	phy->powered = 1;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return 0;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic void pn544_hci_i2c_disable(void *phy_id)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct pn544_i2c_phy *phy = phy_id;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_fw, 0);
25662306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
25762306a36Sopenharmony_ci	usleep_range(10000, 15000);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity);
26062306a36Sopenharmony_ci	usleep_range(10000, 15000);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity);
26362306a36Sopenharmony_ci	usleep_range(10000, 15000);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	phy->powered = 0;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic void pn544_hci_i2c_add_len_crc(struct sk_buff *skb)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	u16 crc;
27162306a36Sopenharmony_ci	int len;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	len = skb->len + 2;
27462306a36Sopenharmony_ci	*(u8 *)skb_push(skb, 1) = len;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	crc = crc_ccitt(0xffff, skb->data, skb->len);
27762306a36Sopenharmony_ci	crc = ~crc;
27862306a36Sopenharmony_ci	skb_put_u8(skb, crc & 0xff);
27962306a36Sopenharmony_ci	skb_put_u8(skb, crc >> 8);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic void pn544_hci_i2c_remove_len_crc(struct sk_buff *skb)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	skb_pull(skb, PN544_I2C_FRAME_HEADROOM);
28562306a36Sopenharmony_ci	skb_trim(skb, PN544_I2C_FRAME_TAILROOM);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci/*
28962306a36Sopenharmony_ci * Writing a frame must not return the number of written bytes.
29062306a36Sopenharmony_ci * It must return either zero for success, or <0 for error.
29162306a36Sopenharmony_ci * In addition, it must not alter the skb
29262306a36Sopenharmony_ci */
29362306a36Sopenharmony_cistatic int pn544_hci_i2c_write(void *phy_id, struct sk_buff *skb)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	int r;
29662306a36Sopenharmony_ci	struct pn544_i2c_phy *phy = phy_id;
29762306a36Sopenharmony_ci	struct i2c_client *client = phy->i2c_dev;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (phy->hard_fault != 0)
30062306a36Sopenharmony_ci		return phy->hard_fault;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	usleep_range(3000, 6000);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	pn544_hci_i2c_add_len_crc(skb);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	I2C_DUMP_SKB("i2c frame written", skb);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	r = i2c_master_send(client, skb->data, skb->len);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (r == -EREMOTEIO) {	/* Retry, chip was in standby */
31162306a36Sopenharmony_ci		usleep_range(6000, 10000);
31262306a36Sopenharmony_ci		r = i2c_master_send(client, skb->data, skb->len);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (r >= 0) {
31662306a36Sopenharmony_ci		if (r != skb->len)
31762306a36Sopenharmony_ci			r = -EREMOTEIO;
31862306a36Sopenharmony_ci		else
31962306a36Sopenharmony_ci			r = 0;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	pn544_hci_i2c_remove_len_crc(skb);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	return r;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic int check_crc(u8 *buf, int buflen)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	int len;
33062306a36Sopenharmony_ci	u16 crc;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	len = buf[0] + 1;
33362306a36Sopenharmony_ci	crc = crc_ccitt(0xffff, buf, len - 2);
33462306a36Sopenharmony_ci	crc = ~crc;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) {
33762306a36Sopenharmony_ci		pr_err("CRC error 0x%x != 0x%x 0x%x\n",
33862306a36Sopenharmony_ci		       crc, buf[len - 1], buf[len - 2]);
33962306a36Sopenharmony_ci		pr_info("%s: BAD CRC\n", __func__);
34062306a36Sopenharmony_ci		print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
34162306a36Sopenharmony_ci			       16, 2, buf, buflen, false);
34262306a36Sopenharmony_ci		return -EPERM;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	return 0;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci/*
34862306a36Sopenharmony_ci * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees
34962306a36Sopenharmony_ci * that i2c bus will be flushed and that next read will start on a new frame.
35062306a36Sopenharmony_ci * returned skb contains only LLC header and payload.
35162306a36Sopenharmony_ci * returns:
35262306a36Sopenharmony_ci * -EREMOTEIO : i2c read error (fatal)
35362306a36Sopenharmony_ci * -EBADMSG : frame was incorrect and discarded
35462306a36Sopenharmony_ci * -ENOMEM : cannot allocate skb, frame dropped
35562306a36Sopenharmony_ci */
35662306a36Sopenharmony_cistatic int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	int r;
35962306a36Sopenharmony_ci	u8 len;
36062306a36Sopenharmony_ci	u8 tmp[PN544_HCI_I2C_LLC_MAX_SIZE - 1];
36162306a36Sopenharmony_ci	struct i2c_client *client = phy->i2c_dev;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	r = i2c_master_recv(client, &len, 1);
36462306a36Sopenharmony_ci	if (r != 1) {
36562306a36Sopenharmony_ci		nfc_err(&client->dev, "cannot read len byte\n");
36662306a36Sopenharmony_ci		return -EREMOTEIO;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if ((len < (PN544_HCI_I2C_LLC_MIN_SIZE - 1)) ||
37062306a36Sopenharmony_ci	    (len > (PN544_HCI_I2C_LLC_MAX_SIZE - 1))) {
37162306a36Sopenharmony_ci		nfc_err(&client->dev, "invalid len byte\n");
37262306a36Sopenharmony_ci		r = -EBADMSG;
37362306a36Sopenharmony_ci		goto flush;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	*skb = alloc_skb(1 + len, GFP_KERNEL);
37762306a36Sopenharmony_ci	if (*skb == NULL) {
37862306a36Sopenharmony_ci		r = -ENOMEM;
37962306a36Sopenharmony_ci		goto flush;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	skb_put_u8(*skb, len);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	r = i2c_master_recv(client, skb_put(*skb, len), len);
38562306a36Sopenharmony_ci	if (r != len) {
38662306a36Sopenharmony_ci		kfree_skb(*skb);
38762306a36Sopenharmony_ci		return -EREMOTEIO;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	I2C_DUMP_SKB("i2c frame read", *skb);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	r = check_crc((*skb)->data, (*skb)->len);
39362306a36Sopenharmony_ci	if (r != 0) {
39462306a36Sopenharmony_ci		kfree_skb(*skb);
39562306a36Sopenharmony_ci		r = -EBADMSG;
39662306a36Sopenharmony_ci		goto flush;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	skb_pull(*skb, 1);
40062306a36Sopenharmony_ci	skb_trim(*skb, (*skb)->len - 2);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	usleep_range(3000, 6000);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ciflush:
40762306a36Sopenharmony_ci	if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
40862306a36Sopenharmony_ci		r = -EREMOTEIO;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	usleep_range(3000, 6000);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return r;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	int r;
41862306a36Sopenharmony_ci	struct pn544_i2c_fw_frame_response response;
41962306a36Sopenharmony_ci	struct i2c_client *client = phy->i2c_dev;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	r = i2c_master_recv(client, (char *) &response, sizeof(response));
42262306a36Sopenharmony_ci	if (r != sizeof(response)) {
42362306a36Sopenharmony_ci		nfc_err(&client->dev, "cannot read fw status\n");
42462306a36Sopenharmony_ci		return -EIO;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	usleep_range(3000, 6000);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	switch (response.status) {
43062306a36Sopenharmony_ci	case 0:
43162306a36Sopenharmony_ci		return 0;
43262306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_CHUNK_OK:
43362306a36Sopenharmony_ci		return response.status;
43462306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_TIMEOUT:
43562306a36Sopenharmony_ci		return -ETIMEDOUT;
43662306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_BAD_CRC:
43762306a36Sopenharmony_ci		return -ENODATA;
43862306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_ACCESS_DENIED:
43962306a36Sopenharmony_ci		return -EACCES;
44062306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_PROTOCOL_ERROR:
44162306a36Sopenharmony_ci		return -EPROTO;
44262306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_INVALID_PARAMETER:
44362306a36Sopenharmony_ci		return -EINVAL;
44462306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND:
44562306a36Sopenharmony_ci		return -ENOTSUPP;
44662306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_INVALID_LENGTH:
44762306a36Sopenharmony_ci		return -EBADMSG;
44862306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR:
44962306a36Sopenharmony_ci		return -ENOKEY;
45062306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR:
45162306a36Sopenharmony_ci		return -EINVAL;
45262306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_MEMORY_ERROR:
45362306a36Sopenharmony_ci		return -ENOMEM;
45462306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_COMMAND_REJECTED:
45562306a36Sopenharmony_ci		return -EACCES;
45662306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_WRITE_FAILED:
45762306a36Sopenharmony_ci	case PN544_FW_CMD_RESULT_CHUNK_ERROR:
45862306a36Sopenharmony_ci		return -EIO;
45962306a36Sopenharmony_ci	default:
46062306a36Sopenharmony_ci		return -EIO;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci/*
46562306a36Sopenharmony_ci * Reads an shdlc frame from the chip. This is not as straightforward as it
46662306a36Sopenharmony_ci * seems. There are cases where we could loose the frame start synchronization.
46762306a36Sopenharmony_ci * The frame format is len-data-crc, and corruption can occur anywhere while
46862306a36Sopenharmony_ci * transiting on i2c bus, such that we could read an invalid len.
46962306a36Sopenharmony_ci * In order to recover synchronization with the next frame, we must be sure
47062306a36Sopenharmony_ci * to read the real amount of data without using the len byte. We do this by
47162306a36Sopenharmony_ci * assuming the following:
47262306a36Sopenharmony_ci * - the chip will always present only one single complete frame on the bus
47362306a36Sopenharmony_ci *   before triggering the interrupt
47462306a36Sopenharmony_ci * - the chip will not present a new frame until we have completely read
47562306a36Sopenharmony_ci *   the previous one (or until we have handled the interrupt).
47662306a36Sopenharmony_ci * The tricky case is when we read a corrupted len that is less than the real
47762306a36Sopenharmony_ci * len. We must detect this here in order to determine that we need to flush
47862306a36Sopenharmony_ci * the bus. This is the reason why we check the crc here.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_cistatic irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct pn544_i2c_phy *phy = phy_id;
48362306a36Sopenharmony_ci	struct i2c_client *client;
48462306a36Sopenharmony_ci	struct sk_buff *skb = NULL;
48562306a36Sopenharmony_ci	int r;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (!phy || irq != phy->i2c_dev->irq) {
48862306a36Sopenharmony_ci		WARN_ON_ONCE(1);
48962306a36Sopenharmony_ci		return IRQ_NONE;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	client = phy->i2c_dev;
49362306a36Sopenharmony_ci	dev_dbg(&client->dev, "IRQ\n");
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (phy->hard_fault != 0)
49662306a36Sopenharmony_ci		return IRQ_HANDLED;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (phy->run_mode == PN544_FW_MODE) {
49962306a36Sopenharmony_ci		phy->fw_cmd_result = pn544_hci_i2c_fw_read_status(phy);
50062306a36Sopenharmony_ci		schedule_work(&phy->fw_work);
50162306a36Sopenharmony_ci	} else {
50262306a36Sopenharmony_ci		r = pn544_hci_i2c_read(phy, &skb);
50362306a36Sopenharmony_ci		if (r == -EREMOTEIO) {
50462306a36Sopenharmony_ci			phy->hard_fault = r;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci			nfc_hci_recv_frame(phy->hdev, NULL);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci			return IRQ_HANDLED;
50962306a36Sopenharmony_ci		} else if ((r == -ENOMEM) || (r == -EBADMSG)) {
51062306a36Sopenharmony_ci			return IRQ_HANDLED;
51162306a36Sopenharmony_ci		}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		nfc_hci_recv_frame(phy->hdev, skb);
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	return IRQ_HANDLED;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic const struct nfc_phy_ops i2c_phy_ops = {
51962306a36Sopenharmony_ci	.write = pn544_hci_i2c_write,
52062306a36Sopenharmony_ci	.enable = pn544_hci_i2c_enable,
52162306a36Sopenharmony_ci	.disable = pn544_hci_i2c_disable,
52262306a36Sopenharmony_ci};
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name,
52562306a36Sopenharmony_ci					u8 hw_variant)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct pn544_i2c_phy *phy = phy_id;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	pr_info("Starting Firmware Download (%s)\n", firmware_name);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	strcpy(phy->firmware_name, firmware_name);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	phy->hw_variant = hw_variant;
53462306a36Sopenharmony_ci	phy->fw_work_state = FW_WORK_STATE_START;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	schedule_work(&phy->fw_work);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic void pn544_hci_i2c_fw_work_complete(struct pn544_i2c_phy *phy,
54262306a36Sopenharmony_ci					   int result)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	pr_info("Firmware Download Complete, result=%d\n", result);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	pn544_hci_i2c_disable(phy);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	phy->fw_work_state = FW_WORK_STATE_IDLE;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	if (phy->fw) {
55162306a36Sopenharmony_ci		release_firmware(phy->fw);
55262306a36Sopenharmony_ci		phy->fw = NULL;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	nfc_fw_download_done(phy->hdev->ndev, phy->firmware_name, (u32) -result);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic int pn544_hci_i2c_fw_write_cmd(struct i2c_client *client, u32 dest_addr,
55962306a36Sopenharmony_ci				      const u8 *data, u16 datalen)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	u8 frame[PN544_FW_I2C_MAX_PAYLOAD];
56262306a36Sopenharmony_ci	struct pn544_i2c_fw_frame_write *framep;
56362306a36Sopenharmony_ci	u16 params_len;
56462306a36Sopenharmony_ci	int framelen;
56562306a36Sopenharmony_ci	int r;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (datalen > PN544_FW_I2C_WRITE_DATA_MAX_LEN)
56862306a36Sopenharmony_ci		datalen = PN544_FW_I2C_WRITE_DATA_MAX_LEN;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	framep = (struct pn544_i2c_fw_frame_write *) frame;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	params_len = sizeof(framep->be_dest_addr) +
57362306a36Sopenharmony_ci		     sizeof(framep->be_datalen) + datalen;
57462306a36Sopenharmony_ci	framelen = params_len + sizeof(framep->cmd) +
57562306a36Sopenharmony_ci			     sizeof(framep->be_length);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	framep->cmd = PN544_FW_CMD_WRITE;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	put_unaligned_be16(params_len, &framep->be_length);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	framep->be_dest_addr[0] = (dest_addr & 0xff0000) >> 16;
58262306a36Sopenharmony_ci	framep->be_dest_addr[1] = (dest_addr & 0xff00) >> 8;
58362306a36Sopenharmony_ci	framep->be_dest_addr[2] = dest_addr & 0xff;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	put_unaligned_be16(datalen, &framep->be_datalen);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	memcpy(framep->data, data, datalen);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	r = i2c_master_send(client, frame, framelen);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (r == framelen)
59262306a36Sopenharmony_ci		return datalen;
59362306a36Sopenharmony_ci	else if (r < 0)
59462306a36Sopenharmony_ci		return r;
59562306a36Sopenharmony_ci	else
59662306a36Sopenharmony_ci		return -EIO;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_cistatic int pn544_hci_i2c_fw_check_cmd(struct i2c_client *client, u32 start_addr,
60062306a36Sopenharmony_ci				      const u8 *data, u16 datalen)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	struct pn544_i2c_fw_frame_check frame;
60362306a36Sopenharmony_ci	int r;
60462306a36Sopenharmony_ci	u16 crc;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/* calculate local crc for the data we want to check */
60762306a36Sopenharmony_ci	crc = crc_ccitt(0xffff, data, datalen);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	frame.cmd = PN544_FW_CMD_CHECK;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	put_unaligned_be16(sizeof(frame.be_start_addr) +
61262306a36Sopenharmony_ci			   sizeof(frame.be_datalen) + sizeof(frame.be_crc),
61362306a36Sopenharmony_ci			   &frame.be_length);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* tell the chip the memory region to which our crc applies */
61662306a36Sopenharmony_ci	frame.be_start_addr[0] = (start_addr & 0xff0000) >> 16;
61762306a36Sopenharmony_ci	frame.be_start_addr[1] = (start_addr & 0xff00) >> 8;
61862306a36Sopenharmony_ci	frame.be_start_addr[2] = start_addr & 0xff;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	put_unaligned_be16(datalen, &frame.be_datalen);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/*
62362306a36Sopenharmony_ci	 * and give our local crc. Chip will calculate its own crc for the
62462306a36Sopenharmony_ci	 * region and compare with ours.
62562306a36Sopenharmony_ci	 */
62662306a36Sopenharmony_ci	put_unaligned_be16(crc, &frame.be_crc);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	r = i2c_master_send(client, (const char *) &frame, sizeof(frame));
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (r == sizeof(frame))
63162306a36Sopenharmony_ci		return 0;
63262306a36Sopenharmony_ci	else if (r < 0)
63362306a36Sopenharmony_ci		return r;
63462306a36Sopenharmony_ci	else
63562306a36Sopenharmony_ci		return -EIO;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic int pn544_hci_i2c_fw_write_chunk(struct pn544_i2c_phy *phy)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	int r;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	r = pn544_hci_i2c_fw_write_cmd(phy->i2c_dev,
64362306a36Sopenharmony_ci				       phy->fw_blob_dest_addr + phy->fw_written,
64462306a36Sopenharmony_ci				       phy->fw_blob_data + phy->fw_written,
64562306a36Sopenharmony_ci				       phy->fw_blob_size - phy->fw_written);
64662306a36Sopenharmony_ci	if (r < 0)
64762306a36Sopenharmony_ci		return r;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	phy->fw_written += r;
65062306a36Sopenharmony_ci	phy->fw_work_state = FW_WORK_STATE_WAIT_WRITE_ANSWER;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	return 0;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic int pn544_hci_i2c_fw_secure_write_frame_cmd(struct pn544_i2c_phy *phy,
65662306a36Sopenharmony_ci					const u8 *data, u16 datalen)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	u8 buf[PN544_FW_I2C_MAX_PAYLOAD];
65962306a36Sopenharmony_ci	struct pn544_i2c_fw_secure_frame *chunk;
66062306a36Sopenharmony_ci	int chunklen;
66162306a36Sopenharmony_ci	int r;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	if (datalen > PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN)
66462306a36Sopenharmony_ci		datalen = PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	chunk = (struct pn544_i2c_fw_secure_frame *) buf;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	chunk->cmd = PN544_FW_CMD_SECURE_CHUNK_WRITE;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	put_unaligned_be16(datalen, &chunk->be_datalen);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	memcpy(chunk->data, data, datalen);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	chunklen = sizeof(chunk->cmd) + sizeof(chunk->be_datalen) + datalen;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	r = i2c_master_send(phy->i2c_dev, buf, chunklen);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (r == chunklen)
67962306a36Sopenharmony_ci		return datalen;
68062306a36Sopenharmony_ci	else if (r < 0)
68162306a36Sopenharmony_ci		return r;
68262306a36Sopenharmony_ci	else
68362306a36Sopenharmony_ci		return -EIO;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic int pn544_hci_i2c_fw_secure_write_frame(struct pn544_i2c_phy *phy)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct pn544_i2c_fw_secure_frame *framep;
69062306a36Sopenharmony_ci	int r;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	framep = (struct pn544_i2c_fw_secure_frame *) phy->fw_blob_data;
69362306a36Sopenharmony_ci	if (phy->fw_written == 0)
69462306a36Sopenharmony_ci		phy->fw_blob_size = get_unaligned_be16(&framep->be_datalen)
69562306a36Sopenharmony_ci				+ PN544_FW_SECURE_FRAME_HEADER_LEN;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	/* Only secure write command can be chunked*/
69862306a36Sopenharmony_ci	if (phy->fw_blob_size > PN544_FW_I2C_MAX_PAYLOAD &&
69962306a36Sopenharmony_ci			framep->cmd != PN544_FW_CMD_SECURE_WRITE)
70062306a36Sopenharmony_ci		return -EINVAL;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	/* The firmware also have other commands, we just send them directly */
70362306a36Sopenharmony_ci	if (phy->fw_blob_size < PN544_FW_I2C_MAX_PAYLOAD) {
70462306a36Sopenharmony_ci		r = i2c_master_send(phy->i2c_dev,
70562306a36Sopenharmony_ci			(const char *) phy->fw_blob_data, phy->fw_blob_size);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		if (r == phy->fw_blob_size)
70862306a36Sopenharmony_ci			goto exit;
70962306a36Sopenharmony_ci		else if (r < 0)
71062306a36Sopenharmony_ci			return r;
71162306a36Sopenharmony_ci		else
71262306a36Sopenharmony_ci			return -EIO;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	r = pn544_hci_i2c_fw_secure_write_frame_cmd(phy,
71662306a36Sopenharmony_ci				       phy->fw_blob_data + phy->fw_written,
71762306a36Sopenharmony_ci				       phy->fw_blob_size - phy->fw_written);
71862306a36Sopenharmony_ci	if (r < 0)
71962306a36Sopenharmony_ci		return r;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ciexit:
72262306a36Sopenharmony_ci	phy->fw_written += r;
72362306a36Sopenharmony_ci	phy->fw_work_state = FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/* SW reset command will not trig any response from PN544 */
72662306a36Sopenharmony_ci	if (framep->cmd == PN544_FW_CMD_RESET) {
72762306a36Sopenharmony_ci		pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE);
72862306a36Sopenharmony_ci		phy->fw_cmd_result = 0;
72962306a36Sopenharmony_ci		schedule_work(&phy->fw_work);
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	return 0;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_cistatic void pn544_hci_i2c_fw_work(struct work_struct *work)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy,
73862306a36Sopenharmony_ci						fw_work);
73962306a36Sopenharmony_ci	int r;
74062306a36Sopenharmony_ci	struct pn544_i2c_fw_blob *blob;
74162306a36Sopenharmony_ci	struct pn544_i2c_fw_secure_blob *secure_blob;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	switch (phy->fw_work_state) {
74462306a36Sopenharmony_ci	case FW_WORK_STATE_START:
74562306a36Sopenharmony_ci		pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci		r = request_firmware(&phy->fw, phy->firmware_name,
74862306a36Sopenharmony_ci				     &phy->i2c_dev->dev);
74962306a36Sopenharmony_ci		if (r < 0)
75062306a36Sopenharmony_ci			goto exit_state_start;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci		phy->fw_written = 0;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		switch (phy->hw_variant) {
75562306a36Sopenharmony_ci		case PN544_HW_VARIANT_C2:
75662306a36Sopenharmony_ci			blob = (struct pn544_i2c_fw_blob *) phy->fw->data;
75762306a36Sopenharmony_ci			phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
75862306a36Sopenharmony_ci			phy->fw_blob_dest_addr = get_unaligned_be32(
75962306a36Sopenharmony_ci							&blob->be_destaddr);
76062306a36Sopenharmony_ci			phy->fw_blob_data = blob->data;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci			r = pn544_hci_i2c_fw_write_chunk(phy);
76362306a36Sopenharmony_ci			break;
76462306a36Sopenharmony_ci		case PN544_HW_VARIANT_C3:
76562306a36Sopenharmony_ci			secure_blob = (struct pn544_i2c_fw_secure_blob *)
76662306a36Sopenharmony_ci								phy->fw->data;
76762306a36Sopenharmony_ci			phy->fw_blob_data = secure_blob->data;
76862306a36Sopenharmony_ci			phy->fw_size = phy->fw->size;
76962306a36Sopenharmony_ci			r = pn544_hci_i2c_fw_secure_write_frame(phy);
77062306a36Sopenharmony_ci			break;
77162306a36Sopenharmony_ci		default:
77262306a36Sopenharmony_ci			r = -ENOTSUPP;
77362306a36Sopenharmony_ci			break;
77462306a36Sopenharmony_ci		}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ciexit_state_start:
77762306a36Sopenharmony_ci		if (r < 0)
77862306a36Sopenharmony_ci			pn544_hci_i2c_fw_work_complete(phy, r);
77962306a36Sopenharmony_ci		break;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	case FW_WORK_STATE_WAIT_WRITE_ANSWER:
78262306a36Sopenharmony_ci		r = phy->fw_cmd_result;
78362306a36Sopenharmony_ci		if (r < 0)
78462306a36Sopenharmony_ci			goto exit_state_wait_write_answer;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		if (phy->fw_written == phy->fw_blob_size) {
78762306a36Sopenharmony_ci			r = pn544_hci_i2c_fw_check_cmd(phy->i2c_dev,
78862306a36Sopenharmony_ci						       phy->fw_blob_dest_addr,
78962306a36Sopenharmony_ci						       phy->fw_blob_data,
79062306a36Sopenharmony_ci						       phy->fw_blob_size);
79162306a36Sopenharmony_ci			if (r < 0)
79262306a36Sopenharmony_ci				goto exit_state_wait_write_answer;
79362306a36Sopenharmony_ci			phy->fw_work_state = FW_WORK_STATE_WAIT_CHECK_ANSWER;
79462306a36Sopenharmony_ci			break;
79562306a36Sopenharmony_ci		}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci		r = pn544_hci_i2c_fw_write_chunk(phy);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ciexit_state_wait_write_answer:
80062306a36Sopenharmony_ci		if (r < 0)
80162306a36Sopenharmony_ci			pn544_hci_i2c_fw_work_complete(phy, r);
80262306a36Sopenharmony_ci		break;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	case FW_WORK_STATE_WAIT_CHECK_ANSWER:
80562306a36Sopenharmony_ci		r = phy->fw_cmd_result;
80662306a36Sopenharmony_ci		if (r < 0)
80762306a36Sopenharmony_ci			goto exit_state_wait_check_answer;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		blob = (struct pn544_i2c_fw_blob *) (phy->fw_blob_data +
81062306a36Sopenharmony_ci		       phy->fw_blob_size);
81162306a36Sopenharmony_ci		phy->fw_blob_size = get_unaligned_be32(&blob->be_size);
81262306a36Sopenharmony_ci		if (phy->fw_blob_size != 0) {
81362306a36Sopenharmony_ci			phy->fw_blob_dest_addr =
81462306a36Sopenharmony_ci					get_unaligned_be32(&blob->be_destaddr);
81562306a36Sopenharmony_ci			phy->fw_blob_data = blob->data;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci			phy->fw_written = 0;
81862306a36Sopenharmony_ci			r = pn544_hci_i2c_fw_write_chunk(phy);
81962306a36Sopenharmony_ci		}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ciexit_state_wait_check_answer:
82262306a36Sopenharmony_ci		if (r < 0 || phy->fw_blob_size == 0)
82362306a36Sopenharmony_ci			pn544_hci_i2c_fw_work_complete(phy, r);
82462306a36Sopenharmony_ci		break;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	case FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER:
82762306a36Sopenharmony_ci		r = phy->fw_cmd_result;
82862306a36Sopenharmony_ci		if (r < 0)
82962306a36Sopenharmony_ci			goto exit_state_wait_secure_write_answer;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		if (r == PN544_FW_CMD_RESULT_CHUNK_OK) {
83262306a36Sopenharmony_ci			r = pn544_hci_i2c_fw_secure_write_frame(phy);
83362306a36Sopenharmony_ci			goto exit_state_wait_secure_write_answer;
83462306a36Sopenharmony_ci		}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci		if (phy->fw_written == phy->fw_blob_size) {
83762306a36Sopenharmony_ci			secure_blob = (struct pn544_i2c_fw_secure_blob *)
83862306a36Sopenharmony_ci				(phy->fw_blob_data + phy->fw_blob_size);
83962306a36Sopenharmony_ci			phy->fw_size -= phy->fw_blob_size +
84062306a36Sopenharmony_ci				PN544_FW_SECURE_BLOB_HEADER_LEN;
84162306a36Sopenharmony_ci			if (phy->fw_size >= PN544_FW_SECURE_BLOB_HEADER_LEN
84262306a36Sopenharmony_ci					+ PN544_FW_SECURE_FRAME_HEADER_LEN) {
84362306a36Sopenharmony_ci				phy->fw_blob_data = secure_blob->data;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci				phy->fw_written = 0;
84662306a36Sopenharmony_ci				r = pn544_hci_i2c_fw_secure_write_frame(phy);
84762306a36Sopenharmony_ci			}
84862306a36Sopenharmony_ci		}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ciexit_state_wait_secure_write_answer:
85162306a36Sopenharmony_ci		if (r < 0 || phy->fw_size == 0)
85262306a36Sopenharmony_ci			pn544_hci_i2c_fw_work_complete(phy, r);
85362306a36Sopenharmony_ci		break;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	default:
85662306a36Sopenharmony_ci		break;
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic const struct acpi_gpio_params enable_gpios = { 1, 0, false };
86162306a36Sopenharmony_cistatic const struct acpi_gpio_params firmware_gpios = { 2, 0, false };
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_pn544_gpios[] = {
86462306a36Sopenharmony_ci	{ "enable-gpios", &enable_gpios, 1 },
86562306a36Sopenharmony_ci	{ "firmware-gpios", &firmware_gpios, 1 },
86662306a36Sopenharmony_ci	{ },
86762306a36Sopenharmony_ci};
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic int pn544_hci_i2c_probe(struct i2c_client *client)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct device *dev = &client->dev;
87262306a36Sopenharmony_ci	struct pn544_i2c_phy *phy;
87362306a36Sopenharmony_ci	int r = 0;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
87662306a36Sopenharmony_ci		nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
87762306a36Sopenharmony_ci		return -ENODEV;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy),
88162306a36Sopenharmony_ci			   GFP_KERNEL);
88262306a36Sopenharmony_ci	if (!phy)
88362306a36Sopenharmony_ci		return -ENOMEM;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	INIT_WORK(&phy->fw_work, pn544_hci_i2c_fw_work);
88662306a36Sopenharmony_ci	phy->fw_work_state = FW_WORK_STATE_IDLE;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	phy->i2c_dev = client;
88962306a36Sopenharmony_ci	i2c_set_clientdata(client, phy);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	r = devm_acpi_dev_add_driver_gpios(dev, acpi_pn544_gpios);
89262306a36Sopenharmony_ci	if (r)
89362306a36Sopenharmony_ci		dev_dbg(dev, "Unable to add GPIO mapping table\n");
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* Get EN GPIO */
89662306a36Sopenharmony_ci	phy->gpiod_en = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
89762306a36Sopenharmony_ci	if (IS_ERR(phy->gpiod_en)) {
89862306a36Sopenharmony_ci		nfc_err(dev, "Unable to get EN GPIO\n");
89962306a36Sopenharmony_ci		return PTR_ERR(phy->gpiod_en);
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	/* Get FW GPIO */
90362306a36Sopenharmony_ci	phy->gpiod_fw = devm_gpiod_get(dev, "firmware", GPIOD_OUT_LOW);
90462306a36Sopenharmony_ci	if (IS_ERR(phy->gpiod_fw)) {
90562306a36Sopenharmony_ci		nfc_err(dev, "Unable to get FW GPIO\n");
90662306a36Sopenharmony_ci		return PTR_ERR(phy->gpiod_fw);
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	pn544_hci_i2c_platform_init(phy);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
91262306a36Sopenharmony_ci				      pn544_hci_i2c_irq_thread_fn,
91362306a36Sopenharmony_ci				      IRQF_TRIGGER_RISING | IRQF_ONESHOT,
91462306a36Sopenharmony_ci				      PN544_HCI_I2C_DRIVER_NAME, phy);
91562306a36Sopenharmony_ci	if (r < 0) {
91662306a36Sopenharmony_ci		nfc_err(&client->dev, "Unable to register IRQ handler\n");
91762306a36Sopenharmony_ci		return r;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
92162306a36Sopenharmony_ci			    PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM,
92262306a36Sopenharmony_ci			    PN544_HCI_I2C_LLC_MAX_PAYLOAD,
92362306a36Sopenharmony_ci			    pn544_hci_i2c_fw_download, &phy->hdev);
92462306a36Sopenharmony_ci	if (r < 0)
92562306a36Sopenharmony_ci		return r;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	return 0;
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_cistatic void pn544_hci_i2c_remove(struct i2c_client *client)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	cancel_work_sync(&phy->fw_work);
93562306a36Sopenharmony_ci	if (phy->fw_work_state != FW_WORK_STATE_IDLE)
93662306a36Sopenharmony_ci		pn544_hci_i2c_fw_work_complete(phy, -ENODEV);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	pn544_hci_remove(phy->hdev);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	if (phy->powered)
94162306a36Sopenharmony_ci		pn544_hci_i2c_disable(phy);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic const struct of_device_id of_pn544_i2c_match[] __maybe_unused = {
94562306a36Sopenharmony_ci	{ .compatible = "nxp,pn544-i2c", },
94662306a36Sopenharmony_ci	{},
94762306a36Sopenharmony_ci};
94862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_pn544_i2c_match);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic struct i2c_driver pn544_hci_i2c_driver = {
95162306a36Sopenharmony_ci	.driver = {
95262306a36Sopenharmony_ci		   .name = PN544_HCI_I2C_DRIVER_NAME,
95362306a36Sopenharmony_ci		   .of_match_table = of_match_ptr(of_pn544_i2c_match),
95462306a36Sopenharmony_ci		   .acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match),
95562306a36Sopenharmony_ci		  },
95662306a36Sopenharmony_ci	.probe = pn544_hci_i2c_probe,
95762306a36Sopenharmony_ci	.id_table = pn544_hci_i2c_id_table,
95862306a36Sopenharmony_ci	.remove = pn544_hci_i2c_remove,
95962306a36Sopenharmony_ci};
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cimodule_i2c_driver(pn544_hci_i2c_driver);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
96462306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
965