/*
* I2C Link Layer for PN544 HCI based Driver
*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/crc-ccitt.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/nfc.h>
#include <linux/firmware.h>
#include <linux/platform_data/pn544.h>
#include <asm/unaligned.h>
#include <net/nfc/hci.h>
#include <net/nfc/llc.h>
#include <net/nfc/nfc.h>
#include "pn544.h"
#define PN544_I2C_FRAME_HEADROOM 1
#define PN544_I2C_FRAME_TAILROOM 2
/* framing in HCI mode */
#define PN544_HCI_I2C_LLC_LEN 1
#define PN544_HCI_I2C_LLC_CRC 2
#define PN544_HCI_I2C_LLC_LEN_CRC (PN544_HCI_I2C_LLC_LEN + \
PN544_HCI_I2C_LLC_CRC)
#define PN544_HCI_I2C_LLC_MIN_SIZE (1 + PN544_HCI_I2C_LLC_LEN_CRC)
#define PN544_HCI_I2C_LLC_MAX_PAYLOAD 29
#define PN544_HCI_I2C_LLC_MAX_SIZE (PN544_HCI_I2C_LLC_LEN_CRC + 1 + \
PN544_HCI_I2C_LLC_MAX_PAYLOAD)
static struct i2c_device_id pn544_hci_i2c_id_table[] = {
{"pn544", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
/*
* Exposed through the 4 most significant bytes
* from the HCI SW_VERSION first byte, a.k.a.
* SW RomLib.
*/
#define PN544_HW_VARIANT_C2 0xa
#define PN544_HW_VARIANT_C3 0xb
#define PN544_FW_CMD_RESET 0x01
#define PN544_FW_CMD_WRITE 0x08
#define PN544_FW_CMD_CHECK 0x06
#define PN544_FW_CMD_SECURE_WRITE 0x0C
#define PN544_FW_CMD_SECURE_CHUNK_WRITE 0x0D
struct pn544_i2c_fw_frame_write {
u8 cmd;
u16 be_length;
u8 be_dest_addr[3];
u16 be_datalen;
u8 data[];
} __packed;
struct pn544_i2c_fw_frame_check {
u8 cmd;
u16 be_length;
u8 be_start_addr[3];
u16 be_datalen;
u16 be_crc;
} __packed;
struct pn544_i2c_fw_frame_response {
u8 status;
u16 be_length;
} __packed;
struct pn544_i2c_fw_blob {
u32 be_size;
u32 be_destaddr;
u8 data[];
};
struct pn544_i2c_fw_secure_frame {
u8 cmd;
u16 be_datalen;
u8 data[];
} __packed;
struct pn544_i2c_fw_secure_blob {
u64 header;
u8 data[];
};
#define PN544_FW_CMD_RESULT_TIMEOUT 0x01
#define PN544_FW_CMD_RESULT_BAD_CRC 0x02
#define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08
#define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B
#define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11
#define PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND 0x13
#define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18
#define PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR 0x19
#define PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR 0x1D
#define PN544_FW_CMD_RESULT_MEMORY_ERROR 0x20
#define PN544_FW_CMD_RESULT_CHUNK_OK 0x21
#define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74
#define PN544_FW_CMD_RESULT_COMMAND_REJECTED 0xE0
#define PN544_FW_CMD_RESULT_CHUNK_ERROR 0xE6
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define PN544_FW_WRITE_BUFFER_MAX_LEN 0x9f7
#define PN544_FW_I2C_MAX_PAYLOAD PN544_HCI_I2C_LLC_MAX_SIZE
#define PN544_FW_I2C_WRITE_FRAME_HEADER_LEN 8
#define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\
PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\
PN544_FW_WRITE_BUFFER_MAX_LEN)
#define PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN 3
#define PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN (PN544_FW_I2C_MAX_PAYLOAD -\
PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN)
#define PN544_FW_SECURE_FRAME_HEADER_LEN 3
#define PN544_FW_SECURE_BLOB_HEADER_LEN 8
#define FW_WORK_STATE_IDLE 1
#define FW_WORK_STATE_START 2
#define FW_WORK_STATE_WAIT_WRITE_ANSWER 3
#define FW_WORK_STATE_WAIT_CHECK_ANSWER 4
#define FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER 5
struct pn544_i2c_phy {
struct i2c_client *i2c_dev;
struct nfc_hci_dev *hdev;
unsigned int gpio_en;
unsigned int gpio_irq;
unsigned int gpio_fw;
unsigned int en_polarity;
u8 hw_variant;
struct work_struct fw_work;
int fw_work_state;
char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
const struct firmware *fw;
u32 fw_blob_dest_addr;
size_t fw_blob_size;
const u8 *fw_blob_data;
size_t fw_written;
size_t fw_size;
int fw_cmd_result;
int powered;
int run_mode;
int hard_fault; /*
* < 0 if hardware error occured (e.g. i2c err)
* and prevents normal operation.
*/
};
#define I2C_DUMP_SKB(info, skb) \
do { \
pr_debug("%s:\n", info); \
print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \
16, 1, (skb)->data, (skb)->len, 0); \
} while (0)
static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
{
int polarity, retry, ret;
char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 };
int count = sizeof(rset_cmd);
nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
/* Disable fw download */
gpio_set_value_cansleep(phy->gpio_fw, 0);
for (polarity = 0; polarity < 2; polarity++) {
phy->en_polarity = polarity;
retry =