Updated corresponding to - NFC_AR_00_E000_12.02.01_OpnSrc

This commit is contained in:
nxf35421
2021-02-26 15:55:00 +05:30
parent 2ec82a2bfd
commit 0d82b80e37
10 changed files with 1946 additions and 1886 deletions

View File

@@ -1,6 +1,8 @@
#
# Makefile for nfc devices
#
obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o
pn553_i2c-objs := common.o common_ese.o i2c_drv.o recovery_seq.o recovery_fw.o
ccflags-y += -DRECOVERY_ENABLE -UDEBUG
obj-$(CONFIG_NXP_NFC_I2C) += pn553_i2c.o
pn553_i2c-objs := common.o common_ese.o i2c_drv.o
pn553_i2c-$(CONFIG_NXP_NFC_RECOVERY) += recovery_seq.o recovery_fw.o
#ccflags-y += -DDEBUG

View File

@@ -1,4 +1,5 @@
/******************************************************************************
* Copyright (C) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2021 NXP
* *
* This program is free software; you can redistribute it and/or modify
@@ -22,16 +23,13 @@
#include <linux/version.h>
#include "common.h"
#include "common_ese.h"
#if defined(RECOVERY_ENABLE)
#include "recovery_seq.h"
#endif
int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs,
int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
uint8_t interface)
{
struct device_node *np = dev->of_node;
platform_gpio_t *nfc_gpio = &nfc_configs->gpio;
struct platform_gpio *nfc_gpio = &nfc_configs->gpio;
if (!np) {
pr_err("nfc of_node NULL\n");
@@ -58,9 +56,8 @@ int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs,
}
nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0);
if ((!gpio_is_valid(nfc_gpio->dwl_req))) {
if ((!gpio_is_valid(nfc_gpio->dwl_req)))
pr_warn("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req);
}
pr_info("%s: %d, %d, %d, %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven,
nfc_gpio->dwl_req);
@@ -80,7 +77,8 @@ void set_valid_gpio(int gpio, int value)
int get_valid_gpio(int gpio)
{
int value = -1;
int value = -EINVAL;
if (gpio_is_valid(gpio)) {
value = gpio_get_value(gpio);
pr_debug("%s gpio %d value %d\n", __func__, gpio, value);
@@ -90,13 +88,14 @@ int get_valid_gpio(int gpio)
void gpio_set_ven(struct nfc_dev *nfc_dev, int value)
{
platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio;
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
if (gpio_get_value(nfc_gpio->ven) != value) {
pr_debug("%s: gpio_set_ven %d\n", __func__, value);
pr_debug("%s: value %d\n", __func__, value);
/*reset on change in level from high to low */
if (value) {
common_ese_on_hard_reset(nfc_dev);
}
if (value)
ese_cold_reset_release(nfc_dev);
gpio_set_value(nfc_gpio->ven, value);
// hardware dependent delay
usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC,
@@ -107,6 +106,7 @@ void gpio_set_ven(struct nfc_dev *nfc_dev, int value)
int configure_gpio(unsigned int gpio, int flag)
{
int ret;
pr_debug("%s: nfc gpio [%d] flag [%01x]\n", __func__, gpio, flag);
if (gpio_is_valid(gpio)) {
ret = gpio_request(gpio, "nfc_gpio");
@@ -146,21 +146,21 @@ int configure_gpio(unsigned int gpio, int flag)
return ret;
}
void gpio_free_all(nfc_dev_t *nfc_dev)
void gpio_free_all(struct nfc_dev *nfc_dev)
{
platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio;
if (gpio_is_valid(nfc_gpio->dwl_req)) {
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
if (gpio_is_valid(nfc_gpio->dwl_req))
gpio_free(nfc_gpio->dwl_req);
}
if (gpio_is_valid(nfc_gpio->irq)) {
if (gpio_is_valid(nfc_gpio->irq))
gpio_free(nfc_gpio->irq);
}
if (gpio_is_valid(nfc_gpio->ven)) {
if (gpio_is_valid(nfc_gpio->ven))
gpio_free(nfc_gpio->ven);
}
}
void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count)
void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count)
{
pr_debug("%s: entry\n", __func__);
device_destroy(nfc_dev->nfc_class, nfc_dev->devno);
@@ -169,11 +169,12 @@ void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count)
unregister_chrdev_region(nfc_dev->devno, count);
}
int nfc_misc_register(nfc_dev_t *nfc_dev,
int nfc_misc_register(struct nfc_dev *nfc_dev,
const struct file_operations *nfc_fops,
int count, char *devname, char *classname)
{
int ret = 0;
ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname);
if (ret < 0) {
pr_err("%s: failed to alloc chrdev region ret %d\n", __func__, ret);
@@ -217,10 +218,11 @@ int nfc_misc_register(nfc_dev_t *nfc_dev,
*
* Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case
*/
static int nfc_ioctl_power_states(nfc_dev_t *nfc_dev, unsigned long arg)
static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg)
{
int ret = 0;
platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio;
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
if (arg == NFC_POWER_OFF) {
/*
* We are attempting a hardware reset so let us disable
@@ -287,6 +289,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{
int ret = 0;
struct nfc_dev *nfc_dev = pfile->private_data;
if (!nfc_dev)
return -ENODEV;
@@ -301,13 +304,6 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
case ESE_GET_PWR:
ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE);
break;
case NFC_GET_PLATFORM_TYPE:
ret = nfc_dev->interface;
break;
case NFC_GET_NFC_STATE:
ret = nfc_dev->nfc_state;
pr_debug("nfc get state %d\n", ret);
break;
case NFC_GET_IRQ_STATE:
ret = gpio_get_value(nfc_dev->configs.gpio.irq);
break;
@@ -320,7 +316,8 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
int nfc_dev_open(struct inode *inode, struct file *filp)
{
nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev);
struct nfc_dev *nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev);
pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode));
mutex_lock(&nfc_dev->dev_ref_mutex);
@@ -339,7 +336,8 @@ int nfc_dev_open(struct inode *inode, struct file *filp)
int nfc_dev_close(struct inode *inode, struct file *filp)
{
nfc_dev_t *nfc_dev = container_of(inode->i_cdev, nfc_dev_t, c_dev);
struct nfc_dev *nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev);
pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode));
mutex_lock(&nfc_dev->dev_ref_mutex);
if (nfc_dev->dev_ref_count == 1) {
@@ -351,7 +349,8 @@ int nfc_dev_close(struct inode *inode, struct file *filp)
else {
nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS_NFC);
/* Uncomment below line incase of eSE calls flow is via NFC driver
* i.e. direct calls from SPI HAL to NFC driver*/
* i.e. direct calls from SPI HAL to NFC driver
*/
//nfc_ese_pwr(nfc_dev, ESE_RST_PROT_DIS);
}
filp->private_data = NULL;
@@ -360,248 +359,321 @@ int nfc_dev_close(struct inode *inode, struct file *filp)
return 0;
}
static int get_nfcc_boot_state(struct nfc_dev *nfc_dev)
/**
* get_nfcc_chip_type_dl() - get chip type in fw download command;
* @nfc_dev: nfc device data structure
*
* Perform get version command and determine chip
* type from response.
*
* @Return: enum chip_types value
*
*/
static enum chip_types get_nfcc_chip_type_dl(struct nfc_dev *nfc_dev)
{
int ret = 0;
char get_version_cmd[] = { 0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF };
char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 };
char rsp_buf[MAX_BUFFER_SIZE];
int cmd_length = 0;
uint8_t *cmd = nfc_dev->write_kbuf;
uint8_t *rsp = nfc_dev->read_kbuf;
enum chip_types chip_type = CHIP_UNKNOWN;
pr_debug("%s:Sending GET_VERSION cmd\n", __func__);
ret = nfc_dev->nfc_write(nfc_dev, get_version_cmd,
sizeof(get_version_cmd), MAX_RETRY_COUNT);
*cmd++ = 0x00;
*cmd++ = 0x04;
*cmd++ = 0xF1;
*cmd++ = 0x00;
*cmd++ = 0x00;
*cmd++ = 0x00;
*cmd++ = 0x6E;
*cmd++ = 0xEF;
cmd_length = cmd - nfc_dev->write_kbuf;
pr_debug("%s:Sending GET_VERSION cmd of size=%d\n", __func__, cmd_length);
ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT);
if (ret <= 0) {
pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret);
goto err;
}
memset(rsp_buf, 0x00, MAX_BUFFER_SIZE);
memset(rsp, 0x00, DL_GET_VERSION_RSP_LEN_2);
pr_debug("%s:Reading response of GET_VERSION cmd\n", __func__);
ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT);
ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_VERSION_RSP_LEN_2, NCI_CMD_RSP_TIMEOUT);
if (ret <= 0) {
pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret);
goto err;
} else if (rsp_buf[0] == FW_MSG_CMD_RSP
&& ret >= DL_GET_VERSION_RSP_LEN_2) {
#if defined(RECOVERY_ENABLE)
nfc_dev->fw_major_version = rsp_buf[FW_MAJOR_VER_OFFSET];
/* recvoery neeeded only for SN1xx */
if(rsp_buf[FW_ROM_CODE_VER_OFFSET] == RECOVERY_FW_SUPPORTED_ROM_VER &&
nfc_dev->fw_major_version == RECOVERY_FW_SUPPORTED_MAJOR_VER)
nfc_dev->recovery_required = true;
#endif
pr_info("%s:NFC chip_type 0x%02x rom_version 0x%02x fw_minor 0x%02x fw_major 0x%02x\n",
__func__, rsp_buf[3], rsp_buf[4], rsp_buf[6], rsp_buf[7]);
} else if (rsp_buf[0] != FW_MSG_CMD_RSP
&& ret >= (NCI_HDR_LEN + rsp_buf[NCI_PAYLOAD_LEN_IDX])) {
pr_info("%s:NFC response bytes 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__,
rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[3]);
pr_debug("%s NFCC booted in NCI mode %d\n", __func__, __LINE__);
return NFC_STATE_NCI;
}
if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) {
pr_debug("%s:Sending GET_SESSION_STATE cmd \n", __func__);
ret = nfc_dev->nfc_write(nfc_dev, get_session_state_cmd,
sizeof(get_session_state_cmd),
MAX_RETRY_COUNT);
if (ret <= 0) {
pr_err("%s: - nfc get session state cmd err ret %d\n", __func__, ret);
goto err;
nfc_dev->fw_major_version = rsp[FW_MAJOR_VER_OFFSET];
if (rsp[FW_ROM_CODE_VER_OFFSET] == SN1XX_ROM_VER &&
rsp[FW_MAJOR_VER_OFFSET] == SN1xx_MAJOR_VER)
chip_type = CHIP_SN1XX;
else if (rsp[FW_ROM_CODE_VER_OFFSET] == SN220_ROM_VER &&
rsp[FW_MAJOR_VER_OFFSET] == SN220_MAJOR_VER)
chip_type = CHIP_SN220;
pr_info("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n",
__func__, rsp[3], rsp[4], rsp[6], rsp[7]);
}
memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN);
pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__);
ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT);
if (ret <= 0) {
pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret);
goto err;
}
pr_debug("Response bytes are %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x",
rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5],
rsp_buf[6], rsp_buf[7]);
/*verify fw in non-teared state */
if (rsp_buf[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) {
pr_debug("%s NFCC booted in teared fw state %d\n", __func__, __LINE__);
return NFC_STATE_FW_TEARED;
}
pr_debug("%s NFCC booted in FW DN mode %d\n", __func__, __LINE__);
return NFC_STATE_FW_DWL;
err:
pr_err("%s Unlikely NFCC not booted in FW DN mode %d\n", __func__, __LINE__);
return NFC_STATE_UNKNOWN;
return chip_type;
}
int validate_nfc_state_nci(nfc_dev_t *nfc_dev)
{
platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio;
if (!gpio_get_value(nfc_gpio->ven)) {
pr_err("VEN LOW - NFCC powered off\n");
return -ENODEV;
} else {
if (get_valid_gpio(nfc_gpio->dwl_req) == 1) {
pr_err("FW download in-progress\n");
return -EBUSY;
} else if (nfc_dev->nfc_state == NFC_STATE_FW_DWL) {
pr_err("FW download state \n");
return -EBUSY;
}
}
return 0;
}
static int set_nfcc_nci_state(struct nfc_dev *nfc_dev)
/**
* get_nfcc_session_state_dl() - gets the session state
* @nfc_dev: nfc device data structure
*
* Performs get session command and determine
* the nfcc state based on session status.
*
* @Return nfcc state based on session status.
* NFC_STATE_FW_TEARED if sessionis not closed
* NFC_STATE_FW_DWL if session closed
* NFC_STATE_UNKNOWN in error cases.
*/
enum nfc_state_flags get_nfcc_session_state_dl(struct nfc_dev *nfc_dev)
{
int ret = 0;
char dl_reset_cmd[] = { 0x00, 0x04, 0xF0, 0x00, 0x00, 0x00, 0x18, 0x5B };
int cmd_length = 0;
uint8_t *cmd = nfc_dev->write_kbuf;
uint8_t *rsp = nfc_dev->read_kbuf;
enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN;
pr_debug("%s:Sending DL_RESET to boot in NCI mode\n", __func__);
ret = nfc_dev->nfc_write(nfc_dev, dl_reset_cmd,
sizeof(dl_reset_cmd), MAX_RETRY_COUNT);
*cmd++ = 0x00;
*cmd++ = 0x04;
*cmd++ = 0xF2;
*cmd++ = 0x00;
*cmd++ = 0x00;
*cmd++ = 0x00;
*cmd++ = 0xF5;
*cmd++ = 0x33;
cmd_length = cmd - nfc_dev->write_kbuf;
pr_debug("%s:Sending GET_SESSION_STATE cmd of size=%d\n", __func__, cmd_length);
ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT);
if (ret <= 0) {
pr_err("%s: nfc dl reset cmd err ret %d\n", __func__, ret);
pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret);
goto err;
}
usleep_range(NFC_SOFT_RESET_WAIT_TIME_USEC,
NFC_SOFT_RESET_WAIT_TIME_USEC + 100);
pr_debug("%s NFCC booted in NCI mode %d\n", __func__, __LINE__);
return 0;
memset(rsp, 0x00, DL_GET_SESSION_STATE_RSP_LEN);
pr_debug("%s:Reading response of GET_SESSION_STATE cmd\n", __func__);
ret = nfc_dev->nfc_read(nfc_dev, rsp, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT);
if (ret <= 0) {
pr_err("%s: - nfc get session rsp error ret %d\n", __func__, ret);
goto err;
}
if (rsp[0] != FW_MSG_CMD_RSP) {
pr_err("%s: - nfc invalid get session state rsp\n", __func__);
goto err;
}
pr_debug("Response bytes are %02x%02x%02x%02x%02x%02x%02x%02x",
rsp[0], rsp[1], rsp[2], rsp[3], rsp[4], rsp[5], rsp[6], rsp[7]);
/*verify fw in non-teared state */
if (rsp[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) {
pr_err("%s NFCC booted in FW teared state\n", __func__);
nfc_state = NFC_STATE_FW_TEARED;
} else {
pr_info("%s NFCC booted in FW DN mode\n", __func__);
nfc_state = NFC_STATE_FW_DWL;
}
err:
pr_err("%s Unlikely NFCC not booted in NCI mode %d\n", __func__, __LINE__);
return -1;
return nfc_state;
}
static bool do_nci_reset(nfc_dev_t *nfc_dev) {
const uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00};
char rsp_buf[MAX_BUFFER_SIZE];
int status = 0;
/**
* get_nfcc_chip_type() - get nfcc chip type in nci mode.
* @nfc_dev: nfc device data structure.
*
* Function to perform nci core reset and extract
* chip type from the response.
*
* @Return: enum chip_types value
*
*/
static enum chip_types get_nfcc_chip_type(struct nfc_dev *nfc_dev)
{
int ret = 0;
int cmd_length = 0;
uint8_t major_version = 0;
uint8_t rom_version = 0;
uint8_t *cmd = nfc_dev->write_kbuf;
uint8_t *rsp = nfc_dev->read_kbuf;
enum chip_types chip_type = CHIP_UNKNOWN;
if (NULL == nfc_dev) {
pr_err("%s invalid params ", __func__);
return false;
}
pr_debug("%s Entry \n", __func__);
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);
pr_debug(" %s send core reset cmd \n", __func__);
status = nfc_dev->nfc_write(nfc_dev, cmd_reset_nci,
sizeof(cmd_reset_nci), NO_RETRY);
if (status <= 0) {
pr_err(" %s: nfc nci core reset cmd err status %d\n", __func__, status);
return false;
*cmd++ = 0x20;
*cmd++ = 0x00;
*cmd++ = 0x01;
*cmd++ = 0x00;
cmd_length = cmd - nfc_dev->write_kbuf;
pr_debug("%s:Sending NCI Core Reset cmd of size=%d\n", __func__, cmd_length);
ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, NO_RETRY);
if (ret <= 0) {
pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret);
goto err;
}
usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100);
nfc_dev->nfc_enable_intr(nfc_dev);
pr_debug(" %s Reading response of NCI reset \n", __func__);
memset(rsp_buf, 0x00, MAX_BUFFER_SIZE);
status = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE, NCI_RESET_RESP_TIMEOUT);
if (status <= 0) {
pr_err(" %s - nfc nci rest rsp error status %d\n", __func__, status);
nfc_dev->nfc_disable_intr(nfc_dev);
return false;
memset(rsp, 0x00, NCI_RESET_RSP_LEN);
pr_debug("%s:Reading NCI Core Reset rsp\n", __func__);
ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_RSP_LEN, NCI_CMD_RSP_TIMEOUT);
if (ret <= 0) {
pr_err("%s: - nfc nci core reset rsp error ret %d\n", __func__, ret);
goto err_disable_intr;
}
pr_debug(" %s: nci core reset response 0x%02x 0x%02x 0x%02x 0x%02x \n",
__func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3]);
if(rsp_buf[0] != NCI_MSG_RSP) {
pr_debug(" %s: nci core reset response 0x%02x%02x%02x%02x\n",
__func__, rsp[0], rsp[1], rsp[2], rsp[3]);
if (rsp[0] != NCI_MSG_RSP) {
/* reset response failed response*/
pr_err("%s invalid nci core reset response");
nfc_dev->nfc_disable_intr(nfc_dev);
return false;
pr_err("%s invalid nci core reset response", __func__);
goto err_disable_intr;
}
memset(rsp_buf, 0x00, MAX_BUFFER_SIZE);
memset(rsp, 0x00, NCI_RESET_NTF_LEN);
/* read nci rest response ntf */
status = nfc_dev->nfc_read(nfc_dev, rsp_buf, MAX_BUFFER_SIZE, NCI_CMD_RSP_TIMEOUT);
if (status <= 0) {
pr_err("%s - nfc nci rest rsp ntf error status %d\n"
, __func__, status);
ret = nfc_dev->nfc_read(nfc_dev, rsp, NCI_RESET_NTF_LEN, NCI_CMD_RSP_TIMEOUT);
if (ret <= 0) {
pr_err("%s - nfc nci rest rsp ntf error status %d\n", __func__, ret);
goto err_disable_intr;
}
pr_debug(" %s:NFC NCI Reset Response ntf 0x%02x 0x%02x 0x%02x 0x%02x \n",
__func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3]);
if (rsp[0] == NCI_MSG_NTF) {
/* read version info from NCI Reset Notification */
rom_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 3];
major_version = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] - 2];
/* determine chip type based on version info */
if (rom_version == SN1XX_ROM_VER && major_version == SN1xx_MAJOR_VER)
chip_type = CHIP_SN1XX;
else if (rom_version == SN220_ROM_VER && major_version == SN220_MAJOR_VER)
chip_type = CHIP_SN220;
pr_debug(" %s:NCI Core Reset ntf 0x%02x%02x%02x%02x\n",
__func__, rsp[0], rsp[1], rsp[2], rsp[3]);
}
err_disable_intr:
nfc_dev->nfc_disable_intr(nfc_dev);
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);
return true;
err:
return chip_type;
}
/**
* validate_download_gpio() - validate download gpio.
* @nfc_dev: nfc_dev device data structure.
* @chip_type: chip type of the platform.
*
* Validates dwnld gpio should configured for supported and
* should not be configured for unsupported platform.
*
* @Return: true if gpio validation successful ortherwise
* false if validation fails.
*/
static bool validate_download_gpio(struct nfc_dev *nfc_dev, enum chip_types chip_type)
{
bool status = false;
struct platform_gpio *nfc_gpio;
if (nfc_dev == NULL) {
pr_err("%s nfc devices structure is null\n");
return status;
}
nfc_gpio = &nfc_dev->configs.gpio;
if (chip_type == CHIP_SN1XX) {
/* gpio should be configured for SN1xx */
status = gpio_is_valid(nfc_gpio->dwl_req);
} else if (chip_type == CHIP_SN220) {
/* gpio should not be configured for SN220 */
set_valid_gpio(nfc_gpio->dwl_req, 0);
gpio_free(nfc_gpio->dwl_req);
nfc_gpio->dwl_req = -EINVAL;
status = true;
}
return status;
}
/* Check for availability of NFC controller hardware */
int nfcc_hw_check(struct nfc_dev *nfc_dev)
{
int ret = 0;
uint8_t nfc_state = NFC_STATE_UNKNOWN;
if(do_nci_reset(nfc_dev)) {
pr_info("%s recovery not required", __func__);
return ret;
enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN;
enum chip_types chip_type = CHIP_UNKNOWN;
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
/*get fw version in nci mode*/
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);
chip_type = get_nfcc_chip_type(nfc_dev);
/*get fw version in fw dwl mode*/
if (chip_type == CHIP_UNKNOWN) {
nfc_dev->nfc_enable_intr(nfc_dev);
/*Chip is unknown, initially assume with fw dwl pin enabled*/
set_valid_gpio(nfc_gpio->dwl_req, 1);
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);
chip_type = get_nfcc_chip_type_dl(nfc_dev);
/*get the state of nfcc normal/teared in fw dwl mode*/
} else {
nfc_state = NFC_STATE_NCI;
}
nfc_dev->nfc_enable_intr(nfc_dev);
/*set download mode for i2c products with dwl pin */
enable_dwnld_mode(nfc_dev, true);
/*validate gpio config required as per the chip*/
if (!validate_download_gpio(nfc_dev, chip_type)) {
pr_info("%s gpio validation fail", __func__);
ret = -ENXIO;
goto err;
}
nfc_state = get_nfcc_boot_state(nfc_dev);
/*check whether the NFCC is in FW DN or Teared state*/
if (nfc_state != NFC_STATE_NCI)
nfc_state = get_nfcc_session_state_dl(nfc_dev);
/*nfcc state specific operations */
switch (nfc_state) {
case NFC_STATE_FW_DWL:
usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC,
NFC_GPIO_SET_WAIT_TIME_USEC + 100);
if (set_nfcc_nci_state(nfc_dev)) {
pr_debug("%s: - NFCC DL Reset Fails\n", __func__);
} else {
nfc_state = NFC_STATE_NCI;
/*set NCI mode for i2c products with dwl pin */
enable_dwnld_mode(nfc_dev, false);
}
/* fall-through */
case NFC_STATE_NCI:
nfc_dev->nfc_ven_enabled = true;
pr_debug("%s: - NFCC HW detected\n", __func__);
break;
case NFC_STATE_FW_TEARED:
pr_warn("%s: - NFCC FW Teared State\n", __func__);
#if defined(RECOVERY_ENABLE)
if(nfc_dev->recovery_required &&
(do_recovery(nfc_dev) == STATUS_SUCCESS)) {
pr_debug("%s: - NFCC HW detected\n", __func__);
#if IS_ENABLED(CONFIG_NXP_NFC_RECOVERY)
/* recovery neeeded only for SN1xx */
if (chip_type == CHIP_SN1XX) {
if (do_recovery(nfc_dev) == STATUS_FAILED)
pr_debug("%s: - nfcc recoverey failed\n", __func__);
else
pr_debug("%s: - nfcc recovered successfully\n", __func__);
nfc_state = get_nfcc_session_state_dl(nfc_dev);
}
#endif
nfc_dev->nfc_ven_enabled = true;
/*fallthrough*/
case NFC_STATE_FW_DWL:
case NFC_STATE_NCI:
break;
case NFC_STATE_UNKNOWN:
default:
ret = -ENXIO;
pr_debug("%s: - NFCC HW not available\n", __func__);
pr_err("%s: - NFCC HW not available\n", __func__);
goto err;
};
nfc_dev->nfc_disable_intr(nfc_dev);
if (nfc_state == NFC_STATE_FW_TEARED) {
nfc_state = NFC_STATE_FW_DWL;
}
nfc_dev->nfc_state = nfc_state;
nfc_dev->nfc_ven_enabled = true;
err:
nfc_dev->nfc_disable_intr(nfc_dev);
set_valid_gpio(nfc_gpio->dwl_req, 0);
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);
return ret;
}
void enable_dwnld_mode(nfc_dev_t* nfc_dev, bool value) {
if(nfc_dev != NULL) {
platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio;
if (get_valid_gpio(nfc_gpio->dwl_req) != -1) {
set_valid_gpio(nfc_gpio->dwl_req, value);
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);
}
}
}
void set_nfcc_state_from_rsp(struct nfc_dev *dev, const char *buf,
const int count)
int validate_nfc_state_nci(struct nfc_dev *nfc_dev)
{
int packet_size = 0;
if (buf[0] == FW_MSG_CMD_RSP && buf[1] >= FW_MIN_PAYLOAD_LEN) {
packet_size = FW_HDR_LEN + buf[FW_PAYLOAD_LEN_IDX] + FW_CRC_LEN;
if (packet_size == count && dev->nfc_state == NFC_STATE_NCI)
dev->nfc_state = NFC_STATE_FW_DWL;
} else {
packet_size = NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX];
if (packet_size == count && dev->nfc_state == NFC_STATE_FW_DWL)
dev->nfc_state = NFC_STATE_NCI;
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
if (!gpio_get_value(nfc_gpio->ven)) {
pr_err("VEN LOW - NFCC powered off\n");
return -ENODEV;
}
if (count != packet_size) {
pr_err("%s: Unlikely mismatch in packet size received (%d/%d)/\n", __func__,
packet_size, count);
if (get_valid_gpio(nfc_gpio->dwl_req) == 1) {
pr_err("FW download in-progress\n");
return -EBUSY;
}
if (nfc_dev->nfc_state != NFC_STATE_NCI) {
pr_err("FW download state\n");
return -EBUSY;
}
return 0;
}

View File

@@ -1,4 +1,5 @@
/******************************************************************************
* Copyright (C) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2021 NXP
* *
* This program is free software; you can redistribute it and/or modify
@@ -38,6 +39,7 @@
// NCI packet details
#define NCI_MSG_CMD 0x20
#define NCI_MSG_RSP 0x40
#define NCI_MSG_NTF 0x60
#define NCI_HDR_LEN 3
#define NCI_PAYLOAD_IDX 3
#define NCI_PAYLOAD_LEN_IDX 2
@@ -57,6 +59,13 @@
#define NCI_RESET_RSP_LEN (4)
#define NCI_RESET_NTF_LEN (13)
#define SN1XX_ROM_VER 0x01
#define SN1xx_MAJOR_VER 0x10
#define SN220_ROM_VER 0x01
#define SN220_MAJOR_VER 0x01
#define FW_ROM_CODE_VER_OFFSET 4
#define FW_MAJOR_VER_OFFSET 7
#define DL_GET_VERSION_CMD_LEN (8)
#define DL_GET_VERSION_RSP_LEN_1 (12)
#define DL_GET_VERSION_RSP_LEN_2 (20)
@@ -77,14 +86,13 @@
#define MAX_IRQ_WAIT_TIME (90)
#define WAKEUP_SRC_TIMEOUT (2000)
#define NCI_MAX_CMD_RSP_TIMEOUT (5000) //5s
/*command response timeout*/
#define NCI_CMD_RSP_TIMEOUT (2000) //2s
/*Time to wait for NFCC to be ready again after any change in the GPIO*/
#define NFC_GPIO_SET_WAIT_TIME_USEC (10000)
/*Time to wait after soft reset via any NCI/DL cmd*/
#define NFC_SOFT_RESET_WAIT_TIME_USEC (5000)
/*Time to wait before retrying i2c writes*/
/*Time to wait before retrying i2c/I3C writes*/
#define WRITE_RETRY_WAIT_TIME_USEC (1000)
/*Time to wait before retrying read for some specific usecases*/
#define READ_RETRY_WAIT_TIME_USEC (3500)
@@ -95,8 +103,6 @@
#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long)
#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, long)
#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, long)
#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04)
#define NFC_GET_NFC_STATE _IO(NFC_MAGIC, 0x05)
/* NFC HAL can call this ioctl to get the current IRQ state */
#define NFC_GET_IRQ_STATE _IO(NFC_MAGIC, 0x06)
@@ -158,34 +164,41 @@ enum gpio_values {
};
// NFC GPIO variables
typedef struct platform_gpio {
struct platform_gpio {
unsigned int irq;
unsigned int ven;
unsigned int dwl_req;
} platform_gpio_t;
};
// NFC Struct to get all the required configs from DTS*/
typedef struct platform_configs {
platform_gpio_t gpio;
} platform_configs_t;
// NFC Struct to get all the required configs from DTS
struct platform_configs {
struct platform_gpio gpio;
};
//cold reset Features specific Parameters
typedef struct cold_reset {
struct cold_reset {
bool rsp_pending; /*cmd rsp pending status */
bool in_progress; /*for cold reset when gurad timer in progress */
bool reset_protection; /*reset protection enabled/disabled */
uint8_t status; /*status from response buffer */
uint8_t rst_prot_src; /*reset protection source (SPI, NFC) */
struct mutex sync_mutex;
struct timer_list timer;
wait_queue_head_t read_wq;
} cold_reset_t;
};
enum chip_types {
CHIP_SN1XX = 0x01,
CHIP_SN220 = 0x02,
CHIP_UNKNOWN = 0xFF,
};
/* Device specific structure */
typedef struct nfc_dev {
struct nfc_dev {
wait_queue_head_t read_wq;
struct mutex read_mutex;
struct mutex ese_access_mutex;
struct mutex write_mutex;
uint8_t *read_kbuf;
uint8_t *write_kbuf;
struct mutex dev_ref_mutex;
unsigned int dev_ref_count;
struct class *nfc_class;
@@ -198,42 +211,34 @@ typedef struct nfc_dev {
uint8_t nfc_state;
/* NFC VEN pin state */
bool nfc_ven_enabled;
#if defined(RECOVERY_ENABLE)
/* current firmware major version */
uint8_t fw_major_version;
/* NFC recovery Required */
bool recovery_required;
#endif
union {
i2c_dev_t i2c_dev;
struct i2c_dev i2c_dev;
};
platform_configs_t configs;
cold_reset_t cold_reset;
struct platform_configs configs;
struct cold_reset cold_reset;
/*funtion pointers for the common i2c functionality */
int (*nfc_read) (struct nfc_dev *dev, char *buf, size_t count, int timeout);
int (*nfc_write) (struct nfc_dev *dev, const char *buf, const size_t count,
/*function pointers for the common i2c functionality */
int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, int timeout);
int (*nfc_write)(struct nfc_dev *dev, const char *buf, const size_t count,
int max_retry_cnt);
int (*nfc_enable_intr) (struct nfc_dev *dev);
int (*nfc_disable_intr) (struct nfc_dev *dev);
int (*nfc_flush_readq) (struct nfc_dev *dev);
} nfc_dev_t;
int (*nfc_enable_intr)(struct nfc_dev *dev);
int (*nfc_disable_intr)(struct nfc_dev *dev);
};
int nfc_dev_open(struct inode *inode, struct file *filp);
int nfc_dev_close(struct inode *inode, struct file *filp);
long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg);
int nfc_parse_dt(struct device *dev, platform_configs_t *nfc_configs,
int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
uint8_t interface);
int nfc_misc_register(nfc_dev_t *nfc_dev,
int nfc_misc_register(struct nfc_dev *nfc_dev,
const struct file_operations *nfc_fops, int count, char *devname,
char *classname);
void nfc_misc_unregister(nfc_dev_t *nfc_dev, int count);
void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count);
int configure_gpio(unsigned int gpio, int flag);
void gpio_set_ven(nfc_dev_t *nfc_dev, int value);
void gpio_free_all(nfc_dev_t *nfc_dev);
int validate_nfc_state_nci(nfc_dev_t *nfc_dev);
int nfcc_hw_check(nfc_dev_t *nfc_dev);
void set_nfcc_state_from_rsp(nfc_dev_t *dev, const char *buf,
const int count);
void enable_dwnld_mode(nfc_dev_t* nfc_dev, bool value);
void gpio_set_ven(struct nfc_dev *nfc_dev, int value);
void gpio_free_all(struct nfc_dev *nfc_dev);
int validate_nfc_state_nci(struct nfc_dev *nfc_dev);
int nfcc_hw_check(struct nfc_dev *nfc_dev);
#endif //_COMMON_H_

View File

@@ -30,17 +30,18 @@
static void cold_reset_gaurd_timer_callback(struct timer_list *t)
{
cold_reset_t *cold_reset = from_timer(cold_reset, t, timer);
struct cold_reset *cold_reset = from_timer(cold_reset, t, timer);
pr_debug("%s: Enter\n", __func__);
cold_reset->in_progress = false;
return;
}
static long start_cold_reset_guard_timer(cold_reset_t *cold_reset)
static long start_cold_reset_guard_timer(struct cold_reset *cold_reset)
{
long ret = -EINVAL;
if (timer_pending(&cold_reset->timer) == 1) {
pr_debug("ese_cold_reset_guard_timer: delete pending timer \n");
pr_debug("ese_cold_reset_guard_timer: delete pending timer\n");
/* delete timer if already pending */
del_timer(&cold_reset->timer);
}
@@ -51,34 +52,33 @@ static long start_cold_reset_guard_timer(cold_reset_t *cold_reset)
return ret;
}
static int send_cold_reset_protection_cmd(nfc_dev_t *nfc_dev, bool requestType)
static int send_cold_reset_protection_cmd(struct nfc_dev *nfc_dev, bool requestType)
{
int ret = 0;
int length = 0;
uint8_t *cmd = NULL;
uint8_t cld_rst_cmd[] = { NCI_PROP_MSG_CMD, CLD_RST_OID,
CLD_RST_PAYLOAD_SIZE
};
uint8_t rst_prot_cmd[] = { NCI_PROP_MSG_CMD, RST_PROT_OID,
RST_PROT_PAYLOAD_SIZE, 0x00
};
int cmd_length = 0;
uint8_t *cmd = nfc_dev->write_kbuf;
struct cold_reset *cold_reset = &nfc_dev->cold_reset;
cold_reset_t *cold_reset = &nfc_dev->cold_reset;
if (requestType) {
length = sizeof(rst_prot_cmd);
rst_prot_cmd[NCI_PAYLOAD_IDX] = (!cold_reset->reset_protection) ? 1 : 0;
cmd = rst_prot_cmd;
} else {
length = sizeof(cld_rst_cmd);
cmd = cld_rst_cmd;
mutex_lock(&nfc_dev->write_mutex);
*cmd++ = NCI_PROP_MSG_CMD;
if (requestType) { /*reset protection*/
*cmd++ = RST_PROT_OID;
*cmd++ = RST_PROT_PAYLOAD_SIZE;
*cmd++ = (!cold_reset->reset_protection) ? 1 : 0;
} else { /*cold reset*/
*cmd++ = CLD_RST_OID;
*cmd++ = CLD_RST_PAYLOAD_SIZE;
}
cmd_length = cmd - nfc_dev->write_kbuf;
ret = nfc_dev->nfc_write(nfc_dev, cmd, length, MAX_RETRY_COUNT);
if (ret != length) {
ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, cmd_length, MAX_RETRY_COUNT);
if (ret != cmd_length) {
ret = -EIO;
pr_err("%s : nfc_write returned %d\n", __func__, ret);
return -EIO;
goto exit;
}
cmd = nfc_dev->write_kbuf;
if (requestType) {
pr_debug("%s: NxpNciX: %d > %02X%02X%02X%02X\n", __func__, ret, cmd[0], cmd[1],
cmd[2], cmd[3]);
@@ -86,19 +86,21 @@ static int send_cold_reset_protection_cmd(nfc_dev_t *nfc_dev, bool requestType)
pr_debug("%s: NxpNciX: %d > %02X%02X%02X\n", __func__, ret, cmd[0], cmd[1],
cmd[2]);
}
exit:
mutex_unlock(&nfc_dev->write_mutex);
return ret;
}
void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf)
void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf)
{
cold_reset_t *cold_reset = &nfc_dev->cold_reset;
cold_reset->status = -EIO;
struct cold_reset *cold_reset = &nfc_dev->cold_reset;
if ((NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]) != NCI_PROP_MSG_RSP_LEN) {
pr_err("%s: - invalid response for cold_reset/protection \n", __func__);
} else {
cold_reset->status = -EIO;
if ((NCI_HDR_LEN + buf[NCI_PAYLOAD_LEN_IDX]) != NCI_PROP_MSG_RSP_LEN)
pr_err("%s: - invalid response for cold_reset/protection\n", __func__);
else
cold_reset->status = buf[NCI_PAYLOAD_IDX];
}
pr_debug("%s NxpNciR : len = 4 > %02X%02X%02X%02X\n", __func__, buf[0], buf[1],
buf[2], buf[3]);
@@ -106,9 +108,11 @@ void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf)
wake_up_interruptible(&cold_reset->read_wq);
}
static int validate_cold_reset_protection_request(cold_reset_t *cold_reset,
static int validate_cold_reset_protection_request(struct cold_reset *cold_reset,
unsigned long arg)
{
int ret = 0;
if (!cold_reset->reset_protection) {
if (IS_RST_PROT_EN_REQ(arg) && IS_SRC_VALID_PROT(arg)) {
pr_debug("%s:req - reset protection enable\n", __func__);
@@ -116,10 +120,10 @@ static int validate_cold_reset_protection_request(cold_reset_t *cold_reset,
pr_debug("%s:req - cold reset\n", __func__);
} else if (IS_RST_PROT_DIS_REQ(arg) && IS_SRC_VALID_PROT(arg)) {
pr_debug("%s:req - reset protection already disable\n", __func__);
return -EINVAL;
ret = -EINVAL;
} else {
pr_err("%s:Operation not permitted \n", __func__);
return -EPERM;
pr_err("%s:Operation not permitted\n", __func__);
ret = -EPERM;
}
} else {
if (IS_RST_PROT_DIS_REQ(arg)
@@ -130,21 +134,21 @@ static int validate_cold_reset_protection_request(cold_reset_t *cold_reset,
pr_debug("%s:req - cold reset from same source\n", __func__);
} else if (IS_RST_PROT_EN_REQ(arg)
&& IS_SRC(arg, cold_reset->rst_prot_src)) {
pr_debug("%s:request - enable reset protection from same source\n", __func__);
pr_debug("%s:req - enable reset protection from same src\n", __func__);
} else {
pr_err("%s: Operation not permitted \n", __func__);
return -EPERM;
pr_err("%s: Operation not permitted\n", __func__);
ret = -EPERM;
}
}
return 0;
return ret;
}
static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg)
static int perform_cold_reset_protection(struct nfc_dev *nfc_dev, unsigned long arg)
{
int ret = 0;
struct file filp;
uint8_t cld_rst_rsp[MAX_BUFFER_SIZE];
cold_reset_t *cold_reset = &nfc_dev->cold_reset;
char *rsp = nfc_dev->read_kbuf;
struct cold_reset *cold_reset = &nfc_dev->cold_reset;
bool nfc_dev_opened = false;
/*check if NFCC not in the FW download or hard reset state */
@@ -157,9 +161,7 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg)
/* check if NFC is enabled */
mutex_lock(&nfc_dev->dev_ref_mutex);
nfc_dev_opened = (nfc_dev->dev_ref_count > 0) ? true : false;
mutex_unlock(&nfc_dev->dev_ref_mutex);
mutex_lock(&cold_reset->sync_mutex);
/*check if NFCC not in the FW download or hard reset state */
ret = validate_cold_reset_protection_request(cold_reset, arg);
if (ret < 0) {
@@ -191,7 +193,7 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg)
/*start the cold reset guard timer */
if (IS_CLD_RST_REQ(arg)) {
/*Guard timer not needed when OSU over NFC*/
if(!(cold_reset->reset_protection && IS_SRC_NFC(arg))) {
if (!(cold_reset->reset_protection && IS_SRC_NFC(arg))) {
ret = start_cold_reset_guard_timer(cold_reset);
if (ret) {
pr_err("%s: Error in mod_timer\n", __func__);
@@ -213,12 +215,14 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg)
} else {
/* Read data as NFC thread is not active */
filp.private_data = nfc_dev;
filp.f_flags &= ~O_NONBLOCK;
ret = nfc_dev->nfc_read(nfc_dev, cld_rst_rsp, 3, NCI_CMD_RSP_TIMEOUT);
if (!ret)
break;
usleep_range(READ_RETRY_WAIT_TIME_USEC,
READ_RETRY_WAIT_TIME_USEC + 500);
if (nfc_dev->interface == PLATFORM_IF_I2C) {
filp.f_flags &= ~O_NONBLOCK;
ret = nfc_dev->nfc_read(nfc_dev, rsp, 3, NCI_CMD_RSP_TIMEOUT);
if (!ret)
break;
usleep_range(READ_RETRY_WAIT_TIME_USEC,
READ_RETRY_WAIT_TIME_USEC + 500);
}
}
} while (ret == -ERESTARTSYS || ret == -EFAULT);
@@ -237,7 +241,7 @@ static int perform_cold_reset_protection(nfc_dev_t *nfc_dev, unsigned long arg)
}
}
err:
mutex_unlock(&cold_reset->sync_mutex);
mutex_unlock(&nfc_dev->dev_ref_mutex);
return ret;
}
@@ -247,10 +251,11 @@ err:
* VEN HIGH - eSE and NFCC both are powered on
* VEN LOW - eSE and NFCC both are power down
*/
int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg)
int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
{
int ret = 0;
platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio;
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
if (arg == ESE_POWER_ON) {
/**
* Let's store the NFC VEN pin state
@@ -284,64 +289,62 @@ int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg)
}
return ret;
}
EXPORT_SYMBOL(nfc_ese_pwr);
#define ESE_LEGACY_INTERFACE
#ifdef ESE_LEGACY_INTERFACE
static nfc_dev_t *nfc_dev_legacy = NULL;
static struct nfc_dev *nfc_dev_legacy;
/******************************************************************************
* perform_ese_cold_reset() - It shall be called by others driver(not nfc/ese)
* to perform cold reset only
* @arg: request of cold reset from other drivers should be ESE_CLD_RST_OTHER
*
* Returns:- 0 in case of sucess and negative values in case of failure
* Returns:- 0 in case of success and negative values in case of failure
*****************************************************************************/
int perform_ese_cold_reset(unsigned long arg)
{
int ret = 0;
if (nfc_dev_legacy) {
if (IS_CLD_RST_REQ(arg) && IS_SRC_OTHER(arg)) {
ret = nfc_ese_pwr(nfc_dev_legacy, arg);
} else {
pr_err("%s : Operation not permitted \n", __func__);
pr_err("%s : Operation not permitted\n", __func__);
return -EPERM;
}
}
pr_debug("%s:%d exit, status:%lu", __func__, arg, ret);
return ret;
}
EXPORT_SYMBOL(perform_ese_cold_reset);
#endif //ESE_LEGACY_INTERFACE
void common_ese_on_hard_reset(nfc_dev_t *nfc_dev)
void ese_cold_reset_release(struct nfc_dev *nfc_dev)
{
cold_reset_t *cold_reset = &nfc_dev->cold_reset;
struct cold_reset *cold_reset = &nfc_dev->cold_reset;
cold_reset->rsp_pending = false;
cold_reset->in_progress = false;
if (timer_pending(&cold_reset->timer) == 1) {
if (timer_pending(&cold_reset->timer) == 1)
del_timer(&cold_reset->timer);
}
}
void common_ese_init(nfc_dev_t *nfc_dev)
void common_ese_init(struct nfc_dev *nfc_dev)
{
cold_reset_t *cold_reset = &nfc_dev->cold_reset;
struct cold_reset *cold_reset = &nfc_dev->cold_reset;
cold_reset->reset_protection = false;
cold_reset->rst_prot_src = SRC_NONE;
init_waitqueue_head(&cold_reset->read_wq);
mutex_init(&cold_reset->sync_mutex);
common_ese_on_hard_reset(nfc_dev);
ese_cold_reset_release(nfc_dev);
#ifdef ESE_LEGACY_INTERFACE
nfc_dev_legacy = nfc_dev;
#endif //ESE_LEGACY_INTERFACE
}
void common_ese_exit(nfc_dev_t *nfc_dev)
void common_ese_exit(struct nfc_dev *nfc_dev)
{
mutex_destroy(&nfc_dev->cold_reset.sync_mutex);
#ifdef ESE_LEGACY_INTERFACE
nfc_dev_legacy = NULL;
#endif //ESE_LEGACY_INTERFACE

View File

@@ -23,32 +23,32 @@
#include "common.h"
/*nci prop msg 1st byte*/
#define NCI_PROP_MSG_GID 0x0F
#define NCI_PROP_MSG_CMD (NCI_MSG_CMD | NCI_PROP_MSG_GID)
#define NCI_PROP_MSG_RSP (NCI_MSG_RSP | NCI_PROP_MSG_GID)
#define NCI_PROP_MSG_GID 0x0F
#define NCI_PROP_MSG_CMD (NCI_MSG_CMD | NCI_PROP_MSG_GID)
#define NCI_PROP_MSG_RSP (NCI_MSG_RSP | NCI_PROP_MSG_GID)
/*nci prop msg 2nd byte*/
#define CLD_RST_OID 0x1E
#define RST_PROT_OID 0x1F
#define CLD_RST_OID 0x1E
#define RST_PROT_OID 0x1F
/*nci prop msg 3rd byte*/
#define CLD_RST_PAYLOAD_SIZE 0x00
#define RST_PROT_PAYLOAD_SIZE 0x01
#define CLD_RST_PAYLOAD_SIZE 0x00
#define RST_PROT_PAYLOAD_SIZE 0x01
/*nci prop msg response length*/
#define NCI_PROP_MSG_RSP_LEN 0x04
#define NCI_PROP_MSG_RSP_LEN 0x04
/*cold reset guard time to allow back to back cold reset after some time*/
#define ESE_CLD_RST_GUARD_TIME (3000) //3s
#define ESE_CLD_RST_GUARD_TIME (3000) //3s
/*guard time to reboot after reset*/
#define ESE_CLD_RST_REBOOT_GUARD_TIME (50) //50ms
#define ESE_CLD_RST_REBOOT_GUARD_TIME (50) //50ms
/*sources of reset protection and cold reset*/
typedef enum reset_source {
enum reset_source {
SRC_SPI = 0,
SRC_NFC = 0x10,
SRC_OTHER = 0x20,
SRC_NONE = 0x80,
} reset_source_t;
};
enum ese_ioctl_request {
ESE_POWER_ON = 0, /* eSE POWER ON */
@@ -75,7 +75,7 @@ enum ese_ioctl_request {
#define IS_SRC_NFC(arg) IS_SRC(arg, SRC_NFC)
#define IS_SRC_OTHER(arg) IS_SRC(arg, SRC_OTHER)
#define IS_SRC_VALID(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg) || \
IS_SRC_OTHER(arg))
IS_SRC_OTHER(arg))
#define IS_SRC_VALID_PROT(arg) (IS_SRC_SPI(arg) || IS_SRC_NFC(arg))
#define IS_RST(arg, type) ((arg & 0xF) == type)
@@ -84,14 +84,14 @@ enum ese_ioctl_request {
#define IS_RST_PROT_DIS_REQ(arg) IS_RST(arg, ESE_RST_PROT_DIS)
#define IS_RST_PROT_REQ(arg) (IS_RST_PROT_EN_REQ(arg) || IS_RST_PROT_DIS_REQ(arg))
/* This macro evaluates to 1 if prop cmd response is received */
#define IS_PROP_CMD_RSP(buf) \
((NCI_PROP_MSG_RSP == buf[0]) && ((CLD_RST_OID == buf[1]) || \
(RST_PROT_OID == buf[1])))
#define IS_PROP_CMD_RSP(buf) \
((buf[0] == NCI_PROP_MSG_RSP) && ((buf[1] == CLD_RST_OID) || \
(buf[1] == RST_PROT_OID)))
void wakeup_on_prop_rsp(nfc_dev_t *nfc_dev, uint8_t *buf);
int nfc_ese_pwr(nfc_dev_t *nfc_dev, unsigned long arg);
void common_ese_on_hard_reset(nfc_dev_t *nfc_dev);
void common_ese_init(nfc_dev_t *nfc_dev);
void common_ese_exit(nfc_dev_t *nfc_dev);
void wakeup_on_prop_rsp(struct nfc_dev *nfc_dev, uint8_t *buf);
int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg);
void ese_cold_reset_release(struct nfc_dev *nfc_dev);
void common_ese_init(struct nfc_dev *nfc_dev);
void common_ese_exit(struct nfc_dev *nfc_dev);
#endif /* _COMMON_ESE_H_ */

View File

@@ -1,4 +1,5 @@
/******************************************************************************
* Copyright (C) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2013-2021 NXP
* *
* This program is free software; you can redistribute it and/or modify
@@ -44,7 +45,6 @@
#include "common.h"
#include "common_ese.h"
static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, int timeout);
/**
* i2c_disable_irq()
*
@@ -91,8 +91,9 @@ int i2c_enable_irq(struct nfc_dev *dev)
static irqreturn_t i2c_irq_handler(int irq, void *dev_id)
{
nfc_dev_t *nfc_dev = dev_id;
i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev;
struct nfc_dev *nfc_dev = dev_id;
struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev;
if (device_may_wakeup(&i2c_dev->client->dev))
pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT);
@@ -102,52 +103,22 @@ static irqreturn_t i2c_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout){
int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout)
{
int ret;
struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev;
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
pr_debug("%s : reading %zu bytes.\n", __func__, count);
if(timeout > NCI_MAX_CMD_RSP_TIMEOUT)
timeout = NCI_MAX_CMD_RSP_TIMEOUT;
return i2c_read_internal(dev, buf, count, timeout);
}
int i2c_write(struct nfc_dev *dev, const char *buf, size_t count,
int max_retry_cnt)
{
int ret = -EINVAL;
int retry_cnt;
pr_debug("%s : writing %zu bytes.\n", __func__, count);
for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) {
ret = i2c_master_send(dev->i2c_dev.client, buf, count);
if (ret <= 0) {
pr_warn("%s: write failed, Maybe in Standby Mode - Retry(%d)\n", __func__,
retry_cnt);
usleep_range(WRITE_RETRY_WAIT_TIME_USEC,
WRITE_RETRY_WAIT_TIME_USEC + 100);
} else if (ret == count)
break;
}
return ret;
}
static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, int timeout)
{
int ret;
char tmp[MAX_BUFFER_SIZE];
nfc_dev_t *nfc_dev = dev;
i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev;
platform_gpio_t *nfc_gpio = &nfc_dev->configs.gpio;
if (timeout > NCI_CMD_RSP_TIMEOUT)
timeout = NCI_CMD_RSP_TIMEOUT;
if (count > MAX_BUFFER_SIZE)
count = MAX_BUFFER_SIZE;
pr_debug("%s : reading %zu bytes.\n", __func__, count);
mutex_lock(&nfc_dev->read_mutex);
if (!gpio_get_value(nfc_gpio->irq)) {
while (1) {
ret = 0;
if (!i2c_dev->irq_enabled) {
@@ -155,9 +126,9 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i
enable_irq(i2c_dev->client->irq);
}
if (!gpio_get_value(nfc_gpio->irq)) {
if(timeout) {
if (timeout) {
ret = wait_event_interruptible_timeout(nfc_dev->read_wq,
!i2c_dev-> irq_enabled, msecs_to_jiffies(timeout));
!i2c_dev->irq_enabled, msecs_to_jiffies(timeout));
if (ret <= 0) {
pr_err("%s timeout/error in read\n", __func__);
@@ -185,11 +156,11 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i
}
}
memset(tmp, 0x00, count);
memset(buf, 0x00, count);
/* Read data */
ret = i2c_master_recv(nfc_dev->i2c_dev.client, tmp, count);
ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf, count);
if (ret <= 0) {
pr_err("%s: i2c_read returned %d\n", __func__, ret);
pr_err("%s: returned %d\n", __func__, ret);
goto err;
}
/* check if it's response of cold reset command
@@ -197,16 +168,15 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i
* command was sent by driver
*/
if (nfc_dev->cold_reset.rsp_pending) {
if (IS_PROP_CMD_RSP(tmp)) {
if (IS_PROP_CMD_RSP(buf)) {
/* Read data */
ret = i2c_master_recv(nfc_dev->i2c_dev.client, &tmp[NCI_PAYLOAD_IDX],
tmp[NCI_PAYLOAD_LEN_IDX]);
ret = i2c_master_recv(nfc_dev->i2c_dev.client, &buf[NCI_PAYLOAD_IDX],
buf[NCI_PAYLOAD_LEN_IDX]);
if (ret <= 0) {
pr_err("%s: failure to read prop cold reset/protection rsp header\n", __func__);
pr_err("%s: error reading cold reset/prot rsp header\n", __func__);
goto err;
}
wakeup_on_prop_rsp(nfc_dev, tmp);
mutex_unlock(&nfc_dev->read_mutex);
wakeup_on_prop_rsp(nfc_dev, buf);
/*
* NFC process doesn't know about cold reset command
* being sent as it was initiated by eSE process
@@ -215,47 +185,76 @@ static ssize_t i2c_read_internal(struct nfc_dev *dev, char *buf, size_t count, i
return 0;
}
}
if (copy_to_user(buf, tmp, ret)) {
pr_warn("%s : failed to copy to user space\n", __func__);
ret = -EFAULT;
}
err:
mutex_unlock(&nfc_dev->read_mutex);
return ret;
}
ssize_t nfc_i2c_dev_read(struct file * filp, char __user *buf,
size_t count, loff_t * offset)
int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count,
int max_retry_cnt)
{
pr_debug("%s : reading %zu bytes.\n", __func__, count);
if (filp->f_flags & O_NONBLOCK) {
pr_err(":f_falg has O_NONBLOCK. EAGAIN\n");
return -EAGAIN;
}
return i2c_read_internal((nfc_dev_t *)filp->private_data, buf, count, 0);
}
ssize_t nfc_i2c_dev_write(struct file * filp, const char __user *buf,
size_t count, loff_t * offset)
{
int ret;
char tmp[MAX_DL_BUFFER_SIZE];
nfc_dev_t *nfc_dev = filp->private_data;
int ret = -EINVAL;
int retry_cnt;
if (count > MAX_DL_BUFFER_SIZE)
count = MAX_DL_BUFFER_SIZE;
if (copy_from_user(tmp, buf, count)) {
pr_debug("%s : writing %zu bytes.\n", __func__, count);
for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) {
ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count);
if (ret <= 0) {
pr_warn("%s: failed to write ret(%d), Maybe in Standby Mode - Retry(%d)\n", __func__,
ret, retry_cnt);
usleep_range(WRITE_RETRY_WAIT_TIME_USEC,
WRITE_RETRY_WAIT_TIME_USEC + 100);
} else if (ret != count) {
pr_err("%s: failed to write %d\n", __func__, ret);
ret = -EIO;
} else if (ret == count)
break;
}
return ret;
}
ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf,
size_t count, loff_t *offset)
{
int ret = 0;
struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data;
if (filp->f_flags & O_NONBLOCK) {
pr_err(":f_falg has O_NONBLOCK. EAGAIN\n");
return -EAGAIN;
}
mutex_lock(&nfc_dev->read_mutex);
ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0);
if (ret > 0) {
if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) {
pr_warn("%s : failed to copy to user space\n", __func__);
ret = -EFAULT;
}
}
mutex_unlock(&nfc_dev->read_mutex);
return ret;
}
ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *offset)
{
int ret = 0;
struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data;
if (count > MAX_DL_BUFFER_SIZE)
count = MAX_DL_BUFFER_SIZE;
mutex_lock(&nfc_dev->write_mutex);
if (copy_from_user(nfc_dev->write_kbuf, buf, count)) {
pr_err("%s : failed to copy from user space\n", __func__);
mutex_unlock(&nfc_dev->write_mutex);
return -EFAULT;
}
ret = i2c_write(nfc_dev, tmp, count, NO_RETRY);
if (ret != count) {
pr_err("%s: failed to write %d\n", __func__, ret);
ret = -EIO;
}
ret = i2c_write(nfc_dev, nfc_dev->write_kbuf, count, NO_RETRY);
mutex_unlock(&nfc_dev->write_mutex);
return ret;
}
@@ -272,12 +271,13 @@ static const struct file_operations nfc_i2c_dev_fops = {
int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret = 0;
nfc_dev_t *nfc_dev = NULL;
i2c_dev_t *i2c_dev = NULL;
platform_configs_t nfc_configs;
platform_gpio_t *nfc_gpio = &nfc_configs.gpio;
struct nfc_dev *nfc_dev = NULL;
struct i2c_dev *i2c_dev = NULL;
struct platform_configs nfc_configs;
struct platform_gpio *nfc_gpio = &nfc_configs.gpio;
pr_debug("%s: enter\n", __func__);
/*retrive details of gpios from dt */
/*retrieve details of gpios from dt */
ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C);
if (ret) {
pr_err("%s : failed to parse dt\n", __func__);
@@ -289,11 +289,21 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
ret = -ENODEV;
goto err;
}
nfc_dev = kzalloc(sizeof(nfc_dev_t), GFP_KERNEL);
nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL);
if (nfc_dev == NULL) {
ret = -ENOMEM;
goto err;
}
nfc_dev->read_kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_DMA | GFP_KERNEL);
if (!nfc_dev->read_kbuf) {
ret = -ENOMEM;
goto err;
}
nfc_dev->write_kbuf = kzalloc(MAX_DL_BUFFER_SIZE, GFP_DMA | GFP_KERNEL);
if (!nfc_dev->write_kbuf) {
ret = -ENOMEM;
goto err;
}
nfc_dev->interface = PLATFORM_IF_I2C;
nfc_dev->nfc_state = NFC_STATE_NCI;
nfc_dev->i2c_dev.client = client;
@@ -302,11 +312,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
nfc_dev->nfc_write = i2c_write;
nfc_dev->nfc_enable_intr = i2c_enable_irq;
nfc_dev->nfc_disable_intr = i2c_disable_irq;
#if defined(RECOVERY_ENABLE)
nfc_dev->recovery_required = false;
nfc_dev->fw_major_version = 0;
#endif
ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT);
if (ret) {
pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__, nfc_gpio->ven);
@@ -324,14 +330,14 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
nfc_gpio->dwl_req);
}
/*copy the retrived gpio details from DT */
/*copy the retrieved gpio details from DT */
memcpy(&nfc_dev->configs, &nfc_configs, sizeof(struct platform_configs));
/* init mutex and queues */
init_waitqueue_head(&nfc_dev->read_wq);
mutex_init(&nfc_dev->read_mutex);
mutex_init(&nfc_dev->write_mutex);
mutex_init(&nfc_dev->dev_ref_mutex);
mutex_init(&nfc_dev->ese_access_mutex);
spin_lock_init(&i2c_dev->irq_enabled_lock);
common_ese_init(nfc_dev);
ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT,
@@ -352,8 +358,9 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_disable_irq(nfc_dev);
ret = nfcc_hw_check(nfc_dev);
if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) {
if (ret != 0) {
pr_err("nfc hw check failed ret %d\n", ret);
goto err_nfc_misc_unregister;
}
device_init_wakeup(&client->dev, true);
@@ -368,21 +375,21 @@ err_nfc_misc_unregister:
err_mutex_destroy:
mutex_destroy(&nfc_dev->dev_ref_mutex);
mutex_destroy(&nfc_dev->read_mutex);
mutex_destroy(&nfc_dev->ese_access_mutex);
mutex_destroy(&nfc_dev->cold_reset.sync_mutex);
mutex_destroy(&nfc_dev->write_mutex);
err:
if (nfc_dev) {
gpio_free_all(nfc_dev);
kfree(nfc_dev);
}
pr_err("%s: probing not successful, check hardware\n", __func__);
return ret;
gpio_free_all(nfc_dev);
kfree(nfc_dev->read_kbuf);
kfree(nfc_dev->write_kbuf);
kfree(nfc_dev);
pr_err("%s: probing not successful, check hardware\n", __func__);
return ret;
}
int nfc_i2c_dev_remove(struct i2c_client *client)
{
int ret = 0;
nfc_dev_t *nfc_dev = NULL;
struct nfc_dev *nfc_dev = NULL;
pr_info("%s: remove device\n", __func__);
nfc_dev = i2c_get_clientdata(client);
if (!nfc_dev) {
@@ -398,9 +405,10 @@ int nfc_i2c_dev_remove(struct i2c_client *client)
free_irq(client->irq, nfc_dev);
nfc_misc_unregister(nfc_dev, DEV_COUNT);
mutex_destroy(&nfc_dev->read_mutex);
mutex_destroy(&nfc_dev->ese_access_mutex);
mutex_destroy(&nfc_dev->cold_reset.sync_mutex);
mutex_destroy(&nfc_dev->write_mutex);
gpio_free_all(nfc_dev);
kfree(nfc_dev->read_kbuf);
kfree(nfc_dev->write_kbuf);
kfree(nfc_dev);
return ret;
}
@@ -408,8 +416,8 @@ int nfc_i2c_dev_remove(struct i2c_client *client)
int nfc_i2c_dev_suspend(struct device *device)
{
struct i2c_client *client = to_i2c_client(device);
nfc_dev_t *nfc_dev = i2c_get_clientdata(client);
i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev;
struct nfc_dev *nfc_dev = i2c_get_clientdata(client);
struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev;
if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) {
if (!enable_irq_wake(client->irq))
@@ -421,8 +429,8 @@ int nfc_i2c_dev_suspend(struct device *device)
int nfc_i2c_dev_resume(struct device *device)
{
struct i2c_client *client = to_i2c_client(device);
nfc_dev_t *nfc_dev = i2c_get_clientdata(client);
i2c_dev_t *i2c_dev = &nfc_dev->i2c_dev;
struct nfc_dev *nfc_dev = i2c_get_clientdata(client);
struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev;
if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) {
if (!disable_irq_wake(client->irq))
@@ -462,6 +470,7 @@ MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table);
static int __init nfc_i2c_dev_init(void)
{
int ret = 0;
pr_info("Loading NXP NFC I2C driver\n");
ret = i2c_add_driver(&nfc_i2c_dev_driver);
if (ret != 0)

View File

@@ -1,4 +1,5 @@
/******************************************************************************
* Copyright (C) 2015, The Linux Foundation. All rights reserved.
* Copyright (C) 2019-2021 NXP
* *
* This program is free software; you can redistribute it and/or modify
@@ -25,14 +26,14 @@
#define NFC_I2C_DEV_ID "pn553"
//Interface specific parameters
typedef struct i2c_dev {
struct i2c_dev {
struct i2c_client *client;
/*IRQ parameters */
bool irq_enabled;
spinlock_t irq_enabled_lock;
/* NFC_IRQ wake-up state */
bool irq_wake_up;
} i2c_dev_t;
};
long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg);
int nfc_i2c_dev_probe(struct i2c_client *client,

File diff suppressed because it is too large Load Diff

View File

@@ -16,14 +16,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
******************************************************************************/
#if defined(RECOVERY_ENABLE)
#include "recovery_seq.h"
recovery_info_t g_recovery_info;
recovery_frame_t g_recovery_frame;
extern const uint32_t gphDnldNfc_DlSeqSz; /* Recovery user buffer size */
extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */
struct recovery_info g_recovery_info;
struct recovery_frame g_recovery_frame;
/** @brief Function to calculate crc value.
*
@@ -31,16 +27,18 @@ extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */
* dwLength: length of input buffer
* @return calculated uint16_t crc valueof input buffer.
*/
static uint16_t calcCrc16(uint8_t* pbuffer, uint32_t dwLength) {
static uint16_t calcCrc16(uint8_t *pbuffer, uint32_t dwLength)
{
uint32_t i = 0;
uint16_t crc_new = 0;
uint16_t crc = DL_INVALID_CRC_VALUE;
if(NULL == pbuffer) {
if (pbuffer == NULL) {
pr_err("%s, invalid params", __func__);
return crc;
}
for (i = 0; i < dwLength; i++) {
crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS );
crc_new = (uint8_t)(crc >> MSB_POS) | (crc << MSB_POS);
crc_new ^= pbuffer[i];
crc_new ^= (uint8_t)(crc_new & DL_CRC_MASK) >> 4;
crc_new ^= crc_new << 12;
@@ -52,29 +50,32 @@ static uint16_t calcCrc16(uint8_t* pbuffer, uint32_t dwLength) {
/** @brief Function to build command frame for recover.
*
* @return status code of recovery_status_t type.
* @return status code of recovery_status type.
*/
static recovery_status_t build_cmd_frame() {
static enum recovery_status build_cmd_frame(void)
{
uint16_t len = 0;
uint16_t wCrc = 0;
uint16_t writeOffset = 0;
pr_debug(" %s Entry", __func__);
if(gphDnldNfc_DlSeqSz == 0) {
if (gphDnldNfc_DlSeqSz == 0) {
pr_err(" %s invalid params", __func__);
return STATUS_FAILED;
}
memset(g_recovery_frame.p_buffer, 0x00, MAX_FRAME_SIZE);
g_recovery_frame.len = 0;
if(g_recovery_info.bFrameSegmented == false) {
if (g_recovery_info.bFrameSegmented == false) {
len = gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset];
len <<= MSB_POS;
len |= gphDnldNfc_DlSequence[g_recovery_info.currentReadOffset + 1];
} else {
/* last frame was segmented frame
* read length reamaining length */
* read length reamaining length
*/
len = g_recovery_info.wRemChunkBytes;
}
if(len > MAX_DATA_SIZE) {
if (len > MAX_DATA_SIZE) {
/* set remaining chunk */
g_recovery_info.wRemChunkBytes = (len - MAX_DATA_SIZE);
len = MAX_DATA_SIZE;
@@ -85,7 +86,7 @@ static recovery_status_t build_cmd_frame() {
/* clear chunk bit for length variable */
len = DL_CLR_HDR_FRAGBIT(len);
/* first chunk of segmented frame*/
if(!g_recovery_info.bFrameSegmented) {
if (!g_recovery_info.bFrameSegmented) {
/* ignore header from user buffer */
g_recovery_info.currentReadOffset += FW_HDR_LEN;
g_recovery_info.remBytes -= FW_HDR_LEN;
@@ -94,22 +95,23 @@ static recovery_status_t build_cmd_frame() {
g_recovery_info.bFrameSegmented = true;
} else {
/* last chunk of segmented frame */
if(g_recovery_info.bFrameSegmented) {
if (g_recovery_info.bFrameSegmented) {
/* write header with user chunk length */
g_recovery_frame.p_buffer[writeOffset++] = (len >> MSB_POS) & SHIFT_MASK;
g_recovery_frame.p_buffer[writeOffset++] = len & SHIFT_MASK;
g_recovery_frame.len += FW_HDR_LEN;
} else {
/* normal Frame with in supported size increase
* len to read header from user data */
* len to read header from user data
*/
len += FW_HDR_LEN;
}
g_recovery_info.wRemChunkBytes = 0;
g_recovery_info.bFrameSegmented = false;
}
if(((writeOffset + len) > MAX_FRAME_SIZE) ||
if (((writeOffset + len) > MAX_FRAME_SIZE) ||
((g_recovery_info.currentReadOffset + len) > gphDnldNfc_DlSeqSz)) {
pr_err("%s frame offsets out of bound",__func__);
pr_err("%s frame offsets out of bound", __func__);
return STATUS_FAILED;
}
memcpy(&g_recovery_frame.p_buffer[writeOffset],
@@ -126,20 +128,21 @@ static recovery_status_t build_cmd_frame() {
return STATUS_SUCCESS;
}
/** @brief Function to tramsmit recovery frame.
/** @brief Function to transmit recovery frame.
* @param nfc_dev nfc driver object.
* @return status code of recovery_status_t type.
* @return status code of recovery_status type.
*/
static recovery_status_t transmit(nfc_dev_t* nfc_dev) {
char rsp_buf[MAX_BUFFER_SIZE];
static enum recovery_status transmit(struct nfc_dev *nfc_dev)
{
int ret = 0;
int frame_resp_len = 0;
uint16_t respCRC = 0;
uint16_t respCRCOffset = 0;
uint8_t *rsp_buf = nfc_dev->read_kbuf;
pr_debug("%s Entry", __func__);
if(NULL == nfc_dev || g_recovery_frame.len <= 0) {
pr_err("%s invalid Params ", __func__);
if (nfc_dev == NULL || g_recovery_frame.len <= 0) {
pr_err("%s invalid Params", __func__);
return STATUS_FAILED;
}
ret = nfc_dev->nfc_write(nfc_dev, g_recovery_frame.p_buffer,
@@ -148,17 +151,17 @@ static recovery_status_t transmit(nfc_dev_t* nfc_dev) {
pr_err(" %s: Write recovery frame error %d\n", __func__, ret);
return STATUS_FAILED;
}
pr_debug(" %s Reading response \n", __func__);
pr_debug(" %s Reading response\n", __func__);
memset(rsp_buf, 0x00, MAX_BUFFER_SIZE);
ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, FW_HDR_LEN, NCI_CMD_RSP_TIMEOUT);
if (ret < FW_HDR_LEN) {
pr_err(" %s - Read recovery frame response error ret %d\n", __func__, ret);
return STATUS_FAILED;
}
if( rsp_buf[0] != FW_MSG_CMD_RSP ||
if (rsp_buf[0] != FW_MSG_CMD_RSP ||
rsp_buf[DL_FRAME_RESP_LEN_OFFSET] != DL_FRAME_RESP_LEN) {
pr_err("%s, invalid response", __func__);
return STATUS_FAILED;
pr_err("%s, invalid response", __func__);
return STATUS_FAILED;
}
frame_resp_len = rsp_buf[DL_FRAME_RESP_LEN_OFFSET] + FW_CRC_LEN;
ret = nfc_dev->nfc_read(nfc_dev, rsp_buf + FW_HDR_LEN, frame_resp_len, NCI_CMD_RSP_TIMEOUT);
@@ -167,22 +170,22 @@ static recovery_status_t transmit(nfc_dev_t* nfc_dev) {
return STATUS_FAILED;
}
pr_debug(" %s: recovery frame Response 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
__func__, rsp_buf[0], rsp_buf[1],rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]);
__func__, rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5]);
respCRCOffset = FW_HDR_LEN + rsp_buf[DL_FRAME_RESP_LEN_OFFSET];
respCRC = rsp_buf[respCRCOffset++];
respCRC <<= MSB_POS;
respCRC |= rsp_buf[respCRCOffset];
if(respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) {
if (respCRC != calcCrc16(rsp_buf, DL_FRAME_RESP_LEN + FW_HDR_LEN)) {
pr_err("%s, invalid response crc", __func__);
return STATUS_FAILED;
}
if(g_recovery_info.bFrameSegmented &&
if (g_recovery_info.bFrameSegmented &&
(rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT1
&& rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_SEGMENTED_FRAME_RESP_STAT2)) {
pr_err("%s, invalid stat flag in chunk response", __func__);
return STATUS_FAILED;
}
if(!g_recovery_info.bFrameSegmented &&
if (!g_recovery_info.bFrameSegmented &&
rsp_buf[DL_FRAME_RESP_STAT_OFFSET] != DL_NON_SEGMENTED_FRAME_RESP_STAT) {
pr_err("%s, invalid stat flag in response", __func__);
return STATUS_FAILED;
@@ -190,46 +193,14 @@ static recovery_status_t transmit(nfc_dev_t* nfc_dev) {
return STATUS_SUCCESS;
}
/** @brief Function to detect the fw state and print.
* @param nfc_dev nfc driver object.
* @return no return.
*/
static void detect_fw_state(nfc_dev_t* nfc_dev) {
const char get_session_state_cmd[] = { 0x00, 0x04, 0xF2, 0x00, 0x00, 0x00, 0xF5, 0x33 };
char rsp_buf[MAX_BUFFER_SIZE];
int ret = 0;
pr_debug("%s:Sending GET_SESSION_STATE cmd \n", __func__);
ret = nfc_dev->nfc_write(nfc_dev, get_session_state_cmd,
sizeof(get_session_state_cmd), MAX_RETRY_COUNT);
if (ret <= 0) {
pr_err("%s: - nfc get session state cmd err ret %d\n", __func__, ret);
return;
}
memset(rsp_buf, 0x00, DL_GET_SESSION_STATE_RSP_LEN);
pr_debug("%s: Reading response of GET_SESSION_STATE cmd\n", __func__);
ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, DL_GET_SESSION_STATE_RSP_LEN, NCI_CMD_RSP_TIMEOUT);
if (ret <= 0) {
pr_err("%s: - nfc get session state rsp err %d\n", __func__, ret);
return;
}
pr_debug("Response bytes are %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x",
rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3], rsp_buf[4], rsp_buf[5],
rsp_buf[6], rsp_buf[7]);
/*verify fw in non-teared state */
if (rsp_buf[GET_SESSION_STS_OFF] != NFCC_SESSION_STS_CLOSED) {
pr_err("%s NFCC is in teared state %d\n", __func__, __LINE__);
} else {
pr_info("%s NFCC is in recoverd state %d\n", __func__, __LINE__);
}
}
/** @brief Function to check input version with recovery fw version.
* @param fw_major_version: input major_version to check.
* @return true if input major_version matches with recovery fw major version
* otherwise returns false.
*/
static bool check_major_version(uint8_t fw_major_version) {
if(gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) {
static bool check_major_version(uint8_t fw_major_version)
{
if (gphDnldNfc_DlSeqSz < RECOVERY_FW_MJ_VER_OFFSET) {
/* Recovery data corrupted */
pr_err("%s Not able to extract major version from recovery fw\n", __func__);
return false;
@@ -239,43 +210,40 @@ static bool check_major_version(uint8_t fw_major_version) {
/** @brief Function to recover the nfcc.
* @param nfc_dev nfc driver object.
* @return status code of type recovery_status_t.
* @return status code of type recovery_status.
*/
recovery_status_t do_recovery(nfc_dev_t *nfc_dev) {
recovery_status_t status = STATUS_SUCCESS;
enum recovery_status do_recovery(struct nfc_dev *nfc_dev)
{
enum recovery_status status = STATUS_SUCCESS;
g_recovery_info.remBytes = gphDnldNfc_DlSeqSz;
g_recovery_info.currentReadOffset = 0;
g_recovery_info.bFrameSegmented = false;
g_recovery_info.wRemChunkBytes = 0;
g_recovery_frame.p_buffer = nfc_dev->write_kbuf;
pr_debug("%s Entry", __func__);
if(NULL == nfc_dev) {
if (nfc_dev == NULL) {
pr_err("%s invalid params ", __func__);
return STATUS_FAILED;
}
if(!nfc_dev->recovery_required
|| !(check_major_version(nfc_dev->fw_major_version))) {
pr_err("%s recovery not required or unsupported version", __func__);
if (!(check_major_version(nfc_dev->fw_major_version))) {
pr_err("%s unsupported version", __func__);
status = STATUS_FAILED;
goto EXIT_RECOVERY;
}
while(g_recovery_info.remBytes > 0) {
while (g_recovery_info.remBytes > 0) {
status = build_cmd_frame();
if(status != STATUS_SUCCESS) {
if (status != STATUS_SUCCESS) {
pr_err(" %s Unable to create recovery frame");
break;
}
status = transmit(nfc_dev);
if(status != STATUS_SUCCESS) {
if (status != STATUS_SUCCESS) {
pr_err(" %s Unable to send recovery frame");
break;
}
}
EXIT_RECOVERY:
detect_fw_state(nfc_dev);
/*set NCI mode for i2c products with dwl pin */
enable_dwnld_mode(nfc_dev, false);
pr_info("%s Recovery done status %d", __func__, status);
return status;
}
#endif

View File

@@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
******************************************************************************/
#if defined(RECOVERY_ENABLE)
#if IS_ENABLED(CONFIG_NXP_NFC_RECOVERY)
#ifndef __RECOVERY_SEQ_H_
#define __RECOVERY_SEQ_H_
@@ -26,18 +26,14 @@
#define MAX_FRAME_SIZE 0x22A /* support for 256(0x100) & 554(0x22A) frame size*/
#define MAX_DATA_SIZE \
(MAX_FRAME_SIZE - FW_CRC_LEN - FW_HDR_LEN)
(MAX_FRAME_SIZE - FW_CRC_LEN - FW_HDR_LEN)
#define FW_ROM_CODE_VER_OFFSET 4
#define FW_MAJOR_VER_OFFSET 7
#define RECOVERY_FW_SUPPORTED_ROM_VER 0x01
#define RECOVERY_FW_SUPPORTED_MAJOR_VER 0x10
#define RECOVERY_FW_MJ_VER_OFFSET 5
#define DL_SET_HDR_FRAGBIT(n) \
((n) | (1 << 10)) /* Header chunk bit set macro */
((n) | (1 << 10)) /* Header chunk bit set macro */
#define DL_CLR_HDR_FRAGBIT(n) \
((n) & ~(1U << 10)) /* Header chunk bit clear macro */
((n) & ~(1U << 10)) /* Header chunk bit clear macro */
#define DL_FRAME_RESP_LEN 0x04
#define DL_FRAME_RESP_LEN_OFFSET 1
@@ -52,29 +48,32 @@
#define MSB_POS 8
/* Data buffer for frame to write */
typedef struct recovery_frame {
struct recovery_frame {
uint32_t len;
uint8_t p_buffer[MAX_FRAME_SIZE];
} recovery_frame_t;
uint8_t *p_buffer;
};
/* Contains Info about user buffer and last data frame */
typedef struct recovery_info {
struct recovery_info {
uint32_t currentReadOffset; /* current offset within the user buffer to read/write */
uint32_t remBytes; /* Remaining bytes to write */
uint16_t wRemChunkBytes; /* Remaining bytes within the chunked frame */
bool bFrameSegmented; /* Indicates the current frame is segmented */
} recovery_info_t;
};
/* indicates the error codes for nfc recovery module */
typedef enum recovery_status {
enum recovery_status {
STATUS_SUCCESS = 0x00,
STATUS_FAILED = 0x01,
} recovery_status_t;
};
extern const uint32_t gphDnldNfc_DlSeqSz; /* Recovery user buffer size */
extern const uint8_t gphDnldNfc_DlSequence[]; /* Recovery user buffer */
/** @brief Function to recover the nfcc.
* @param nfc_dev nfc driver object.
* @return status code of type recovery_status_t.
*/
recovery_status_t do_recovery(nfc_dev_t *nfc_dev);
enum recovery_status do_recovery(struct nfc_dev *nfc_dev);
#endif// end __RECOVERY_SEQ_H_
#endif