18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * I2C Link Layer for PN544 HCI based Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Intel Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/crc-ccitt.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/i2c.h> 138c2ecf20Sopenharmony_ci#include <linux/acpi.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/nfc.h> 178c2ecf20Sopenharmony_ci#include <linux/firmware.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <net/nfc/hci.h> 238c2ecf20Sopenharmony_ci#include <net/nfc/llc.h> 248c2ecf20Sopenharmony_ci#include <net/nfc/nfc.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "pn544.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define PN544_I2C_FRAME_HEADROOM 1 298c2ecf20Sopenharmony_ci#define PN544_I2C_FRAME_TAILROOM 2 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* GPIO names */ 328c2ecf20Sopenharmony_ci#define PN544_GPIO_NAME_IRQ "pn544_irq" 338c2ecf20Sopenharmony_ci#define PN544_GPIO_NAME_FW "pn544_fw" 348c2ecf20Sopenharmony_ci#define PN544_GPIO_NAME_EN "pn544_en" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* framing in HCI mode */ 378c2ecf20Sopenharmony_ci#define PN544_HCI_I2C_LLC_LEN 1 388c2ecf20Sopenharmony_ci#define PN544_HCI_I2C_LLC_CRC 2 398c2ecf20Sopenharmony_ci#define PN544_HCI_I2C_LLC_LEN_CRC (PN544_HCI_I2C_LLC_LEN + \ 408c2ecf20Sopenharmony_ci PN544_HCI_I2C_LLC_CRC) 418c2ecf20Sopenharmony_ci#define PN544_HCI_I2C_LLC_MIN_SIZE (1 + PN544_HCI_I2C_LLC_LEN_CRC) 428c2ecf20Sopenharmony_ci#define PN544_HCI_I2C_LLC_MAX_PAYLOAD 29 438c2ecf20Sopenharmony_ci#define PN544_HCI_I2C_LLC_MAX_SIZE (PN544_HCI_I2C_LLC_LEN_CRC + 1 + \ 448c2ecf20Sopenharmony_ci PN544_HCI_I2C_LLC_MAX_PAYLOAD) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const struct i2c_device_id pn544_hci_i2c_id_table[] = { 478c2ecf20Sopenharmony_ci {"pn544", 0}, 488c2ecf20Sopenharmony_ci {} 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic const struct acpi_device_id pn544_hci_i2c_acpi_match[] = { 548c2ecf20Sopenharmony_ci {"NXP5440", 0}, 558c2ecf20Sopenharmony_ci {} 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, pn544_hci_i2c_acpi_match); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * Exposed through the 4 most significant bytes 648c2ecf20Sopenharmony_ci * from the HCI SW_VERSION first byte, a.k.a. 658c2ecf20Sopenharmony_ci * SW RomLib. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci#define PN544_HW_VARIANT_C2 0xa 688c2ecf20Sopenharmony_ci#define PN544_HW_VARIANT_C3 0xb 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESET 0x01 718c2ecf20Sopenharmony_ci#define PN544_FW_CMD_WRITE 0x08 728c2ecf20Sopenharmony_ci#define PN544_FW_CMD_CHECK 0x06 738c2ecf20Sopenharmony_ci#define PN544_FW_CMD_SECURE_WRITE 0x0C 748c2ecf20Sopenharmony_ci#define PN544_FW_CMD_SECURE_CHUNK_WRITE 0x0D 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistruct pn544_i2c_fw_frame_write { 778c2ecf20Sopenharmony_ci u8 cmd; 788c2ecf20Sopenharmony_ci u16 be_length; 798c2ecf20Sopenharmony_ci u8 be_dest_addr[3]; 808c2ecf20Sopenharmony_ci u16 be_datalen; 818c2ecf20Sopenharmony_ci u8 data[]; 828c2ecf20Sopenharmony_ci} __packed; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct pn544_i2c_fw_frame_check { 858c2ecf20Sopenharmony_ci u8 cmd; 868c2ecf20Sopenharmony_ci u16 be_length; 878c2ecf20Sopenharmony_ci u8 be_start_addr[3]; 888c2ecf20Sopenharmony_ci u16 be_datalen; 898c2ecf20Sopenharmony_ci u16 be_crc; 908c2ecf20Sopenharmony_ci} __packed; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistruct pn544_i2c_fw_frame_response { 938c2ecf20Sopenharmony_ci u8 status; 948c2ecf20Sopenharmony_ci u16 be_length; 958c2ecf20Sopenharmony_ci} __packed; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistruct pn544_i2c_fw_blob { 988c2ecf20Sopenharmony_ci u32 be_size; 998c2ecf20Sopenharmony_ci u32 be_destaddr; 1008c2ecf20Sopenharmony_ci u8 data[]; 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistruct pn544_i2c_fw_secure_frame { 1048c2ecf20Sopenharmony_ci u8 cmd; 1058c2ecf20Sopenharmony_ci u16 be_datalen; 1068c2ecf20Sopenharmony_ci u8 data[]; 1078c2ecf20Sopenharmony_ci} __packed; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistruct pn544_i2c_fw_secure_blob { 1108c2ecf20Sopenharmony_ci u64 header; 1118c2ecf20Sopenharmony_ci u8 data[]; 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_TIMEOUT 0x01 1158c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_BAD_CRC 0x02 1168c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08 1178c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B 1188c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11 1198c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND 0x13 1208c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18 1218c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR 0x19 1228c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR 0x1D 1238c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_MEMORY_ERROR 0x20 1248c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_CHUNK_OK 0x21 1258c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74 1268c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_COMMAND_REJECTED 0xE0 1278c2ecf20Sopenharmony_ci#define PN544_FW_CMD_RESULT_CHUNK_ERROR 0xE6 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define PN544_FW_WRITE_BUFFER_MAX_LEN 0x9f7 1328c2ecf20Sopenharmony_ci#define PN544_FW_I2C_MAX_PAYLOAD PN544_HCI_I2C_LLC_MAX_SIZE 1338c2ecf20Sopenharmony_ci#define PN544_FW_I2C_WRITE_FRAME_HEADER_LEN 8 1348c2ecf20Sopenharmony_ci#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\ 1358c2ecf20Sopenharmony_ci PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\ 1368c2ecf20Sopenharmony_ci PN544_FW_WRITE_BUFFER_MAX_LEN) 1378c2ecf20Sopenharmony_ci#define PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN 3 1388c2ecf20Sopenharmony_ci#define PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN (PN544_FW_I2C_MAX_PAYLOAD -\ 1398c2ecf20Sopenharmony_ci PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN) 1408c2ecf20Sopenharmony_ci#define PN544_FW_SECURE_FRAME_HEADER_LEN 3 1418c2ecf20Sopenharmony_ci#define PN544_FW_SECURE_BLOB_HEADER_LEN 8 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define FW_WORK_STATE_IDLE 1 1448c2ecf20Sopenharmony_ci#define FW_WORK_STATE_START 2 1458c2ecf20Sopenharmony_ci#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3 1468c2ecf20Sopenharmony_ci#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4 1478c2ecf20Sopenharmony_ci#define FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER 5 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistruct pn544_i2c_phy { 1508c2ecf20Sopenharmony_ci struct i2c_client *i2c_dev; 1518c2ecf20Sopenharmony_ci struct nfc_hci_dev *hdev; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_en; 1548c2ecf20Sopenharmony_ci struct gpio_desc *gpiod_fw; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci unsigned int en_polarity; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci u8 hw_variant; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci struct work_struct fw_work; 1618c2ecf20Sopenharmony_ci int fw_work_state; 1628c2ecf20Sopenharmony_ci char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; 1638c2ecf20Sopenharmony_ci const struct firmware *fw; 1648c2ecf20Sopenharmony_ci u32 fw_blob_dest_addr; 1658c2ecf20Sopenharmony_ci size_t fw_blob_size; 1668c2ecf20Sopenharmony_ci const u8 *fw_blob_data; 1678c2ecf20Sopenharmony_ci size_t fw_written; 1688c2ecf20Sopenharmony_ci size_t fw_size; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci int fw_cmd_result; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci int powered; 1738c2ecf20Sopenharmony_ci int run_mode; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci int hard_fault; /* 1768c2ecf20Sopenharmony_ci * < 0 if hardware error occured (e.g. i2c err) 1778c2ecf20Sopenharmony_ci * and prevents normal operation. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define I2C_DUMP_SKB(info, skb) \ 1828c2ecf20Sopenharmony_cido { \ 1838c2ecf20Sopenharmony_ci pr_debug("%s:\n", info); \ 1848c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \ 1858c2ecf20Sopenharmony_ci 16, 1, (skb)->data, (skb)->len, 0); \ 1868c2ecf20Sopenharmony_ci} while (0) 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci int polarity, retry, ret; 1918c2ecf20Sopenharmony_ci char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 }; 1928c2ecf20Sopenharmony_ci int count = sizeof(rset_cmd); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n"); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Disable fw download */ 1978c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_fw, 0); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci for (polarity = 0; polarity < 2; polarity++) { 2008c2ecf20Sopenharmony_ci phy->en_polarity = polarity; 2018c2ecf20Sopenharmony_ci retry = 3; 2028c2ecf20Sopenharmony_ci while (retry--) { 2038c2ecf20Sopenharmony_ci /* power off */ 2048c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity); 2058c2ecf20Sopenharmony_ci usleep_range(10000, 15000); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* power on */ 2088c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity); 2098c2ecf20Sopenharmony_ci usleep_range(10000, 15000); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* send reset */ 2128c2ecf20Sopenharmony_ci dev_dbg(&phy->i2c_dev->dev, "Sending reset cmd\n"); 2138c2ecf20Sopenharmony_ci ret = i2c_master_send(phy->i2c_dev, rset_cmd, count); 2148c2ecf20Sopenharmony_ci if (ret == count) { 2158c2ecf20Sopenharmony_ci nfc_info(&phy->i2c_dev->dev, 2168c2ecf20Sopenharmony_ci "nfc_en polarity : active %s\n", 2178c2ecf20Sopenharmony_ci (polarity == 0 ? "low" : "high")); 2188c2ecf20Sopenharmony_ci goto out; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci nfc_err(&phy->i2c_dev->dev, 2248c2ecf20Sopenharmony_ci "Could not detect nfc_en polarity, fallback to active high\n"); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciout: 2278c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity); 2288c2ecf20Sopenharmony_ci usleep_range(10000, 15000); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_fw, run_mode == PN544_FW_MODE ? 1 : 0); 2348c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity); 2358c2ecf20Sopenharmony_ci usleep_range(10000, 15000); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci phy->run_mode = run_mode; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_enable(void *phy_id) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy = phy_id; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci pr_info("%s\n", __func__); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci pn544_hci_i2c_enable_mode(phy, PN544_HCI_MODE); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci phy->powered = 1; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void pn544_hci_i2c_disable(void *phy_id) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy = phy_id; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_fw, 0); 2588c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity); 2598c2ecf20Sopenharmony_ci usleep_range(10000, 15000); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_en, phy->en_polarity); 2628c2ecf20Sopenharmony_ci usleep_range(10000, 15000); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(phy->gpiod_en, !phy->en_polarity); 2658c2ecf20Sopenharmony_ci usleep_range(10000, 15000); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci phy->powered = 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void pn544_hci_i2c_add_len_crc(struct sk_buff *skb) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci u16 crc; 2738c2ecf20Sopenharmony_ci int len; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci len = skb->len + 2; 2768c2ecf20Sopenharmony_ci *(u8 *)skb_push(skb, 1) = len; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci crc = crc_ccitt(0xffff, skb->data, skb->len); 2798c2ecf20Sopenharmony_ci crc = ~crc; 2808c2ecf20Sopenharmony_ci skb_put_u8(skb, crc & 0xff); 2818c2ecf20Sopenharmony_ci skb_put_u8(skb, crc >> 8); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic void pn544_hci_i2c_remove_len_crc(struct sk_buff *skb) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci skb_pull(skb, PN544_I2C_FRAME_HEADROOM); 2878c2ecf20Sopenharmony_ci skb_trim(skb, PN544_I2C_FRAME_TAILROOM); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/* 2918c2ecf20Sopenharmony_ci * Writing a frame must not return the number of written bytes. 2928c2ecf20Sopenharmony_ci * It must return either zero for success, or <0 for error. 2938c2ecf20Sopenharmony_ci * In addition, it must not alter the skb 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_write(void *phy_id, struct sk_buff *skb) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int r; 2988c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy = phy_id; 2998c2ecf20Sopenharmony_ci struct i2c_client *client = phy->i2c_dev; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (phy->hard_fault != 0) 3028c2ecf20Sopenharmony_ci return phy->hard_fault; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci usleep_range(3000, 6000); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci pn544_hci_i2c_add_len_crc(skb); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci I2C_DUMP_SKB("i2c frame written", skb); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci r = i2c_master_send(client, skb->data, skb->len); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (r == -EREMOTEIO) { /* Retry, chip was in standby */ 3138c2ecf20Sopenharmony_ci usleep_range(6000, 10000); 3148c2ecf20Sopenharmony_ci r = i2c_master_send(client, skb->data, skb->len); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (r >= 0) { 3188c2ecf20Sopenharmony_ci if (r != skb->len) 3198c2ecf20Sopenharmony_ci r = -EREMOTEIO; 3208c2ecf20Sopenharmony_ci else 3218c2ecf20Sopenharmony_ci r = 0; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci pn544_hci_i2c_remove_len_crc(skb); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return r; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int check_crc(u8 *buf, int buflen) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci int len; 3328c2ecf20Sopenharmony_ci u16 crc; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci len = buf[0] + 1; 3358c2ecf20Sopenharmony_ci crc = crc_ccitt(0xffff, buf, len - 2); 3368c2ecf20Sopenharmony_ci crc = ~crc; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) { 3398c2ecf20Sopenharmony_ci pr_err("CRC error 0x%x != 0x%x 0x%x\n", 3408c2ecf20Sopenharmony_ci crc, buf[len - 1], buf[len - 2]); 3418c2ecf20Sopenharmony_ci pr_info("%s: BAD CRC\n", __func__); 3428c2ecf20Sopenharmony_ci print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, 3438c2ecf20Sopenharmony_ci 16, 2, buf, buflen, false); 3448c2ecf20Sopenharmony_ci return -EPERM; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees 3518c2ecf20Sopenharmony_ci * that i2c bus will be flushed and that next read will start on a new frame. 3528c2ecf20Sopenharmony_ci * returned skb contains only LLC header and payload. 3538c2ecf20Sopenharmony_ci * returns: 3548c2ecf20Sopenharmony_ci * -EREMOTEIO : i2c read error (fatal) 3558c2ecf20Sopenharmony_ci * -EBADMSG : frame was incorrect and discarded 3568c2ecf20Sopenharmony_ci * -ENOMEM : cannot allocate skb, frame dropped 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci int r; 3618c2ecf20Sopenharmony_ci u8 len; 3628c2ecf20Sopenharmony_ci u8 tmp[PN544_HCI_I2C_LLC_MAX_SIZE - 1]; 3638c2ecf20Sopenharmony_ci struct i2c_client *client = phy->i2c_dev; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci r = i2c_master_recv(client, &len, 1); 3668c2ecf20Sopenharmony_ci if (r != 1) { 3678c2ecf20Sopenharmony_ci nfc_err(&client->dev, "cannot read len byte\n"); 3688c2ecf20Sopenharmony_ci return -EREMOTEIO; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if ((len < (PN544_HCI_I2C_LLC_MIN_SIZE - 1)) || 3728c2ecf20Sopenharmony_ci (len > (PN544_HCI_I2C_LLC_MAX_SIZE - 1))) { 3738c2ecf20Sopenharmony_ci nfc_err(&client->dev, "invalid len byte\n"); 3748c2ecf20Sopenharmony_ci r = -EBADMSG; 3758c2ecf20Sopenharmony_ci goto flush; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci *skb = alloc_skb(1 + len, GFP_KERNEL); 3798c2ecf20Sopenharmony_ci if (*skb == NULL) { 3808c2ecf20Sopenharmony_ci r = -ENOMEM; 3818c2ecf20Sopenharmony_ci goto flush; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci skb_put_u8(*skb, len); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci r = i2c_master_recv(client, skb_put(*skb, len), len); 3878c2ecf20Sopenharmony_ci if (r != len) { 3888c2ecf20Sopenharmony_ci kfree_skb(*skb); 3898c2ecf20Sopenharmony_ci return -EREMOTEIO; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci I2C_DUMP_SKB("i2c frame read", *skb); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci r = check_crc((*skb)->data, (*skb)->len); 3958c2ecf20Sopenharmony_ci if (r != 0) { 3968c2ecf20Sopenharmony_ci kfree_skb(*skb); 3978c2ecf20Sopenharmony_ci r = -EBADMSG; 3988c2ecf20Sopenharmony_ci goto flush; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci skb_pull(*skb, 1); 4028c2ecf20Sopenharmony_ci skb_trim(*skb, (*skb)->len - 2); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci usleep_range(3000, 6000); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciflush: 4098c2ecf20Sopenharmony_ci if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) 4108c2ecf20Sopenharmony_ci r = -EREMOTEIO; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci usleep_range(3000, 6000); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return r; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci int r; 4208c2ecf20Sopenharmony_ci struct pn544_i2c_fw_frame_response response; 4218c2ecf20Sopenharmony_ci struct i2c_client *client = phy->i2c_dev; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci r = i2c_master_recv(client, (char *) &response, sizeof(response)); 4248c2ecf20Sopenharmony_ci if (r != sizeof(response)) { 4258c2ecf20Sopenharmony_ci nfc_err(&client->dev, "cannot read fw status\n"); 4268c2ecf20Sopenharmony_ci return -EIO; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci usleep_range(3000, 6000); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci switch (response.status) { 4328c2ecf20Sopenharmony_ci case 0: 4338c2ecf20Sopenharmony_ci return 0; 4348c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_CHUNK_OK: 4358c2ecf20Sopenharmony_ci return response.status; 4368c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_TIMEOUT: 4378c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4388c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_BAD_CRC: 4398c2ecf20Sopenharmony_ci return -ENODATA; 4408c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_ACCESS_DENIED: 4418c2ecf20Sopenharmony_ci return -EACCES; 4428c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_PROTOCOL_ERROR: 4438c2ecf20Sopenharmony_ci return -EPROTO; 4448c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_INVALID_PARAMETER: 4458c2ecf20Sopenharmony_ci return -EINVAL; 4468c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND: 4478c2ecf20Sopenharmony_ci return -ENOTSUPP; 4488c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_INVALID_LENGTH: 4498c2ecf20Sopenharmony_ci return -EBADMSG; 4508c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR: 4518c2ecf20Sopenharmony_ci return -ENOKEY; 4528c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR: 4538c2ecf20Sopenharmony_ci return -EINVAL; 4548c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_MEMORY_ERROR: 4558c2ecf20Sopenharmony_ci return -ENOMEM; 4568c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_COMMAND_REJECTED: 4578c2ecf20Sopenharmony_ci return -EACCES; 4588c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_WRITE_FAILED: 4598c2ecf20Sopenharmony_ci case PN544_FW_CMD_RESULT_CHUNK_ERROR: 4608c2ecf20Sopenharmony_ci return -EIO; 4618c2ecf20Sopenharmony_ci default: 4628c2ecf20Sopenharmony_ci return -EIO; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/* 4678c2ecf20Sopenharmony_ci * Reads an shdlc frame from the chip. This is not as straightforward as it 4688c2ecf20Sopenharmony_ci * seems. There are cases where we could loose the frame start synchronization. 4698c2ecf20Sopenharmony_ci * The frame format is len-data-crc, and corruption can occur anywhere while 4708c2ecf20Sopenharmony_ci * transiting on i2c bus, such that we could read an invalid len. 4718c2ecf20Sopenharmony_ci * In order to recover synchronization with the next frame, we must be sure 4728c2ecf20Sopenharmony_ci * to read the real amount of data without using the len byte. We do this by 4738c2ecf20Sopenharmony_ci * assuming the following: 4748c2ecf20Sopenharmony_ci * - the chip will always present only one single complete frame on the bus 4758c2ecf20Sopenharmony_ci * before triggering the interrupt 4768c2ecf20Sopenharmony_ci * - the chip will not present a new frame until we have completely read 4778c2ecf20Sopenharmony_ci * the previous one (or until we have handled the interrupt). 4788c2ecf20Sopenharmony_ci * The tricky case is when we read a corrupted len that is less than the real 4798c2ecf20Sopenharmony_ci * len. We must detect this here in order to determine that we need to flush 4808c2ecf20Sopenharmony_ci * the bus. This is the reason why we check the crc here. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_cistatic irqreturn_t pn544_hci_i2c_irq_thread_fn(int irq, void *phy_id) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy = phy_id; 4858c2ecf20Sopenharmony_ci struct i2c_client *client; 4868c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 4878c2ecf20Sopenharmony_ci int r; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (!phy || irq != phy->i2c_dev->irq) { 4908c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 4918c2ecf20Sopenharmony_ci return IRQ_NONE; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci client = phy->i2c_dev; 4958c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "IRQ\n"); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (phy->hard_fault != 0) 4988c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (phy->run_mode == PN544_FW_MODE) { 5018c2ecf20Sopenharmony_ci phy->fw_cmd_result = pn544_hci_i2c_fw_read_status(phy); 5028c2ecf20Sopenharmony_ci schedule_work(&phy->fw_work); 5038c2ecf20Sopenharmony_ci } else { 5048c2ecf20Sopenharmony_ci r = pn544_hci_i2c_read(phy, &skb); 5058c2ecf20Sopenharmony_ci if (r == -EREMOTEIO) { 5068c2ecf20Sopenharmony_ci phy->hard_fault = r; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci nfc_hci_recv_frame(phy->hdev, NULL); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5118c2ecf20Sopenharmony_ci } else if ((r == -ENOMEM) || (r == -EBADMSG)) { 5128c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci nfc_hci_recv_frame(phy->hdev, skb); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic struct nfc_phy_ops i2c_phy_ops = { 5218c2ecf20Sopenharmony_ci .write = pn544_hci_i2c_write, 5228c2ecf20Sopenharmony_ci .enable = pn544_hci_i2c_enable, 5238c2ecf20Sopenharmony_ci .disable = pn544_hci_i2c_disable, 5248c2ecf20Sopenharmony_ci}; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name, 5278c2ecf20Sopenharmony_ci u8 hw_variant) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy = phy_id; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci pr_info("Starting Firmware Download (%s)\n", firmware_name); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci strcpy(phy->firmware_name, firmware_name); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci phy->hw_variant = hw_variant; 5368c2ecf20Sopenharmony_ci phy->fw_work_state = FW_WORK_STATE_START; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci schedule_work(&phy->fw_work); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic void pn544_hci_i2c_fw_work_complete(struct pn544_i2c_phy *phy, 5448c2ecf20Sopenharmony_ci int result) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci pr_info("Firmware Download Complete, result=%d\n", result); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci pn544_hci_i2c_disable(phy); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci phy->fw_work_state = FW_WORK_STATE_IDLE; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (phy->fw) { 5538c2ecf20Sopenharmony_ci release_firmware(phy->fw); 5548c2ecf20Sopenharmony_ci phy->fw = NULL; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci nfc_fw_download_done(phy->hdev->ndev, phy->firmware_name, (u32) -result); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_fw_write_cmd(struct i2c_client *client, u32 dest_addr, 5618c2ecf20Sopenharmony_ci const u8 *data, u16 datalen) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci u8 frame[PN544_FW_I2C_MAX_PAYLOAD]; 5648c2ecf20Sopenharmony_ci struct pn544_i2c_fw_frame_write *framep; 5658c2ecf20Sopenharmony_ci u16 params_len; 5668c2ecf20Sopenharmony_ci int framelen; 5678c2ecf20Sopenharmony_ci int r; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (datalen > PN544_FW_I2C_WRITE_DATA_MAX_LEN) 5708c2ecf20Sopenharmony_ci datalen = PN544_FW_I2C_WRITE_DATA_MAX_LEN; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci framep = (struct pn544_i2c_fw_frame_write *) frame; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci params_len = sizeof(framep->be_dest_addr) + 5758c2ecf20Sopenharmony_ci sizeof(framep->be_datalen) + datalen; 5768c2ecf20Sopenharmony_ci framelen = params_len + sizeof(framep->cmd) + 5778c2ecf20Sopenharmony_ci sizeof(framep->be_length); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci framep->cmd = PN544_FW_CMD_WRITE; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci put_unaligned_be16(params_len, &framep->be_length); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci framep->be_dest_addr[0] = (dest_addr & 0xff0000) >> 16; 5848c2ecf20Sopenharmony_ci framep->be_dest_addr[1] = (dest_addr & 0xff00) >> 8; 5858c2ecf20Sopenharmony_ci framep->be_dest_addr[2] = dest_addr & 0xff; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci put_unaligned_be16(datalen, &framep->be_datalen); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci memcpy(framep->data, data, datalen); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci r = i2c_master_send(client, frame, framelen); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (r == framelen) 5948c2ecf20Sopenharmony_ci return datalen; 5958c2ecf20Sopenharmony_ci else if (r < 0) 5968c2ecf20Sopenharmony_ci return r; 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci return -EIO; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_fw_check_cmd(struct i2c_client *client, u32 start_addr, 6028c2ecf20Sopenharmony_ci const u8 *data, u16 datalen) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct pn544_i2c_fw_frame_check frame; 6058c2ecf20Sopenharmony_ci int r; 6068c2ecf20Sopenharmony_ci u16 crc; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci /* calculate local crc for the data we want to check */ 6098c2ecf20Sopenharmony_ci crc = crc_ccitt(0xffff, data, datalen); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci frame.cmd = PN544_FW_CMD_CHECK; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci put_unaligned_be16(sizeof(frame.be_start_addr) + 6148c2ecf20Sopenharmony_ci sizeof(frame.be_datalen) + sizeof(frame.be_crc), 6158c2ecf20Sopenharmony_ci &frame.be_length); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* tell the chip the memory region to which our crc applies */ 6188c2ecf20Sopenharmony_ci frame.be_start_addr[0] = (start_addr & 0xff0000) >> 16; 6198c2ecf20Sopenharmony_ci frame.be_start_addr[1] = (start_addr & 0xff00) >> 8; 6208c2ecf20Sopenharmony_ci frame.be_start_addr[2] = start_addr & 0xff; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci put_unaligned_be16(datalen, &frame.be_datalen); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* 6258c2ecf20Sopenharmony_ci * and give our local crc. Chip will calculate its own crc for the 6268c2ecf20Sopenharmony_ci * region and compare with ours. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ci put_unaligned_be16(crc, &frame.be_crc); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci r = i2c_master_send(client, (const char *) &frame, sizeof(frame)); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (r == sizeof(frame)) 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci else if (r < 0) 6358c2ecf20Sopenharmony_ci return r; 6368c2ecf20Sopenharmony_ci else 6378c2ecf20Sopenharmony_ci return -EIO; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_fw_write_chunk(struct pn544_i2c_phy *phy) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci int r; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_write_cmd(phy->i2c_dev, 6458c2ecf20Sopenharmony_ci phy->fw_blob_dest_addr + phy->fw_written, 6468c2ecf20Sopenharmony_ci phy->fw_blob_data + phy->fw_written, 6478c2ecf20Sopenharmony_ci phy->fw_blob_size - phy->fw_written); 6488c2ecf20Sopenharmony_ci if (r < 0) 6498c2ecf20Sopenharmony_ci return r; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci phy->fw_written += r; 6528c2ecf20Sopenharmony_ci phy->fw_work_state = FW_WORK_STATE_WAIT_WRITE_ANSWER; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_fw_secure_write_frame_cmd(struct pn544_i2c_phy *phy, 6588c2ecf20Sopenharmony_ci const u8 *data, u16 datalen) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci u8 buf[PN544_FW_I2C_MAX_PAYLOAD]; 6618c2ecf20Sopenharmony_ci struct pn544_i2c_fw_secure_frame *chunk; 6628c2ecf20Sopenharmony_ci int chunklen; 6638c2ecf20Sopenharmony_ci int r; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (datalen > PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN) 6668c2ecf20Sopenharmony_ci datalen = PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci chunk = (struct pn544_i2c_fw_secure_frame *) buf; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci chunk->cmd = PN544_FW_CMD_SECURE_CHUNK_WRITE; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci put_unaligned_be16(datalen, &chunk->be_datalen); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci memcpy(chunk->data, data, datalen); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci chunklen = sizeof(chunk->cmd) + sizeof(chunk->be_datalen) + datalen; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci r = i2c_master_send(phy->i2c_dev, buf, chunklen); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (r == chunklen) 6818c2ecf20Sopenharmony_ci return datalen; 6828c2ecf20Sopenharmony_ci else if (r < 0) 6838c2ecf20Sopenharmony_ci return r; 6848c2ecf20Sopenharmony_ci else 6858c2ecf20Sopenharmony_ci return -EIO; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_fw_secure_write_frame(struct pn544_i2c_phy *phy) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct pn544_i2c_fw_secure_frame *framep; 6928c2ecf20Sopenharmony_ci int r; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci framep = (struct pn544_i2c_fw_secure_frame *) phy->fw_blob_data; 6958c2ecf20Sopenharmony_ci if (phy->fw_written == 0) 6968c2ecf20Sopenharmony_ci phy->fw_blob_size = get_unaligned_be16(&framep->be_datalen) 6978c2ecf20Sopenharmony_ci + PN544_FW_SECURE_FRAME_HEADER_LEN; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* Only secure write command can be chunked*/ 7008c2ecf20Sopenharmony_ci if (phy->fw_blob_size > PN544_FW_I2C_MAX_PAYLOAD && 7018c2ecf20Sopenharmony_ci framep->cmd != PN544_FW_CMD_SECURE_WRITE) 7028c2ecf20Sopenharmony_ci return -EINVAL; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* The firmware also have other commands, we just send them directly */ 7058c2ecf20Sopenharmony_ci if (phy->fw_blob_size < PN544_FW_I2C_MAX_PAYLOAD) { 7068c2ecf20Sopenharmony_ci r = i2c_master_send(phy->i2c_dev, 7078c2ecf20Sopenharmony_ci (const char *) phy->fw_blob_data, phy->fw_blob_size); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (r == phy->fw_blob_size) 7108c2ecf20Sopenharmony_ci goto exit; 7118c2ecf20Sopenharmony_ci else if (r < 0) 7128c2ecf20Sopenharmony_ci return r; 7138c2ecf20Sopenharmony_ci else 7148c2ecf20Sopenharmony_ci return -EIO; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_secure_write_frame_cmd(phy, 7188c2ecf20Sopenharmony_ci phy->fw_blob_data + phy->fw_written, 7198c2ecf20Sopenharmony_ci phy->fw_blob_size - phy->fw_written); 7208c2ecf20Sopenharmony_ci if (r < 0) 7218c2ecf20Sopenharmony_ci return r; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ciexit: 7248c2ecf20Sopenharmony_ci phy->fw_written += r; 7258c2ecf20Sopenharmony_ci phy->fw_work_state = FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* SW reset command will not trig any response from PN544 */ 7288c2ecf20Sopenharmony_ci if (framep->cmd == PN544_FW_CMD_RESET) { 7298c2ecf20Sopenharmony_ci pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE); 7308c2ecf20Sopenharmony_ci phy->fw_cmd_result = 0; 7318c2ecf20Sopenharmony_ci schedule_work(&phy->fw_work); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci return 0; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic void pn544_hci_i2c_fw_work(struct work_struct *work) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy, 7408c2ecf20Sopenharmony_ci fw_work); 7418c2ecf20Sopenharmony_ci int r; 7428c2ecf20Sopenharmony_ci struct pn544_i2c_fw_blob *blob; 7438c2ecf20Sopenharmony_ci struct pn544_i2c_fw_secure_blob *secure_blob; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci switch (phy->fw_work_state) { 7468c2ecf20Sopenharmony_ci case FW_WORK_STATE_START: 7478c2ecf20Sopenharmony_ci pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci r = request_firmware(&phy->fw, phy->firmware_name, 7508c2ecf20Sopenharmony_ci &phy->i2c_dev->dev); 7518c2ecf20Sopenharmony_ci if (r < 0) 7528c2ecf20Sopenharmony_ci goto exit_state_start; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci phy->fw_written = 0; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci switch (phy->hw_variant) { 7578c2ecf20Sopenharmony_ci case PN544_HW_VARIANT_C2: 7588c2ecf20Sopenharmony_ci blob = (struct pn544_i2c_fw_blob *) phy->fw->data; 7598c2ecf20Sopenharmony_ci phy->fw_blob_size = get_unaligned_be32(&blob->be_size); 7608c2ecf20Sopenharmony_ci phy->fw_blob_dest_addr = get_unaligned_be32( 7618c2ecf20Sopenharmony_ci &blob->be_destaddr); 7628c2ecf20Sopenharmony_ci phy->fw_blob_data = blob->data; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_write_chunk(phy); 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci case PN544_HW_VARIANT_C3: 7678c2ecf20Sopenharmony_ci secure_blob = (struct pn544_i2c_fw_secure_blob *) 7688c2ecf20Sopenharmony_ci phy->fw->data; 7698c2ecf20Sopenharmony_ci phy->fw_blob_data = secure_blob->data; 7708c2ecf20Sopenharmony_ci phy->fw_size = phy->fw->size; 7718c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_secure_write_frame(phy); 7728c2ecf20Sopenharmony_ci break; 7738c2ecf20Sopenharmony_ci default: 7748c2ecf20Sopenharmony_ci r = -ENOTSUPP; 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ciexit_state_start: 7798c2ecf20Sopenharmony_ci if (r < 0) 7808c2ecf20Sopenharmony_ci pn544_hci_i2c_fw_work_complete(phy, r); 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci case FW_WORK_STATE_WAIT_WRITE_ANSWER: 7848c2ecf20Sopenharmony_ci r = phy->fw_cmd_result; 7858c2ecf20Sopenharmony_ci if (r < 0) 7868c2ecf20Sopenharmony_ci goto exit_state_wait_write_answer; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (phy->fw_written == phy->fw_blob_size) { 7898c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_check_cmd(phy->i2c_dev, 7908c2ecf20Sopenharmony_ci phy->fw_blob_dest_addr, 7918c2ecf20Sopenharmony_ci phy->fw_blob_data, 7928c2ecf20Sopenharmony_ci phy->fw_blob_size); 7938c2ecf20Sopenharmony_ci if (r < 0) 7948c2ecf20Sopenharmony_ci goto exit_state_wait_write_answer; 7958c2ecf20Sopenharmony_ci phy->fw_work_state = FW_WORK_STATE_WAIT_CHECK_ANSWER; 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_write_chunk(phy); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ciexit_state_wait_write_answer: 8028c2ecf20Sopenharmony_ci if (r < 0) 8038c2ecf20Sopenharmony_ci pn544_hci_i2c_fw_work_complete(phy, r); 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci case FW_WORK_STATE_WAIT_CHECK_ANSWER: 8078c2ecf20Sopenharmony_ci r = phy->fw_cmd_result; 8088c2ecf20Sopenharmony_ci if (r < 0) 8098c2ecf20Sopenharmony_ci goto exit_state_wait_check_answer; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci blob = (struct pn544_i2c_fw_blob *) (phy->fw_blob_data + 8128c2ecf20Sopenharmony_ci phy->fw_blob_size); 8138c2ecf20Sopenharmony_ci phy->fw_blob_size = get_unaligned_be32(&blob->be_size); 8148c2ecf20Sopenharmony_ci if (phy->fw_blob_size != 0) { 8158c2ecf20Sopenharmony_ci phy->fw_blob_dest_addr = 8168c2ecf20Sopenharmony_ci get_unaligned_be32(&blob->be_destaddr); 8178c2ecf20Sopenharmony_ci phy->fw_blob_data = blob->data; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci phy->fw_written = 0; 8208c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_write_chunk(phy); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ciexit_state_wait_check_answer: 8248c2ecf20Sopenharmony_ci if (r < 0 || phy->fw_blob_size == 0) 8258c2ecf20Sopenharmony_ci pn544_hci_i2c_fw_work_complete(phy, r); 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci case FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER: 8298c2ecf20Sopenharmony_ci r = phy->fw_cmd_result; 8308c2ecf20Sopenharmony_ci if (r < 0) 8318c2ecf20Sopenharmony_ci goto exit_state_wait_secure_write_answer; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (r == PN544_FW_CMD_RESULT_CHUNK_OK) { 8348c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_secure_write_frame(phy); 8358c2ecf20Sopenharmony_ci goto exit_state_wait_secure_write_answer; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (phy->fw_written == phy->fw_blob_size) { 8398c2ecf20Sopenharmony_ci secure_blob = (struct pn544_i2c_fw_secure_blob *) 8408c2ecf20Sopenharmony_ci (phy->fw_blob_data + phy->fw_blob_size); 8418c2ecf20Sopenharmony_ci phy->fw_size -= phy->fw_blob_size + 8428c2ecf20Sopenharmony_ci PN544_FW_SECURE_BLOB_HEADER_LEN; 8438c2ecf20Sopenharmony_ci if (phy->fw_size >= PN544_FW_SECURE_BLOB_HEADER_LEN 8448c2ecf20Sopenharmony_ci + PN544_FW_SECURE_FRAME_HEADER_LEN) { 8458c2ecf20Sopenharmony_ci phy->fw_blob_data = secure_blob->data; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci phy->fw_written = 0; 8488c2ecf20Sopenharmony_ci r = pn544_hci_i2c_fw_secure_write_frame(phy); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ciexit_state_wait_secure_write_answer: 8538c2ecf20Sopenharmony_ci if (r < 0 || phy->fw_size == 0) 8548c2ecf20Sopenharmony_ci pn544_hci_i2c_fw_work_complete(phy, r); 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci default: 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params enable_gpios = { 1, 0, false }; 8638c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params firmware_gpios = { 2, 0, false }; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_pn544_gpios[] = { 8668c2ecf20Sopenharmony_ci { "enable-gpios", &enable_gpios, 1 }, 8678c2ecf20Sopenharmony_ci { "firmware-gpios", &firmware_gpios, 1 }, 8688c2ecf20Sopenharmony_ci { }, 8698c2ecf20Sopenharmony_ci}; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_probe(struct i2c_client *client, 8728c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 8758c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy; 8768c2ecf20Sopenharmony_ci int r = 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s\n", __func__); 8798c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "IRQ: %d\n", client->irq); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 8828c2ecf20Sopenharmony_ci nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); 8838c2ecf20Sopenharmony_ci return -ENODEV; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy), 8878c2ecf20Sopenharmony_ci GFP_KERNEL); 8888c2ecf20Sopenharmony_ci if (!phy) 8898c2ecf20Sopenharmony_ci return -ENOMEM; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci INIT_WORK(&phy->fw_work, pn544_hci_i2c_fw_work); 8928c2ecf20Sopenharmony_ci phy->fw_work_state = FW_WORK_STATE_IDLE; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci phy->i2c_dev = client; 8958c2ecf20Sopenharmony_ci i2c_set_clientdata(client, phy); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci r = devm_acpi_dev_add_driver_gpios(dev, acpi_pn544_gpios); 8988c2ecf20Sopenharmony_ci if (r) 8998c2ecf20Sopenharmony_ci dev_dbg(dev, "Unable to add GPIO mapping table\n"); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* Get EN GPIO */ 9028c2ecf20Sopenharmony_ci phy->gpiod_en = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 9038c2ecf20Sopenharmony_ci if (IS_ERR(phy->gpiod_en)) { 9048c2ecf20Sopenharmony_ci nfc_err(dev, "Unable to get EN GPIO\n"); 9058c2ecf20Sopenharmony_ci return PTR_ERR(phy->gpiod_en); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* Get FW GPIO */ 9098c2ecf20Sopenharmony_ci phy->gpiod_fw = devm_gpiod_get(dev, "firmware", GPIOD_OUT_LOW); 9108c2ecf20Sopenharmony_ci if (IS_ERR(phy->gpiod_fw)) { 9118c2ecf20Sopenharmony_ci nfc_err(dev, "Unable to get FW GPIO\n"); 9128c2ecf20Sopenharmony_ci return PTR_ERR(phy->gpiod_fw); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci pn544_hci_i2c_platform_init(phy); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci r = devm_request_threaded_irq(&client->dev, client->irq, NULL, 9188c2ecf20Sopenharmony_ci pn544_hci_i2c_irq_thread_fn, 9198c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 9208c2ecf20Sopenharmony_ci PN544_HCI_I2C_DRIVER_NAME, phy); 9218c2ecf20Sopenharmony_ci if (r < 0) { 9228c2ecf20Sopenharmony_ci nfc_err(&client->dev, "Unable to register IRQ handler\n"); 9238c2ecf20Sopenharmony_ci return r; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci r = pn544_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, 9278c2ecf20Sopenharmony_ci PN544_I2C_FRAME_HEADROOM, PN544_I2C_FRAME_TAILROOM, 9288c2ecf20Sopenharmony_ci PN544_HCI_I2C_LLC_MAX_PAYLOAD, 9298c2ecf20Sopenharmony_ci pn544_hci_i2c_fw_download, &phy->hdev); 9308c2ecf20Sopenharmony_ci if (r < 0) 9318c2ecf20Sopenharmony_ci return r; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci return 0; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic int pn544_hci_i2c_remove(struct i2c_client *client) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci struct pn544_i2c_phy *phy = i2c_get_clientdata(client); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "%s\n", __func__); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci cancel_work_sync(&phy->fw_work); 9438c2ecf20Sopenharmony_ci if (phy->fw_work_state != FW_WORK_STATE_IDLE) 9448c2ecf20Sopenharmony_ci pn544_hci_i2c_fw_work_complete(phy, -ENODEV); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci pn544_hci_remove(phy->hdev); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (phy->powered) 9498c2ecf20Sopenharmony_ci pn544_hci_i2c_disable(phy); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci return 0; 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cistatic const struct of_device_id of_pn544_i2c_match[] = { 9558c2ecf20Sopenharmony_ci { .compatible = "nxp,pn544-i2c", }, 9568c2ecf20Sopenharmony_ci {}, 9578c2ecf20Sopenharmony_ci}; 9588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_pn544_i2c_match); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic struct i2c_driver pn544_hci_i2c_driver = { 9618c2ecf20Sopenharmony_ci .driver = { 9628c2ecf20Sopenharmony_ci .name = PN544_HCI_I2C_DRIVER_NAME, 9638c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(of_pn544_i2c_match), 9648c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match), 9658c2ecf20Sopenharmony_ci }, 9668c2ecf20Sopenharmony_ci .probe = pn544_hci_i2c_probe, 9678c2ecf20Sopenharmony_ci .id_table = pn544_hci_i2c_id_table, 9688c2ecf20Sopenharmony_ci .remove = pn544_hci_i2c_remove, 9698c2ecf20Sopenharmony_ci}; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cimodule_i2c_driver(pn544_hci_i2c_driver); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 9748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 975