NFC: Update NFC driver as per NFC MW 12.02.01
Add support for SN220 NFC chip. Update the NFCC initialization flow. Add wrapper APIs to validate and set GPIOs. Add timeout for NFC read. Change-Id: I7bb2cd1a2fb81cdb405a9aed64564481e06e87e7 Signed-off-by: Karthik Poosa <kpoosa2@codeaurora.org>
This commit is contained in:
parent
c4042850f3
commit
981559d3d9
@ -18,12 +18,12 @@ static int send_ese_cmd(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (gpio_get_value(nfc_dev->gpio.dwl_req)) {
|
||||
if (nfc_dev->nfc_state == NFC_STATE_FW_DWL) {
|
||||
dev_err(nfc_dev->nfc_device,
|
||||
"cannot send ese cmd as FW download is in-progress\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!gpio_get_value(nfc_dev->gpio.ven)) {
|
||||
if (!gpio_get_value(nfc_dev->configs.gpio.ven)) {
|
||||
dev_err(nfc_dev->nfc_device,
|
||||
"cannot send ese cmd as NFCC powered off\n");
|
||||
return -ENODEV;
|
||||
@ -63,7 +63,8 @@ int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header)
|
||||
*/
|
||||
if ((!cold_rst->is_nfc_enabled) &&
|
||||
(nfc_dev->interface == PLATFORM_IF_I2C)) {
|
||||
ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, NCI_HDR_LEN);
|
||||
ret = nfc_dev->nfc_read(nfc_dev, rsp_buf, NCI_HDR_LEN,
|
||||
NCI_CMD_RSP_TIMEOUT);
|
||||
if (ret <= 0) {
|
||||
dev_err(nfc_dev->nfc_device,
|
||||
"%s: failure to read cold reset rsp header\n",
|
||||
@ -104,7 +105,8 @@ int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header)
|
||||
if (nfc_dev->interface == PLATFORM_IF_I2C)
|
||||
ret = nfc_dev->nfc_read(nfc_dev,
|
||||
&rsp_buf[NCI_PAYLOAD_IDX],
|
||||
rsp_buf[NCI_PAYLOAD_LEN_IDX]);
|
||||
rsp_buf[NCI_PAYLOAD_LEN_IDX],
|
||||
NCI_CMD_RSP_TIMEOUT);
|
||||
|
||||
if (ret <= 0) {
|
||||
dev_err(nfc_dev->nfc_device,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __ESE_COLD_RESET_H
|
||||
@ -32,6 +32,7 @@ enum ese_ioctl_arg_type {
|
||||
enum ese_cold_reset_origin {
|
||||
ESE_COLD_RESET_ORIGIN_ESE = 0,
|
||||
ESE_COLD_RESET_ORIGIN_NFC,
|
||||
ESE_COLD_RESET_ORIGIN_OTHER = 0x20,
|
||||
ESE_COLD_RESET_ORIGIN_NONE = 0xFF,
|
||||
};
|
||||
|
||||
|
@ -1,24 +1,48 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
* Copyright (c) 2019-2021 NXP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include "nfc_common.h"
|
||||
|
||||
int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio,
|
||||
struct platform_ldo *ldo, uint8_t interface)
|
||||
int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
|
||||
uint8_t interface)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct platform_gpio *nfc_gpio = &nfc_configs->gpio;
|
||||
struct platform_ldo *ldo = &nfc_configs->ldo;
|
||||
|
||||
if (!np) {
|
||||
pr_err("nfc of_node NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nfc_gpio->irq = -EINVAL;
|
||||
nfc_gpio->dwl_req = -EINVAL;
|
||||
nfc_gpio->ven = -EINVAL;
|
||||
nfc_gpio->clkreq = -EINVAL;
|
||||
|
||||
/* required for i2c based chips only */
|
||||
if (interface == PLATFORM_IF_I2C) {
|
||||
nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0);
|
||||
if ((!gpio_is_valid(nfc_gpio->irq))) {
|
||||
@ -27,7 +51,6 @@ int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio,
|
||||
}
|
||||
pr_info("%s: irq %d\n", __func__, nfc_gpio->irq);
|
||||
}
|
||||
|
||||
nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0);
|
||||
if ((!gpio_is_valid(nfc_gpio->ven))) {
|
||||
pr_err("nfc ven gpio invalid %d\n", nfc_gpio->ven);
|
||||
@ -35,10 +58,10 @@ int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio,
|
||||
}
|
||||
|
||||
nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0);
|
||||
if ((!gpio_is_valid(nfc_gpio->dwl_req))) {
|
||||
pr_err("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* not returning failure for dwl gpio as it is optional for sn220 */
|
||||
if ((!gpio_is_valid(nfc_gpio->dwl_req)))
|
||||
pr_warn("nfc dwl_req gpio invalid %d\n", nfc_gpio->dwl_req);
|
||||
|
||||
nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0);
|
||||
if (!gpio_is_valid(nfc_gpio->clkreq)) {
|
||||
@ -84,15 +107,15 @@ int nfc_ldo_vote(struct nfc_dev *nfc_dev)
|
||||
int ret;
|
||||
|
||||
ret = regulator_set_voltage(nfc_dev->reg,
|
||||
nfc_dev->ldo.vdd_levels[0],
|
||||
nfc_dev->ldo.vdd_levels[1]);
|
||||
nfc_dev->configs.ldo.vdd_levels[0],
|
||||
nfc_dev->configs.ldo.vdd_levels[1]);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: set voltage failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* pass expected current from NFC in uA */
|
||||
ret = regulator_set_load(nfc_dev->reg, nfc_dev->ldo.max_current);
|
||||
ret = regulator_set_load(nfc_dev->reg, nfc_dev->configs.ldo.max_current);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: set load failed\n", __func__);
|
||||
return ret;
|
||||
@ -182,12 +205,39 @@ int nfc_ldo_unvote(struct nfc_dev *nfc_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void set_valid_gpio(int gpio, int value)
|
||||
{
|
||||
if (gpio_is_valid(gpio)) {
|
||||
pr_debug("%s gpio %d value %d\n", __func__, gpio, value);
|
||||
gpio_set_value(gpio, value);
|
||||
/* hardware dependent delay */
|
||||
usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC,
|
||||
NFC_GPIO_SET_WAIT_TIME_USEC + 100);
|
||||
}
|
||||
}
|
||||
|
||||
int get_valid_gpio(int gpio)
|
||||
{
|
||||
int value = -EINVAL;
|
||||
|
||||
if (gpio_is_valid(gpio)) {
|
||||
value = gpio_get_value(gpio);
|
||||
pr_debug("%s gpio %d value %d\n", __func__, gpio, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void gpio_set_ven(struct nfc_dev *nfc_dev, int value)
|
||||
{
|
||||
if (gpio_get_value(nfc_dev->gpio.ven) != value) {
|
||||
gpio_set_value(nfc_dev->gpio.ven, value);
|
||||
// hardware dependent delay
|
||||
usleep_range(10000, 10100);
|
||||
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
|
||||
|
||||
if (gpio_get_value(nfc_gpio->ven) != value) {
|
||||
pr_debug("%s: value %d\n", __func__, value);
|
||||
|
||||
gpio_set_value(nfc_gpio->ven, value);
|
||||
/* hardware dependent delay */
|
||||
usleep_range(NFC_GPIO_SET_WAIT_TIME_USEC,
|
||||
NFC_GPIO_SET_WAIT_TIME_USEC + 100);
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,11 +254,14 @@ int configure_gpio(unsigned int gpio, int flag)
|
||||
__func__, gpio);
|
||||
return ret;
|
||||
}
|
||||
// set direction and value for output pin
|
||||
if (flag & GPIO_OUTPUT)
|
||||
/* set direction and value for output pin */
|
||||
if (flag & GPIO_OUTPUT) {
|
||||
ret = gpio_direction_output(gpio, (GPIO_HIGH & flag));
|
||||
else
|
||||
pr_debug("nfc o/p gpio %d level %d\n", gpio, gpio_get_value(gpio));
|
||||
} else {
|
||||
ret = gpio_direction_input(gpio);
|
||||
pr_debug("nfc i/p gpio %d\n", gpio);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
pr_err
|
||||
@ -238,7 +291,7 @@ int configure_gpio(unsigned int gpio, int flag)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nfc_misc_remove(struct nfc_dev *nfc_dev, int count)
|
||||
void nfc_misc_unregister(struct nfc_dev *nfc_dev, int count)
|
||||
{
|
||||
pr_debug("%s: entry\n", __func__);
|
||||
|
||||
@ -251,7 +304,7 @@ void nfc_misc_remove(struct nfc_dev *nfc_dev, int count)
|
||||
ipc_log_context_destroy(nfc_dev->ipcl);
|
||||
}
|
||||
|
||||
int nfc_misc_probe(struct nfc_dev *nfc_dev,
|
||||
int nfc_misc_register(struct nfc_dev *nfc_dev,
|
||||
const struct file_operations *nfc_fops, int count,
|
||||
char *devname, char *classname)
|
||||
{
|
||||
@ -297,7 +350,7 @@ int nfc_misc_probe(struct nfc_dev *nfc_dev,
|
||||
nfc_dev->kbuflen = MAX_BUFFER_SIZE;
|
||||
nfc_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
if (!nfc_dev->kbuf) {
|
||||
nfc_misc_remove(nfc_dev, count);
|
||||
nfc_misc_unregister(nfc_dev, count);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -311,9 +364,6 @@ int nfc_misc_probe(struct nfc_dev *nfc_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Power management of the eSE
|
||||
* eSE and NFCC both are powered using VEN gpio,
|
||||
@ -332,7 +382,7 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
|
||||
* VEN state will remain HIGH if NFC is enabled otherwise
|
||||
* it will be set as LOW
|
||||
*/
|
||||
nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->gpio.ven);
|
||||
nfc_dev->nfc_ven_enabled = gpio_get_value(nfc_dev->configs.gpio.ven);
|
||||
if (!nfc_dev->nfc_ven_enabled) {
|
||||
pr_debug("eSE HAL service setting ven HIGH\n");
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
@ -349,8 +399,8 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
|
||||
}
|
||||
nfc_dev->is_ese_session_active = false;
|
||||
} else if (arg == ESE_POWER_STATE) {
|
||||
// eSE power state
|
||||
ret = gpio_get_value(nfc_dev->gpio.ven);
|
||||
/* get VEN gpio state for eSE, as eSE also enabled through same GPIO */
|
||||
ret = gpio_get_value(nfc_dev->configs.gpio.ven);
|
||||
} else {
|
||||
pr_err("%s bad arg %lu\n", __func__, arg);
|
||||
ret = -ENOIOCTLCMD;
|
||||
@ -371,6 +421,7 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
|
||||
static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
|
||||
|
||||
if (arg == NFC_POWER_OFF) {
|
||||
/*
|
||||
@ -379,24 +430,14 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg)
|
||||
* layers.
|
||||
*/
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
pr_debug("gpio firm disable\n");
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 0);
|
||||
usleep_range(10000, 10100);
|
||||
}
|
||||
|
||||
pr_debug("Set ven to low\n");
|
||||
set_valid_gpio(nfc_gpio->dwl_req, 0);
|
||||
gpio_set_ven(nfc_dev, 0);
|
||||
|
||||
nfc_dev->nfc_ven_enabled = false;
|
||||
|
||||
} else if (arg == NFC_POWER_ON) {
|
||||
nfc_dev->nfc_enable_intr(nfc_dev);
|
||||
pr_debug("gpio_set_value enable: %s:\n", __func__);
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 0);
|
||||
usleep_range(10000, 10100);
|
||||
}
|
||||
set_valid_gpio(nfc_gpio->dwl_req, 0);
|
||||
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
nfc_dev->nfc_ven_enabled = true;
|
||||
|
||||
@ -405,37 +446,26 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg)
|
||||
* We are switching to download Mode, toggle the enable pin
|
||||
* in order to set the NFCC in the new mode
|
||||
*/
|
||||
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
set_valid_gpio(nfc_gpio->dwl_req, 1);
|
||||
nfc_dev->nfc_state = NFC_STATE_FW_DWL;
|
||||
gpio_set_ven(nfc_dev, 0);
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 1);
|
||||
usleep_range(10000, 10100);
|
||||
}
|
||||
if (nfc_dev->interface == PLATFORM_IF_I2C) {
|
||||
gpio_set_ven(nfc_dev, 0);
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
}
|
||||
|
||||
nfc_dev->nfc_enable_intr(nfc_dev);
|
||||
} else if (arg == NFC_FW_DWL_HIGH) {
|
||||
/*
|
||||
* Setting firmware download gpio to HIGH
|
||||
* before FW download start
|
||||
*/
|
||||
pr_debug("set fw gpio high\n");
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 1);
|
||||
usleep_range(10000, 10100);
|
||||
} else
|
||||
pr_debug("gpio.dwl_req is invalid\n");
|
||||
set_valid_gpio(nfc_gpio->dwl_req, 1);
|
||||
nfc_dev->nfc_state = NFC_STATE_FW_DWL;
|
||||
|
||||
} else if (arg == NFC_VEN_FORCED_HARD_RESET
|
||||
&& nfc_dev->interface == PLATFORM_IF_I2C) {
|
||||
|
||||
gpio_set_value(nfc_dev->gpio.ven, 0);
|
||||
usleep_range(10000, 10100);
|
||||
gpio_set_value(nfc_dev->gpio.ven, 1);
|
||||
usleep_range(10000, 10100);
|
||||
} else if (arg == NFC_VEN_FORCED_HARD_RESET) {
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
gpio_set_ven(nfc_dev, 0);
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
nfc_dev->nfc_enable_intr(nfc_dev);
|
||||
pr_info("%s VEN forced reset done\n", __func__);
|
||||
|
||||
} else if (arg == NFC_FW_DWL_LOW) {
|
||||
@ -444,8 +474,8 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg)
|
||||
* FW download finished
|
||||
*/
|
||||
pr_debug("set fw gpio LOW\n");
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 0);
|
||||
usleep_range(10000, 10100);
|
||||
set_valid_gpio(nfc_gpio->dwl_req, 0);
|
||||
nfc_dev->nfc_state = NFC_STATE_NCI;
|
||||
|
||||
} else if (arg == NFC_ENABLE) {
|
||||
/*
|
||||
@ -477,7 +507,7 @@ unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg)
|
||||
struct nfc_dev *nfc_dev = filp->private_data;
|
||||
|
||||
r = nfc_dev->nqx_info.i;
|
||||
pr_debug("nfc : %s r = %d\n", __func__, r);
|
||||
pr_debug("nfc : %s r = 0x%x\n", __func__, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -520,8 +550,11 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
|
||||
pr_debug("nfc ese cold reset ioctl\n");
|
||||
ret = ese_cold_reset_ioctl(nfc_dev, arg);
|
||||
break;
|
||||
case NFC_GET_IRQ_STATE:
|
||||
ret = gpio_get_value(nfc_dev->configs.gpio.irq);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s Unsupported ioctl 0x%x, arg %lu\n",
|
||||
pr_err("%s Unsupported ioctl cmd 0x%x, arg %lu\n",
|
||||
__func__, cmd, arg);
|
||||
ret = -ENOIOCTLCMD;
|
||||
}
|
||||
@ -543,10 +576,7 @@ int nfc_dev_open(struct inode *inode, struct file *filp)
|
||||
filp->private_data = nfc_dev;
|
||||
|
||||
if (nfc_dev->dev_ref_count == 0) {
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 0);
|
||||
usleep_range(10000, 10100);
|
||||
}
|
||||
set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0);
|
||||
nfc_dev->nfc_enable_intr(nfc_dev);
|
||||
}
|
||||
nfc_dev->dev_ref_count = nfc_dev->dev_ref_count + 1;
|
||||
@ -569,13 +599,8 @@ int nfc_dev_close(struct inode *inode, struct file *filp)
|
||||
mutex_lock(&nfc_dev->dev_ref_mutex);
|
||||
|
||||
if (nfc_dev->dev_ref_count == 1) {
|
||||
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 0);
|
||||
usleep_range(10000, 10100);
|
||||
}
|
||||
set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0);
|
||||
}
|
||||
|
||||
if (nfc_dev->dev_ref_count > 0)
|
||||
@ -600,213 +625,327 @@ int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
uint8_t *cmd = nfc_dev->write_kbuf;
|
||||
uint8_t *rsp = nfc_dev->read_kbuf;
|
||||
enum chip_types chip_type = CHIP_UNKNOWN;
|
||||
|
||||
*cmd++ = DL_CMD;
|
||||
*cmd++ = DL_GET_VERSION_CMD_PAYLOAD_LEN;
|
||||
*cmd++ = DL_GET_VERSION_CMD_ID;
|
||||
*cmd++ = DL_PAYLOAD_BYTE_ZERO;
|
||||
*cmd++ = DL_PAYLOAD_BYTE_ZERO;
|
||||
*cmd++ = DL_PAYLOAD_BYTE_ZERO;
|
||||
*cmd++ = DL_GET_VERSION_CMD_CRC_1;
|
||||
*cmd++ = DL_GET_VERSION_CMD_CRC_2;
|
||||
|
||||
pr_debug("%s:Sending GET_VERSION cmd of size = %d\n", __func__, DL_GET_VERSION_CMD_LEN);
|
||||
ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_VERSION_CMD_LEN,
|
||||
MAX_RETRY_COUNT);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret);
|
||||
goto err;
|
||||
}
|
||||
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, 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;
|
||||
}
|
||||
if (rsp[0] == FW_MSG_CMD_RSP && ret >= DL_GET_VERSION_RSP_LEN_2) {
|
||||
|
||||
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_debug("%s:NFC Chip Type 0x%02x Rom Version 0x%02x FW Minor 0x%02x Major 0x%02x\n",
|
||||
__func__, rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET],
|
||||
rsp[FW_ROM_CODE_VER_OFFSET],
|
||||
rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET],
|
||||
rsp[FW_MAJOR_VER_OFFSET]);
|
||||
|
||||
nfc_dev->nqx_info.info.chip_type = rsp[GET_VERSION_RSP_CHIP_TYPE_OFFSET];
|
||||
nfc_dev->nqx_info.info.rom_version = rsp[FW_ROM_CODE_VER_OFFSET];
|
||||
nfc_dev->nqx_info.info.fw_minor = rsp[GET_VERSION_RSP_MINOR_VERSION_OFFSET];
|
||||
nfc_dev->nqx_info.info.fw_major = rsp[FW_MAJOR_VER_OFFSET];
|
||||
}
|
||||
err:
|
||||
return chip_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
uint8_t *cmd = nfc_dev->write_kbuf;
|
||||
uint8_t *rsp = nfc_dev->read_kbuf;
|
||||
enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN;
|
||||
|
||||
*cmd++ = DL_CMD;
|
||||
*cmd++ = DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN;
|
||||
*cmd++ = DL_GET_SESSION_CMD_ID;
|
||||
*cmd++ = DL_PAYLOAD_BYTE_ZERO;
|
||||
*cmd++ = DL_PAYLOAD_BYTE_ZERO;
|
||||
*cmd++ = DL_PAYLOAD_BYTE_ZERO;
|
||||
*cmd++ = DL_GET_SESSION_CMD_CRC_1;
|
||||
*cmd++ = DL_GET_SESSION_CMD_CRC_2;
|
||||
|
||||
pr_debug("%s:Sending GET_SESSION_STATE cmd of size = %d\n", __func__,
|
||||
DL_GET_SESSION_STATE_CMD_LEN);
|
||||
ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, DL_GET_SESSION_STATE_CMD_LEN,
|
||||
MAX_RETRY_COUNT);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - nfc get session cmd error ret %d\n", __func__, ret);
|
||||
goto err;
|
||||
}
|
||||
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\n",
|
||||
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:
|
||||
return nfc_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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;
|
||||
|
||||
*cmd++ = NCI_MSG_CMD;
|
||||
*cmd++ = NCI_CORE_RESET_CMD_OID;
|
||||
*cmd++ = NCI_CORE_RESET_CMD_PAYLOAD_LEN;
|
||||
*cmd++ = NCI_CORE_RESET_KEEP_CONFIG;
|
||||
|
||||
pr_debug("%s:Sending NCI Core Reset cmd of size = %d\n", __func__, NCI_RESET_CMD_LEN);
|
||||
ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->write_kbuf, NCI_RESET_CMD_LEN, NO_RETRY);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - nfc nci core reset cmd error ret %d\n", __func__, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* to flush out debug NTF this delay is required */
|
||||
usleep_range(NCI_RESET_RESP_READ_DELAY, NCI_RESET_RESP_READ_DELAY + 100);
|
||||
nfc_dev->nfc_enable_intr(nfc_dev);
|
||||
|
||||
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%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\n", __func__);
|
||||
goto err_disable_intr;
|
||||
}
|
||||
|
||||
memset(rsp, 0x00, NCI_RESET_NTF_LEN);
|
||||
/* read nci rest response ntf */
|
||||
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;
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
nfc_dev->nqx_info.info.chip_type = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] -
|
||||
NFC_CHIP_TYPE_OFF];
|
||||
nfc_dev->nqx_info.info.rom_version = rom_version;
|
||||
nfc_dev->nqx_info.info.fw_major = major_version;
|
||||
nfc_dev->nqx_info.info.fw_minor = rsp[NCI_HDR_LEN + rsp[NCI_PAYLOAD_LEN_IDX] -
|
||||
NFC_FW_MINOR_OFF];
|
||||
}
|
||||
err_disable_intr:
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
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;
|
||||
unsigned char reset_ntf_len = 0;
|
||||
char *nci_reset_cmd = NULL;
|
||||
char *nci_reset_rsp = NULL;
|
||||
char *nci_reset_ntf = NULL;
|
||||
char *nci_get_version_cmd = NULL;
|
||||
char *nci_get_version_rsp = NULL;
|
||||
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;
|
||||
|
||||
NFCLOG_IPC(nfc_dev, false, "%s", __func__);
|
||||
/*get fw version in nci mode*/
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
gpio_set_ven(nfc_dev, 0);
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
chip_type = get_nfcc_chip_type(nfc_dev);
|
||||
|
||||
nci_reset_cmd = kzalloc(NCI_RESET_CMD_LEN + 1, GFP_DMA | GFP_KERNEL);
|
||||
if (!nci_reset_cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
nci_reset_rsp = kzalloc(NCI_RESET_RSP_LEN + 1, GFP_DMA | GFP_KERNEL);
|
||||
if (!nci_reset_rsp) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
nci_reset_ntf = kzalloc(NCI_RESET_NTF_LEN + 1, GFP_DMA | GFP_KERNEL);
|
||||
if (!nci_reset_ntf) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
nci_get_version_cmd = kzalloc(NCI_GET_VERSION_CMD_LEN + 1,
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (!nci_get_version_cmd) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
nci_get_version_rsp = kzalloc(NCI_GET_VERSION_RSP_LEN + 1,
|
||||
GFP_DMA | GFP_KERNEL);
|
||||
if (!nci_get_version_rsp) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* making sure that the NFCC starts in a clean state. */
|
||||
gpio_set_ven(nfc_dev, 1);/* HPD : Enable*/
|
||||
gpio_set_ven(nfc_dev, 0);/* ULPM: Disable */
|
||||
gpio_set_ven(nfc_dev, 1);/* HPD : Enable*/
|
||||
|
||||
nci_reset_cmd[0] = 0x20;
|
||||
nci_reset_cmd[1] = 0x00;
|
||||
nci_reset_cmd[2] = 0x01;
|
||||
nci_reset_cmd[3] = 0x00;
|
||||
|
||||
/* send NCI CORE RESET CMD with Keep Config parameters */
|
||||
ret = nfc_dev->nfc_write(nfc_dev, nci_reset_cmd, NCI_RESET_CMD_LEN,
|
||||
MAX_RETRY_COUNT);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - nfc core reset error\n", __func__);
|
||||
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 1);
|
||||
usleep_range(10000, 10100);
|
||||
}
|
||||
|
||||
if (nfc_dev->interface == PLATFORM_IF_I2C) {
|
||||
gpio_set_ven(nfc_dev, 0);
|
||||
gpio_set_ven(nfc_dev, 1);
|
||||
}
|
||||
|
||||
nci_get_version_cmd[0] = 0x00;
|
||||
nci_get_version_cmd[1] = 0x04;
|
||||
nci_get_version_cmd[2] = 0xF1;
|
||||
nci_get_version_cmd[3] = 0x00;
|
||||
nci_get_version_cmd[4] = 0x00;
|
||||
nci_get_version_cmd[5] = 0x00;
|
||||
nci_get_version_cmd[6] = 0x6E;
|
||||
nci_get_version_cmd[7] = 0xEF;
|
||||
|
||||
ret = nfc_dev->nfc_write(nfc_dev, nci_get_version_cmd,
|
||||
NCI_GET_VERSION_CMD_LEN, MAX_RETRY_COUNT);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - nfc get version cmd error ret %d\n",
|
||||
__func__, ret);
|
||||
goto err_nfcc_hw_check;
|
||||
}
|
||||
|
||||
if (nfc_dev->interface == PLATFORM_IF_I2C) {
|
||||
ret = is_nfc_data_available_for_read(nfc_dev);
|
||||
if (ret <= 0) {
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
pr_err("%s: - error waiting for get version rsp ret %d\n",
|
||||
__func__, ret);
|
||||
goto err_nfcc_hw_check;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nfc_dev->nfc_read(nfc_dev, nci_get_version_rsp,
|
||||
NCI_GET_VERSION_RSP_LEN);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - nfc get version rsp error ret %d\n",
|
||||
__func__, ret);
|
||||
goto err_nfcc_hw_check;
|
||||
} else {
|
||||
nfc_dev->nqx_info.info.chip_type =
|
||||
nci_get_version_rsp[3];
|
||||
nfc_dev->nqx_info.info.rom_version =
|
||||
nci_get_version_rsp[4];
|
||||
nfc_dev->nqx_info.info.fw_minor =
|
||||
nci_get_version_rsp[6];
|
||||
nfc_dev->nqx_info.info.fw_major =
|
||||
nci_get_version_rsp[7];
|
||||
}
|
||||
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 0);
|
||||
|
||||
goto err_nfcc_reset_failed;
|
||||
}
|
||||
|
||||
if (nfc_dev->interface == PLATFORM_IF_I2C) {
|
||||
ret = is_nfc_data_available_for_read(nfc_dev);
|
||||
if (ret <= 0) {
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
pr_err("%s: - error waiting for core reset rsp ret %d\n",
|
||||
__func__, ret);
|
||||
|
||||
goto err_nfcc_hw_check;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read Response of RESET command */
|
||||
ret = nfc_dev->nfc_read(nfc_dev, nci_reset_rsp, NCI_RESET_RSP_LEN);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - nfc rst rsp read err %d\n", __func__,
|
||||
ret);
|
||||
goto err_nfcc_hw_check;
|
||||
}
|
||||
|
||||
if (nfc_dev->interface == PLATFORM_IF_I2C) {
|
||||
ret = is_nfc_data_available_for_read(nfc_dev);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: - error waiting for core reset ntf ret %d\n",
|
||||
__func__, ret);
|
||||
nfc_dev->nfc_disable_intr(nfc_dev);
|
||||
goto err_nfcc_hw_check;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read Notification of RESET command */
|
||||
ret = nfc_dev->nfc_read(nfc_dev, nci_reset_ntf, NCI_RESET_NTF_LEN);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: nfc nfc read error %d\n", __func__, ret);
|
||||
goto err_nfcc_hw_check;
|
||||
}
|
||||
|
||||
reset_ntf_len = NCI_HDR_LEN + nci_reset_ntf[NCI_PAYLOAD_LEN_IDX] - 1;
|
||||
if (reset_ntf_len > NCI_HDR_LEN) {
|
||||
nfc_dev->nqx_info.info.chip_type =
|
||||
nci_reset_ntf[reset_ntf_len - NFC_CHIP_TYPE_OFF];
|
||||
nfc_dev->nqx_info.info.rom_version =
|
||||
nci_reset_ntf[reset_ntf_len - NFC_ROM_VERSION_OFF];
|
||||
nfc_dev->nqx_info.info.fw_major =
|
||||
nci_reset_ntf[reset_ntf_len - NFC_FW_MAJOR_OFF];
|
||||
nfc_dev->nqx_info.info.fw_minor =
|
||||
nci_reset_ntf[reset_ntf_len];
|
||||
}
|
||||
pr_debug("%s: - NFC reset rsp : NfcNciRx %x %x %x\n",
|
||||
__func__, nci_reset_rsp[0],
|
||||
nci_reset_rsp[1], nci_reset_rsp[2]);
|
||||
|
||||
err_nfcc_reset_failed:
|
||||
pr_info("NFC chip_type = %x\n",
|
||||
nfc_dev->nqx_info.info.chip_type);
|
||||
pr_info("NFC fw version = %x.%x.%x\n",
|
||||
nfc_dev->nqx_info.info.rom_version,
|
||||
nfc_dev->nqx_info.info.fw_major,
|
||||
nfc_dev->nqx_info.info.fw_minor);
|
||||
|
||||
switch (nfc_dev->nqx_info.info.chip_type) {
|
||||
case NFCC_SN100_A:
|
||||
case NFCC_SN100_B:
|
||||
pr_debug("%s: ## NFCC == SN100x ##\n", __func__);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: - NFCC HW not Supported\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
nfc_dev->nfc_ven_enabled = true;
|
||||
|
||||
goto done;
|
||||
|
||||
err_nfcc_hw_check:
|
||||
if (nfc_dev->interface == PLATFORM_IF_I2C)
|
||||
/*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;
|
||||
}
|
||||
|
||||
gpio_set_value(nfc_dev->gpio.dwl_req, 0);
|
||||
/*validate gpio config required as per the chip*/
|
||||
if (!validate_download_gpio(nfc_dev, chip_type)) {
|
||||
pr_info("%s gpio validation fail\n", __func__);
|
||||
ret = -ENXIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = -ENXIO;
|
||||
pr_debug("%s: - NFCC HW not available\n", __func__);
|
||||
|
||||
done:
|
||||
kfree(nci_reset_rsp);
|
||||
kfree(nci_reset_ntf);
|
||||
kfree(nci_get_version_cmd);
|
||||
kfree(nci_get_version_rsp);
|
||||
kfree(nci_reset_cmd);
|
||||
/*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_TEARED:
|
||||
pr_warn("%s: - NFCC FW Teared State\n", __func__);
|
||||
case NFC_STATE_FW_DWL:
|
||||
case NFC_STATE_NCI:
|
||||
break;
|
||||
case NFC_STATE_UNKNOWN:
|
||||
default:
|
||||
ret = -ENXIO;
|
||||
pr_err("%s: - NFCC HW not available\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
nfc_dev->nfc_state = nfc_state;
|
||||
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);
|
||||
nfc_dev->nfc_ven_enabled = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int validate_nfc_state_nci(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
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 (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;
|
||||
}
|
||||
|
@ -1,7 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
* Copyright (c) 2019-2021 NXP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _NFC_COMMON_H_
|
||||
#define _NFC_COMMON_H_
|
||||
@ -37,32 +53,78 @@
|
||||
// NFC character device name, this will be in /dev/
|
||||
#define NFC_CHAR_DEV_NAME "nq-nci"
|
||||
|
||||
// HDR length of NCI packet
|
||||
#define NCI_HDR_LEN 3
|
||||
#define NCI_PAYLOAD_IDX 3
|
||||
#define NCI_PAYLOAD_LEN_IDX 2
|
||||
// NCI packet details
|
||||
#define NCI_MSG_CMD 0x20
|
||||
#define NCI_MSG_RSP 0x40
|
||||
#define NCI_MSG_NTF 0x60
|
||||
#define DL_CMD 0x00
|
||||
#define DL_PAYLOAD_BYTE_ZERO 0x00
|
||||
#define NCI_HDR_LEN 3
|
||||
#define NCI_PAYLOAD_IDX 3
|
||||
#define NCI_PAYLOAD_LEN_IDX 2
|
||||
|
||||
/*Time to wait for first NCI rest response*/
|
||||
#define NCI_RESET_RESP_READ_DELAY (10000) // 10ms
|
||||
#define NCI_RESET_RESP_TIMEOUT (500) // 500ms
|
||||
|
||||
// FW DNLD packet details
|
||||
#define FW_MSG_CMD_RSP 0x00
|
||||
#define FW_HDR_LEN 2
|
||||
#define FW_PAYLOAD_LEN_IDX 1
|
||||
#define FW_CRC_LEN 2
|
||||
|
||||
#define NCI_RSP_PKT_TYPE (0x40)
|
||||
#define FW_MIN_PAYLOAD_LEN 4
|
||||
#define MIN_NFC_DL_FRAME_SIZE 3
|
||||
|
||||
#define NCI_RESET_CMD_LEN (4)
|
||||
#define NCI_RESET_RSP_LEN (4)
|
||||
#define NCI_CORE_RESET_CMD_OID (0x0)
|
||||
#define NCI_CORE_RESET_CMD_PAYLOAD_LEN (0x1)
|
||||
#define NCI_CORE_RESET_KEEP_CONFIG (0x0)
|
||||
#define NCI_RESET_NTF_LEN (13)
|
||||
#define NCI_GET_VERSION_CMD_LEN (8)
|
||||
#define NCI_GET_VERSION_RSP_LEN (12)
|
||||
#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 GET_VERSION_RSP_CHIP_TYPE_OFFSET 3
|
||||
#define GET_VERSION_RSP_MINOR_VERSION_OFFSET 6
|
||||
#define DL_GET_VERSION_CMD_LEN (8)
|
||||
#define DL_GET_VERSION_RSP_LEN_1 (12) /* SN110 */
|
||||
#define DL_GET_VERSION_RSP_LEN_2 (20) /* SN220 */
|
||||
#define DL_GET_VERSION_CMD_PAYLOAD_LEN (4)
|
||||
#define DL_GET_VERSION_CMD_ID (0xF1)
|
||||
#define DL_GET_VERSION_CMD_CRC_1 (0x6E)
|
||||
#define DL_GET_VERSION_CMD_CRC_2 (0xEF)
|
||||
|
||||
// Below offsets should be subtracted from core reset ntf len
|
||||
#define DL_RESET_CMD_LEN (8)
|
||||
#define DL_GET_SESSION_STATE_CMD_LEN (8)
|
||||
#define DL_GET_SESSION_STATE_RSP_LEN (8)
|
||||
#define DL_GET_SESSION_STATE_CMD_PAYLOAD_LEN (4)
|
||||
#define DL_GET_SESSION_CMD_ID (0xF2)
|
||||
#define DL_GET_SESSION_CMD_CRC_1 (0xF5)
|
||||
#define DL_GET_SESSION_CMD_CRC_2 (0x33)
|
||||
#define GET_SESSION_STS_OFF (3)
|
||||
#define NFCC_SESSION_STS_CLOSED (0x0)
|
||||
|
||||
#define NFC_CHIP_TYPE_OFF (3)
|
||||
#define NFC_ROM_VERSION_OFF (2)
|
||||
#define NFC_FW_MAJOR_OFF (1)
|
||||
/* Below offsets should be subtracted from NCI header length + payload length */
|
||||
|
||||
#define NFC_CHIP_TYPE_OFF (4)
|
||||
#define NFC_FW_MINOR_OFF (1)
|
||||
|
||||
#define GET_VERSION_CMD_LEN 8
|
||||
#define GET_SESSION_STATE_CMD_LEN 8
|
||||
#define MAX_NCI_PAYLOAD_LEN (255)
|
||||
#define MAX_BUFFER_SIZE (NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN)
|
||||
/*
|
||||
* From MW 11.04 buffer size increased to support
|
||||
* frame size of 554 in FW download mode
|
||||
* Frame len(2) + Frame Header(6) + DATA(512) + HASH(32) + CRC(2) + RFU(4)
|
||||
*/
|
||||
#define MAX_BUFFER_SIZE (558)
|
||||
|
||||
#define MAX_DL_PAYLOAD_LEN (550)
|
||||
#define MAX_DL_BUFFER_SIZE (FW_HDR_LEN + FW_CRC_LEN + MAX_DL_PAYLOAD_LEN)
|
||||
// Maximum retry count for standby writes
|
||||
#define MAX_RETRY_COUNT (3)
|
||||
|
||||
@ -71,6 +133,16 @@
|
||||
#define MAX_IRQ_WAIT_TIME (90)
|
||||
#define WAKEUP_SRC_TIMEOUT (2000)
|
||||
|
||||
/*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*/
|
||||
#define WRITE_RETRY_WAIT_TIME_USEC (1000)
|
||||
/*Time to wait before retrying read for some specific usecases*/
|
||||
#define READ_RETRY_WAIT_TIME_USEC (3500)
|
||||
#define NFC_MAGIC 0xE9
|
||||
|
||||
// Ioctls
|
||||
@ -81,6 +153,9 @@
|
||||
#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, unsigned int)
|
||||
#define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04)
|
||||
|
||||
/* NFC HAL can call this ioctl to get the current IRQ state */
|
||||
#define NFC_GET_IRQ_STATE _IO(NFC_MAGIC, 0x06)
|
||||
|
||||
#define DTS_IRQ_GPIO_STR "qcom,sn-irq"
|
||||
#define DTS_VEN_GPIO_STR "qcom,sn-ven"
|
||||
#define DTS_FWDN_GPIO_STR "qcom,sn-firm"
|
||||
@ -141,8 +216,6 @@ enum nfcc_ioctl_request {
|
||||
NFC_ENABLE,
|
||||
/* NFC disable without VEN gpio modification */
|
||||
NFC_DISABLE,
|
||||
/*for HDR size change in FW mode */
|
||||
NFC_FW_HDR_LEN,
|
||||
};
|
||||
|
||||
/*nfc platform interface type*/
|
||||
@ -151,11 +224,21 @@ enum interface_flags {
|
||||
PLATFORM_IF_I2C = 0,
|
||||
};
|
||||
|
||||
/*nfc state flags*/
|
||||
enum nfc_state_flags {
|
||||
/*nfc in unknown state */
|
||||
NFC_STATE_UNKNOWN = 0,
|
||||
/*nfc in download mode */
|
||||
NFC_STATE_FW_DWL = 0x1,
|
||||
/*nfc booted in NCI mode */
|
||||
NFC_STATE_NCI = 0x2,
|
||||
/*nfc booted in Fw teared mode */
|
||||
NFC_STATE_FW_TEARED = 0x4,
|
||||
};
|
||||
/*
|
||||
* Power state for IBI handing, mainly needed to defer the IBI handling
|
||||
* for the IBI received in suspend state to do it later in resume call
|
||||
*/
|
||||
|
||||
enum pm_state_flags {
|
||||
PM_STATE_NORMAL = 0,
|
||||
PM_STATE_SUSPEND,
|
||||
@ -171,12 +254,6 @@ enum gpio_values {
|
||||
GPIO_IRQ = 0x4,
|
||||
};
|
||||
|
||||
enum nfcc_chip_variant {
|
||||
NFCC_SN100_A = 0xa3, /**< NFCC SN100_A */
|
||||
NFCC_SN100_B = 0xa4, /**< NFCC SN100_B */
|
||||
NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */
|
||||
};
|
||||
|
||||
// NFC GPIO variables
|
||||
struct platform_gpio {
|
||||
unsigned int irq;
|
||||
@ -191,11 +268,25 @@ struct platform_ldo {
|
||||
int max_current;
|
||||
};
|
||||
|
||||
// NFC Struct to get all the required configs from DTS
|
||||
struct platform_configs {
|
||||
struct platform_gpio gpio;
|
||||
struct platform_ldo ldo;
|
||||
};
|
||||
|
||||
enum chip_types {
|
||||
CHIP_SN1XX = 0x01,
|
||||
CHIP_SN220 = 0x02,
|
||||
CHIP_UNKNOWN = 0xFF,
|
||||
};
|
||||
|
||||
/* Device specific structure */
|
||||
struct nfc_dev {
|
||||
wait_queue_head_t read_wq;
|
||||
struct mutex read_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;
|
||||
@ -204,13 +295,16 @@ struct nfc_dev {
|
||||
dev_t devno;
|
||||
/* Interface flag */
|
||||
uint8_t interface;
|
||||
/* nfc state flags */
|
||||
uint8_t nfc_state;
|
||||
/* NFC VEN pin state */
|
||||
bool nfc_ven_enabled;
|
||||
/* current firmware major version */
|
||||
uint8_t fw_major_version;
|
||||
bool is_vreg_enabled;
|
||||
bool is_ese_session_active;
|
||||
struct i2c_dev i2c_dev;
|
||||
struct platform_gpio gpio;
|
||||
struct platform_ldo ldo;
|
||||
struct platform_configs configs;
|
||||
struct cold_reset cold_reset;
|
||||
struct regulator *reg;
|
||||
|
||||
@ -222,10 +316,9 @@ struct nfc_dev {
|
||||
|
||||
void *ipcl;
|
||||
|
||||
int (*nfc_read)(struct nfc_dev *dev,
|
||||
char *buf, size_t count);
|
||||
int (*nfc_write)(struct nfc_dev *dev,
|
||||
const char *buf, const size_t count, int max_retry_cnt);
|
||||
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);
|
||||
};
|
||||
@ -233,12 +326,12 @@ struct nfc_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, struct platform_gpio *nfc_gpio,
|
||||
struct platform_ldo *ldo, uint8_t interface);
|
||||
int nfc_misc_probe(struct nfc_dev *nfc_dev,
|
||||
const struct file_operations *nfc_fops, int count,
|
||||
char *devname, char *classname);
|
||||
void nfc_misc_remove(struct nfc_dev *nfc_dev, int count);
|
||||
int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
|
||||
uint8_t interface);
|
||||
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(struct nfc_dev *nfc_dev, int count);
|
||||
int configure_gpio(unsigned int gpio, int flag);
|
||||
void gpio_set_ven(struct nfc_dev *nfc_dev, int value);
|
||||
int nfcc_hw_check(struct nfc_dev *nfc_dev);
|
||||
@ -246,5 +339,8 @@ int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev);
|
||||
int nfc_ldo_vote(struct nfc_dev *nfc_dev);
|
||||
int nfc_ldo_unvote(struct nfc_dev *nfc_dev);
|
||||
int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev);
|
||||
|
||||
int validate_nfc_state_nci(struct nfc_dev *nfc_dev);
|
||||
void set_nfcc_state_from_rsp(struct nfc_dev *dev, const char *buf,
|
||||
const int count);
|
||||
void enable_dwnld_mode(struct nfc_dev *nfc_dev, bool value);
|
||||
#endif //_NFC_COMMON_H_
|
||||
|
@ -1,6 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013-2021 NXP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Copyright (C) 2010 Trusted Logic S.A.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "nfc_common.h"
|
||||
@ -63,60 +96,126 @@ 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 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;
|
||||
uint16_t i = 0;
|
||||
uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count);
|
||||
|
||||
pr_debug("%s : reading %zu bytes.\n", __func__, count);
|
||||
/* Read data */
|
||||
|
||||
ret = i2c_master_recv(dev->i2c_dev.client, buf, count);
|
||||
NFCLOG_IPC(dev, false, "%s of %d bytes, ret %d", __func__, count,
|
||||
if (timeout > NCI_CMD_RSP_TIMEOUT)
|
||||
timeout = NCI_CMD_RSP_TIMEOUT;
|
||||
|
||||
if (count > MAX_BUFFER_SIZE)
|
||||
count = MAX_BUFFER_SIZE;
|
||||
|
||||
if (!gpio_get_value(nfc_gpio->irq)) {
|
||||
while (1) {
|
||||
ret = 0;
|
||||
if (!i2c_dev->irq_enabled) {
|
||||
i2c_dev->irq_enabled = true;
|
||||
enable_irq(i2c_dev->client->irq);
|
||||
}
|
||||
if (!gpio_get_value(nfc_gpio->irq)) {
|
||||
if (timeout) {
|
||||
ret = wait_event_interruptible_timeout(nfc_dev->read_wq,
|
||||
!i2c_dev->irq_enabled, msecs_to_jiffies(timeout));
|
||||
|
||||
if (ret <= 0) {
|
||||
pr_err("%s timeout/error in read\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
ret = wait_event_interruptible(nfc_dev->read_wq,
|
||||
!i2c_dev->irq_enabled);
|
||||
if (ret) {
|
||||
pr_err("%s error wakeup of read wq\n", __func__);
|
||||
ret = -EINTR;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
i2c_disable_irq(nfc_dev);
|
||||
|
||||
if (gpio_get_value(nfc_gpio->irq))
|
||||
break;
|
||||
if (!gpio_get_value(nfc_gpio->ven)) {
|
||||
pr_info("%s: releasing read\n", __func__);
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
pr_warn("%s: spurious interrupt detected\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf, 0x00, count);
|
||||
/* Read data */
|
||||
ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf, count);
|
||||
NFCLOG_IPC(nfc_dev, false, "%s of %d bytes, ret %d", __func__, count,
|
||||
ret);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: i2c_master_recv returned %d\n", __func__, ret);
|
||||
goto i2c_read_err;
|
||||
}
|
||||
if (ret > count) {
|
||||
pr_err("%s: received too many bytes from i2c (%d)\n",
|
||||
__func__, ret);
|
||||
ret = -EIO;
|
||||
pr_err("%s: returned %d\n", __func__, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < disp_len; i++)
|
||||
NFCLOG_IPC(dev, false, " %02x", buf[i]);
|
||||
NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]);
|
||||
|
||||
/* delay for the slow nfc devices between susequent read operation */
|
||||
usleep_range(1000, 1100);
|
||||
i2c_read_err:
|
||||
/* check if it's response of cold reset command
|
||||
* NFC HAL process shouldn't receive this data as
|
||||
* command was esepowermanager
|
||||
*/
|
||||
if (nfc_dev->cold_reset.rsp_pending && nfc_dev->cold_reset.cmd_buf
|
||||
&& (buf[0] == PROP_NCI_RSP_GID)
|
||||
&& (buf[1] == nfc_dev->cold_reset.cmd_buf[1])) {
|
||||
read_cold_reset_rsp(nfc_dev, buf);
|
||||
nfc_dev->cold_reset.rsp_pending = false;
|
||||
wake_up_interruptible(&nfc_dev->cold_reset.read_wq);
|
||||
/*
|
||||
* NFC process doesn't know about cold reset command
|
||||
* being sent as it was initiated by eSE process
|
||||
* we shouldn't return any data to NFC process
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int i2c_write(struct nfc_dev *dev, const char *buf, size_t count,
|
||||
int max_retry_cnt)
|
||||
int i2c_write(struct nfc_dev *nfc_dev, const char *buf, size_t count,
|
||||
int max_retry_cnt)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int retry_cnt;
|
||||
uint16_t i = 0;
|
||||
uint16_t disp_len = GET_IPCLOG_MAX_PKT_LEN(count);
|
||||
|
||||
if (count > MAX_DL_BUFFER_SIZE)
|
||||
count = MAX_DL_BUFFER_SIZE;
|
||||
|
||||
pr_debug("%s : writing %zu bytes.\n", __func__, count);
|
||||
|
||||
NFCLOG_IPC(dev, false, "%s sending %d B", __func__, count);
|
||||
NFCLOG_IPC(nfc_dev, false, "%s sending %d B", __func__, count);
|
||||
|
||||
for (i = 0; i < disp_len; i++)
|
||||
NFCLOG_IPC(dev, false, " %02x", buf[i]);
|
||||
NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]);
|
||||
|
||||
for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) {
|
||||
|
||||
ret = i2c_master_send(dev->i2c_dev.client, buf, count);
|
||||
NFCLOG_IPC(dev, false, "%s ret %d", __func__, ret);
|
||||
ret = i2c_master_send(nfc_dev->i2c_dev.client, buf, count);
|
||||
NFCLOG_IPC(nfc_dev, false, "%s ret %d", __func__, ret);
|
||||
if (ret <= 0) {
|
||||
pr_warn("%s: write failed, Maybe in Standby Mode - Retry(%d)\n",
|
||||
__func__, retry_cnt);
|
||||
usleep_range(1000, 1100);
|
||||
pr_warn("%s: write failed 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;
|
||||
}
|
||||
@ -126,96 +225,21 @@ int i2c_write(struct nfc_dev *dev, const char *buf, size_t count,
|
||||
ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *offset)
|
||||
{
|
||||
int ret;
|
||||
char *tmp = NULL;
|
||||
struct nfc_dev *nfc_dev = filp->private_data;
|
||||
struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev;
|
||||
|
||||
if (!nfc_dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (count > nfc_dev->kbuflen)
|
||||
count = nfc_dev->kbuflen;
|
||||
|
||||
pr_debug("%s : reading %zu bytes.\n", __func__, count);
|
||||
int ret = 0;
|
||||
struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data;
|
||||
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
pr_err(":f_flag has O_NONBLOCK. EAGAIN\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
mutex_lock(&nfc_dev->read_mutex);
|
||||
|
||||
if (!gpio_get_value(nfc_dev->gpio.irq)) {
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
pr_err(":f_falg has O_NONBLOCK. EAGAIN\n");
|
||||
ret = -EAGAIN;
|
||||
goto err;
|
||||
}
|
||||
while (1) {
|
||||
ret = 0;
|
||||
if (!i2c_dev->irq_enabled) {
|
||||
i2c_dev->irq_enabled = true;
|
||||
enable_irq(i2c_dev->client->irq);
|
||||
}
|
||||
if (!gpio_get_value(nfc_dev->gpio.irq)) {
|
||||
ret = wait_event_interruptible(nfc_dev->read_wq,
|
||||
!i2c_dev->irq_enabled);
|
||||
|
||||
if (ret) {
|
||||
pr_err("error wakeup of read wq\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
i2c_disable_irq(nfc_dev);
|
||||
|
||||
if (gpio_get_value(nfc_dev->gpio.irq))
|
||||
break;
|
||||
|
||||
if (!gpio_get_value(nfc_dev->gpio.ven)) {
|
||||
pr_info("%s: ven low in read !\n", __func__);
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
pr_warn("%s: spurious interrupt detected\n", __func__);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = nfc_dev->kbuf;
|
||||
if (!tmp) {
|
||||
pr_err("%s: device doesn't exist anymore\n", __func__);
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
memset(tmp, 0x00, count);
|
||||
|
||||
/* Read data */
|
||||
ret = i2c_read(nfc_dev, tmp, count);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: i2c_master_recv returned %d\n", __func__, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* check if it's response of cold reset command
|
||||
* NFC HAL process shouldn't receive this data as
|
||||
* command was sent by SPI driver
|
||||
*/
|
||||
if (nfc_dev->cold_reset.rsp_pending && nfc_dev->cold_reset.cmd_buf
|
||||
&& (tmp[0] == PROP_NCI_RSP_GID)
|
||||
&& (tmp[1] == nfc_dev->cold_reset.cmd_buf[1])) {
|
||||
read_cold_reset_rsp(nfc_dev, tmp);
|
||||
nfc_dev->cold_reset.rsp_pending = false;
|
||||
wake_up_interruptible(&nfc_dev->cold_reset.read_wq);
|
||||
mutex_unlock(&nfc_dev->read_mutex);
|
||||
/*
|
||||
* NFC process doesn't know about cold reset command
|
||||
* being sent as it was initiated by eSE process
|
||||
* we shouldn't return any data to NFC process
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -224,37 +248,22 @@ ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *offset)
|
||||
{
|
||||
int ret;
|
||||
char *tmp = NULL;
|
||||
struct nfc_dev *nfc_dev = filp->private_data;
|
||||
struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data;
|
||||
|
||||
if (!nfc_dev) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
if (count > MAX_DL_BUFFER_SIZE)
|
||||
count = MAX_DL_BUFFER_SIZE;
|
||||
|
||||
if (!nfc_dev)
|
||||
return -ENODEV;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (count > nfc_dev->kbuflen) {
|
||||
pr_err("%s: out of memory\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp = memdup_user(buf, count);
|
||||
if (IS_ERR(tmp)) {
|
||||
pr_err("%s: memdup_user failed\n", __func__);
|
||||
ret = PTR_ERR(tmp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = i2c_write(nfc_dev, tmp, count, NO_RETRY);
|
||||
if (ret != count) {
|
||||
pr_err("%s: failed to write %d\n", __func__, ret);
|
||||
ret = -EIO;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
out_free:
|
||||
kfree(tmp);
|
||||
out:
|
||||
ret = i2c_write(nfc_dev, nfc_dev->write_kbuf, count, NO_RETRY);
|
||||
mutex_unlock(&nfc_dev->write_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -273,14 +282,14 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
int ret = 0;
|
||||
struct nfc_dev *nfc_dev = NULL;
|
||||
struct i2c_dev *i2c_dev = NULL;
|
||||
struct platform_gpio nfc_gpio;
|
||||
struct platform_ldo nfc_ldo;
|
||||
struct platform_configs nfc_configs;
|
||||
struct platform_gpio *nfc_gpio = &nfc_configs.gpio;
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
|
||||
//retrieve details of gpios from dt
|
||||
|
||||
ret = nfc_parse_dt(&client->dev, &nfc_gpio, &nfc_ldo, PLATFORM_IF_I2C);
|
||||
ret = nfc_parse_dt(&client->dev, &nfc_configs, PLATFORM_IF_I2C);
|
||||
if (ret) {
|
||||
pr_err("%s : failed to parse dt\n", __func__);
|
||||
goto err;
|
||||
@ -296,56 +305,65 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
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_free_nfc_dev;
|
||||
}
|
||||
nfc_dev->write_kbuf = kzalloc(MAX_DL_BUFFER_SIZE, GFP_DMA | GFP_KERNEL);
|
||||
if (!nfc_dev->write_kbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_read_kbuf;
|
||||
}
|
||||
nfc_dev->interface = PLATFORM_IF_I2C;
|
||||
nfc_dev->nfc_state = NFC_STATE_NCI;
|
||||
nfc_dev->i2c_dev.client = client;
|
||||
i2c_dev = &nfc_dev->i2c_dev;
|
||||
nfc_dev->nfc_read = i2c_read;
|
||||
nfc_dev->nfc_write = i2c_write;
|
||||
nfc_dev->nfc_enable_intr = i2c_enable_irq;
|
||||
nfc_dev->nfc_disable_intr = i2c_disable_irq;
|
||||
|
||||
ret = configure_gpio(nfc_gpio.ven, GPIO_OUTPUT);
|
||||
nfc_dev->fw_major_version = 0;
|
||||
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);
|
||||
goto err_free_nfc_dev;
|
||||
__func__, nfc_gpio->ven);
|
||||
goto err_free_write_kbuf;
|
||||
}
|
||||
ret = configure_gpio(nfc_gpio.irq, GPIO_IRQ);
|
||||
ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s: unable to request nfc irq gpio [%d]\n",
|
||||
__func__, nfc_gpio.irq);
|
||||
__func__, nfc_gpio->irq);
|
||||
goto err_free_ven;
|
||||
}
|
||||
client->irq = ret;
|
||||
ret = configure_gpio(nfc_gpio.dwl_req, GPIO_OUTPUT);
|
||||
ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT);
|
||||
if (ret) {
|
||||
pr_err("%s: unable to request nfc firm downl gpio [%d]\n",
|
||||
__func__, nfc_gpio.dwl_req);
|
||||
goto err_free_irq;
|
||||
__func__, nfc_gpio->dwl_req);
|
||||
//not returning failure here as dwl gpio is a optional gpio for sn220
|
||||
}
|
||||
|
||||
ret = configure_gpio(nfc_gpio.clkreq, GPIO_INPUT);
|
||||
ret = configure_gpio(nfc_gpio->clkreq, GPIO_INPUT);
|
||||
if (ret) {
|
||||
pr_err("%s: unable to request nfc clkreq gpio [%d]\n",
|
||||
__func__, nfc_gpio.clkreq);
|
||||
__func__, nfc_gpio->clkreq);
|
||||
goto err_free_dwl_req;
|
||||
}
|
||||
|
||||
nfc_dev->gpio.ven = nfc_gpio.ven;
|
||||
nfc_dev->gpio.irq = nfc_gpio.irq;
|
||||
nfc_dev->gpio.dwl_req = nfc_gpio.dwl_req;
|
||||
nfc_dev->gpio.clkreq = nfc_gpio.clkreq;
|
||||
/*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);
|
||||
spin_lock_init(&i2c_dev->irq_enabled_lock);
|
||||
|
||||
ret = nfc_misc_probe(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT,
|
||||
ret = nfc_misc_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT,
|
||||
NFC_CHAR_DEV_NAME, CLASS_NAME);
|
||||
if (ret) {
|
||||
pr_err("%s: nfc_misc_probe failed\n", __func__);
|
||||
pr_err("%s: nfc_misc_register failed\n", __func__);
|
||||
goto err_mutex_destroy;
|
||||
}
|
||||
/* interrupt initializations */
|
||||
@ -355,7 +373,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
IRQF_TRIGGER_HIGH, client->name, nfc_dev);
|
||||
if (ret) {
|
||||
pr_err("%s: request_irq failed\n", __func__);
|
||||
goto err_nfc_misc_remove;
|
||||
goto err_nfc_misc_unregister;
|
||||
}
|
||||
i2c_disable_irq(nfc_dev);
|
||||
i2c_set_clientdata(client, nfc_dev);
|
||||
@ -367,7 +385,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
}
|
||||
|
||||
ret = nfcc_hw_check(nfc_dev);
|
||||
if (ret) {
|
||||
if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) {
|
||||
pr_err("nfc hw check failed ret %d\n", ret);
|
||||
goto err_nfcc_hw_check;
|
||||
}
|
||||
@ -386,18 +404,23 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
}
|
||||
err_ldo_config_failed:
|
||||
free_irq(client->irq, nfc_dev);
|
||||
err_nfc_misc_remove:
|
||||
nfc_misc_remove(nfc_dev, DEV_COUNT);
|
||||
err_nfc_misc_unregister:
|
||||
nfc_misc_unregister(nfc_dev, DEV_COUNT);
|
||||
err_mutex_destroy:
|
||||
mutex_destroy(&nfc_dev->dev_ref_mutex);
|
||||
mutex_destroy(&nfc_dev->read_mutex);
|
||||
gpio_free(nfc_dev->gpio.clkreq);
|
||||
mutex_destroy(&nfc_dev->write_mutex);
|
||||
gpio_free(nfc_gpio->clkreq);
|
||||
err_free_dwl_req:
|
||||
gpio_free(nfc_dev->gpio.dwl_req);
|
||||
err_free_irq:
|
||||
gpio_free(nfc_dev->gpio.irq);
|
||||
if (gpio_is_valid(nfc_gpio->dwl_req))
|
||||
gpio_free(nfc_gpio->dwl_req);
|
||||
gpio_free(nfc_gpio->irq);
|
||||
err_free_ven:
|
||||
gpio_free(nfc_dev->gpio.ven);
|
||||
gpio_free(nfc_gpio->ven);
|
||||
err_free_write_kbuf:
|
||||
kfree(nfc_dev->write_kbuf);
|
||||
err_free_read_kbuf:
|
||||
kfree(nfc_dev->read_kbuf);
|
||||
err_free_nfc_dev:
|
||||
kfree(nfc_dev);
|
||||
err:
|
||||
@ -418,7 +441,12 @@ int nfc_i2c_dev_remove(struct i2c_client *client)
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_set_value(nfc_dev->gpio.ven, 0);
|
||||
if (nfc_dev->dev_ref_count > 0) {
|
||||
pr_err("%s: device already in use\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
gpio_set_value(nfc_dev->configs.gpio.ven, 0);
|
||||
// HW dependent delay before LDO goes into LPM mode
|
||||
usleep_range(10000, 10100);
|
||||
if (nfc_dev->reg) {
|
||||
@ -428,22 +456,25 @@ int nfc_i2c_dev_remove(struct i2c_client *client)
|
||||
|
||||
device_init_wakeup(&client->dev, false);
|
||||
free_irq(client->irq, nfc_dev);
|
||||
nfc_misc_remove(nfc_dev, DEV_COUNT);
|
||||
nfc_misc_unregister(nfc_dev, DEV_COUNT);
|
||||
mutex_destroy(&nfc_dev->dev_ref_mutex);
|
||||
mutex_destroy(&nfc_dev->read_mutex);
|
||||
mutex_destroy(&nfc_dev->write_mutex);
|
||||
|
||||
if (gpio_is_valid(nfc_dev->gpio.clkreq))
|
||||
gpio_free(nfc_dev->gpio.clkreq);
|
||||
if (gpio_is_valid(nfc_dev->configs.gpio.clkreq))
|
||||
gpio_free(nfc_dev->configs.gpio.clkreq);
|
||||
|
||||
if (gpio_is_valid(nfc_dev->gpio.dwl_req))
|
||||
gpio_free(nfc_dev->gpio.dwl_req);
|
||||
if (gpio_is_valid(nfc_dev->configs.gpio.dwl_req))
|
||||
gpio_free(nfc_dev->configs.gpio.dwl_req);
|
||||
|
||||
if (gpio_is_valid(nfc_dev->gpio.irq))
|
||||
gpio_free(nfc_dev->gpio.irq);
|
||||
if (gpio_is_valid(nfc_dev->configs.gpio.irq))
|
||||
gpio_free(nfc_dev->configs.gpio.irq);
|
||||
|
||||
if (gpio_is_valid(nfc_dev->gpio.ven))
|
||||
gpio_free(nfc_dev->gpio.ven);
|
||||
if (gpio_is_valid(nfc_dev->configs.gpio.ven))
|
||||
gpio_free(nfc_dev->configs.gpio.ven);
|
||||
|
||||
kfree(nfc_dev->read_kbuf);
|
||||
kfree(nfc_dev->write_kbuf);
|
||||
kfree(nfc_dev);
|
||||
return ret;
|
||||
}
|
||||
@ -499,11 +530,11 @@ static struct i2c_driver nfc_i2c_dev_driver = {
|
||||
.probe = nfc_i2c_dev_probe,
|
||||
.remove = nfc_i2c_dev_remove,
|
||||
.driver = {
|
||||
.name = NFC_I2C_DRV_STR,
|
||||
.pm = &nfc_i2c_dev_pm_ops,
|
||||
.of_match_table = nfc_i2c_dev_match_table,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.name = NFC_I2C_DRV_STR,
|
||||
.pm = &nfc_i2c_dev_pm_ops,
|
||||
.of_match_table = nfc_i2c_dev_match_table,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table);
|
||||
|
@ -1,26 +1,43 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2019-2021 NXP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _NFC_I2C_DRV_H_
|
||||
#define _NFC_I2C_DRV_H_
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define NFC_I2C_DRV_STR "qcom,sn-nci" /*kept same as dts */
|
||||
#define NFC_I2C_DEV_ID "sn-i2c"
|
||||
#define NFC_I2C_DEV_ID "sn-i2c"
|
||||
|
||||
struct nfc_dev;
|
||||
|
||||
//Interface specific parameters
|
||||
struct i2c_dev {
|
||||
struct i2c_client *client;
|
||||
// IRQ parameters
|
||||
/*IRQ parameters */
|
||||
bool irq_enabled;
|
||||
spinlock_t irq_enabled_lock;
|
||||
// NFC_IRQ wake-up state
|
||||
/* NFC_IRQ wake-up state */
|
||||
bool irq_wake_up;
|
||||
};
|
||||
|
||||
long nfc_i2c_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg);
|
||||
int nfc_i2c_dev_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
@ -34,7 +51,7 @@ int i2c_enable_irq(struct nfc_dev *dev);
|
||||
int i2c_disable_irq(struct nfc_dev *dev);
|
||||
int i2c_write(struct nfc_dev *dev, const char *buf, size_t count,
|
||||
int max_retry_cnt);
|
||||
int i2c_read(struct nfc_dev *dev, char *buf, size_t count);
|
||||
int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout);
|
||||
|
||||
#else
|
||||
|
||||
@ -54,7 +71,7 @@ static inline int i2c_write(struct nfc_dev *dev, const char *buf,
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static inline int i2c_read(struct nfc_dev *dev, char *buf, size_t count)
|
||||
static inline int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user