nxp: Import oplus changes from CPH2723_15.0.2.501(EX01)

Change-Id: Iff8b173fccfc1465608a6ca96e00d36018fd29d3
This commit is contained in:
dianlujitao
2025-09-09 20:48:11 +08:00
committed by Bruno Martins
parent a1309047cc
commit ee4446fb99
11 changed files with 402 additions and 2 deletions

View File

@@ -19,3 +19,7 @@ nxp-nci-objs += nfc/ese_cold_reset.o \
nfc/common_qcom.o \
nfc/i2c_drv.o
#ifdef CONFIG_NXP_NFC_VBAT_MONITOR
nxp-nci-objs += nfc/nfc_vbat_monitor.o
ccflags-y += -DCONFIG_NXP_NFC_VBAT_MONITOR
#endif

View File

@@ -1 +1,2 @@
export CONFIG_NXP_NFC_I2C=m
export CONFIG_NXP_NFC_VBAT_MONITOR=m

View File

@@ -9,3 +9,4 @@
***************************************************************************/
#define CONFIG_NXP_NFC_I2C 1
#define CONFIG_NXP_NFC_VBAT_MONITOR 1

View File

@@ -23,8 +23,10 @@ def define_modules(target, variant):
"nfc/common_qcom.c",
"nfc/ese_cold_reset.c",
"nfc/i2c_drv.c",
"nfc/nfc_vbat_monitor.c",
"nfc/common.h",
"nfc/common_nxp.h",
"nfc/nfc_vbat_monitor.h",
"nfc/ese_cold_reset.h",
"nfc/i2c_drv.h"
],

View File

@@ -25,6 +25,7 @@
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/pinctrl/qcom-pinctrl.h>
#include <linux/interrupt.h>
#include "common.h"
bool secure_peripheral_not_found = true;
@@ -56,6 +57,17 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
return nfc_gpio->irq;
}
pr_info("NxpDrv: %s: irq %d\n", __func__, nfc_gpio->irq);
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
nfc_gpio->vbat_irq = -EINVAL;
nfc_gpio->vbat_irq =
of_get_named_gpio(np, DTS_NFC_VBAT_MONITOR_STR, 0);
if ((!gpio_is_valid(nfc_gpio->vbat_irq))) {
pr_err("%s: vbat_irq gpio invalid %d\n", __func__,
nfc_gpio->vbat_irq);
//return nfc_gpio->vbat_irq;
}
pr_err("%s: vbat gpio %d\n", __func__, nfc_gpio->vbat_irq);
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
}
nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0);
if ((!gpio_is_valid(nfc_gpio->ven))) {
@@ -217,6 +229,11 @@ void gpio_free_all(struct nfc_dev *nfc_dev)
if (gpio_is_valid(nfc_gpio->irq))
gpio_free(nfc_gpio->irq);
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
if (gpio_is_valid(nfc_gpio->vbat_irq))
gpio_free(nfc_gpio->vbat_irq);
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
if (gpio_is_valid(nfc_gpio->ven))
gpio_free(nfc_gpio->ven);
}

View File

@@ -32,6 +32,7 @@
#include <nfcinfo.h>
#include <sn_uapi.h>
#include "i2c_drv.h"
#include "nfc_vbat_monitor.h"
#include "ese_cold_reset.h"
#ifdef NFC_SECURE_PERIPHERAL_ENABLED
@@ -91,12 +92,16 @@
#define MAX_RETRY_COUNT (3)
#define MAX_WRITE_IRQ_COUNT (5)
#define MAX_IRQ_WAIT_TIME (90)
#define WAKEUP_SRC_TIMEOUT (100)
#define WAKEUP_SRC_TIMEOUT (500)
/* command response timeout */
#define NCI_CMD_RSP_TIMEOUT_MS (2000)
/* Time to wait for NFCC to be ready again after any change in the GPIO */
#define NFC_GPIO_SET_WAIT_TIME_US (10000)
/* #ifdef OPLUS_BUG_STABILITY */
/* #define NFC_GPIO_SET_WAIT_TIME_US (10000) */
/* #else OPLUS_BUG_STABILITY */
#define NFC_GPIO_SET_WAIT_TIME_US (20000)
/* #endif OPLUS_BUG_STABILITY */
/* Time to wait before retrying writes */
#define WRITE_RETRY_WAIT_TIME_US (3000)
/* Time to wait before retrying read for some specific usecases */
@@ -226,6 +231,9 @@ enum gpio_values {
/* NFC GPIO variables */
struct platform_gpio {
unsigned int irq;
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
unsigned int vbat_irq;
//#endif CONFIG_NXP_NFC_VBAT_MONITOR
unsigned int ven;
unsigned int clkreq;
unsigned int dwl_req;
@@ -277,6 +285,9 @@ struct nfc_dev {
};
struct platform_configs configs;
struct cold_reset cold_reset;
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
struct nfc_vbat_monitor nfc_vbat_monitor;
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
struct regulator *reg;
/* read buffer*/
@@ -331,4 +342,9 @@ int validate_nfc_state_nci(struct nfc_dev *nfc_dev);
int nfc_post_init(struct nfc_dev *nfc_dev);
int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans);
bool nfc_hw_secure_check(void);
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
int nfc_vbat_monitor_init(struct nfc_dev *nfc_dev,
struct platform_gpio *nfc_gpio,
struct i2c_client *client);
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
#endif /* _COMMON_H_ */

View File

@@ -281,6 +281,7 @@ int nfcc_hw_check(struct nfc_dev *nfc_dev)
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
/*get fw version in nci mode*/
usleep_range(NFC_GPIO_SET_WAIT_TIME_US,NFC_GPIO_SET_WAIT_TIME_US + 100);//add for Satisfy VEN spec of 15ms delay
gpio_set_ven(nfc_dev, 1);
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);

View File

@@ -63,6 +63,7 @@
#define DL_GET_SESSION_CMD_CRC_2 (0x33)
#define GET_SESSION_STS_OFF (3)
#define NFCC_SESSION_STS_CLOSED (0x0)
#define NFC_GPIO_SET_WAIT_TIME_US (20000)
/* Below offsets should be subtracted from NCI header length + payload length */

View File

@@ -48,6 +48,9 @@
#include <linux/compat.h>
#endif
#include "common.h"
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
#include "nfc_vbat_monitor.h"
//#endif CONFIG_NXP_NFC_VBAT_MONITOR
/**
* i2c_disable_irq()
@@ -152,6 +155,16 @@ int i2c_read(struct nfc_dev *nfc_dev, char *buf, size_t count, int timeout)
}
}
}
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
if (nfc_dev->nfc_vbat_monitor.vbat_monitor_status) {
pr_debug("%s: NFC recovering state\n",
__func__);
nfc_dev->nfc_vbat_monitor.vbat_monitor_status =
false;
ret = -EREMOTEIO;
goto err;
}
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
i2c_disable_irq(nfc_dev);
if (gpio_get_value(nfc_gpio->irq))
@@ -414,6 +427,13 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
pr_err("NxpDrv: %s: request_irq failed\n", __func__);
goto err_nfc_misc_unregister;
}
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
ret = nfc_vbat_monitor_init(nfc_dev, nfc_gpio, client);
if (ret) {
pr_err("%s: nfcc vbat monitor init failed, ret: %d\n", __func__, ret);
//goto err_nfc_misc_unregister;
}
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
i2c_disable_irq(nfc_dev);
ret = nfc_ldo_config(&client->dev, nfc_dev);
@@ -501,6 +521,11 @@ int nfc_i2c_dev_remove(struct i2c_client *client)
device_init_wakeup(&client->dev, false);
free_irq(client->irq, nfc_dev);
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
if (gpio_is_valid(nfc_dev->nfc_vbat_monitor.irq_num)) {
free_irq(nfc_dev->nfc_vbat_monitor.irq_num, nfc_dev);
}
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
nfc_misc_unregister(nfc_dev, DEV_COUNT);
mutex_destroy(&nfc_dev->dev_ref_mutex);
mutex_destroy(&nfc_dev->read_mutex);
@@ -532,6 +557,13 @@ int nfc_i2c_dev_suspend(struct device *device)
if (!enable_irq_wake(client->irq))
i2c_dev->irq_wake_up = true;
}
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
if (gpio_is_valid(nfc_dev->nfc_vbat_monitor.irq_num)) {
if (enable_irq_wake(nfc_dev->nfc_vbat_monitor.irq_num) != 0) {
pr_err("%s: vbat irq wake enabled failed\n", __func__);
}
}
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
pr_debug("NxpDrv: %s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up);
return 0;
}
@@ -554,6 +586,13 @@ int nfc_i2c_dev_resume(struct device *device)
if (!disable_irq_wake(client->irq))
i2c_dev->irq_wake_up = false;
}
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
if (gpio_is_valid(nfc_dev->nfc_vbat_monitor.irq_num)) {
if (disable_irq_wake(nfc_dev->nfc_vbat_monitor.irq_num) != 0) {
pr_err("%s: vbat irq wake disabled failed\n", __func__);
}
}
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */
pr_debug("NxpDrv: %s: irq_wake_up = %d", __func__, i2c_dev->irq_wake_up);
return 0;
}

View File

@@ -0,0 +1,271 @@
/******************************************************************************
* Copyright 2024 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
*
******************************************************************************/
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
#include <linux/interrupt.h>
#include <linux/delay.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif
#include "common.h"
/**
* nfc_nci_data_read - This API can be used to read nci data packet.
*
* This function is called from nfc Init.
*
* @nfc_dev: the dev structure for driver.
* @buf: to copy/get response message.
* Return: -EREMOTEIO for transcieve error
* No. of bytes read if Success(or no issue)
*/
int nfc_nci_data_read(struct nfc_dev *nfc_dev, char *buf)
{
int ret = 0;
int length_byte = 0;
unsigned char hdr_len = NCI_HDR_LEN;
ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf, hdr_len);
if (ret < 0) {
pr_err("%s: returned header error %d\n", __func__, ret);
return -EREMOTEIO;
}
length_byte = buf[NCI_PAYLOAD_LEN_IDX];
ret = i2c_master_recv(nfc_dev->i2c_dev.client, buf + hdr_len,
length_byte);
if (ret < 0) {
pr_err("%s: returned payload error %d\n", __func__, ret);
return -EREMOTEIO;
}
return (hdr_len + length_byte);
}
/**
* perform_nfcc_initialization - used to send nci cmd through i2c
*
* Reset and init commands send to recover NFC
*
* @nfc_dev: nfc device data structure
* Return: -EREMOTEIO for transcieve error
* 0 if Success(or no issue)
*/
int perform_nfcc_initialization(struct nfc_dev *nfc_dev)
{
int ret = 0;
unsigned char cmd_reset_nci[] = { 0x20, 0x00, 0x01, 0x00 };
unsigned char cmd_init_nci[] = { 0x20, 0x01, 0x02, 0x00, 0x00 };
unsigned char cmd_read_buff[MAX_NCI_BUFFER_SIZE];
gpio_set_ven(nfc_dev, 0);
gpio_set_ven(nfc_dev, 1);
do {
msleep(NFC_RST_CMD_READ_DELAY_MS);
if (nfc_dev->nfc_write(nfc_dev, cmd_reset_nci, sizeof(cmd_reset_nci),
NO_RETRY) <= 0)
break;
msleep(NFC_RST_CMD_READ_DELAY_MS);
memset(cmd_read_buff, 0x00, sizeof(cmd_read_buff));
if (nfc_nci_data_read(nfc_dev, cmd_read_buff) <= 0)
break;
msleep(NFC_RST_CMD_READ_DELAY_MS);
memset(cmd_read_buff, 0x00, sizeof(cmd_read_buff));
if (nfc_nci_data_read(nfc_dev, cmd_read_buff) <= 0)
break;
msleep(NFC_RST_CMD_READ_DELAY_MS);
if (nfc_dev->nfc_write(nfc_dev, cmd_init_nci, sizeof(cmd_init_nci),
NO_RETRY) <= 0)
break;
msleep(NFC_RST_CMD_READ_DELAY_MS);
memset(cmd_read_buff, 0x00, sizeof(cmd_read_buff));
if (nfc_nci_data_read(nfc_dev, cmd_read_buff) <= 0)
break;
if (cmd_read_buff[0] == 0x40 && cmd_read_buff[1] == 0x01 &&
cmd_read_buff[3] == 0x00)
return 0;
} while (0);
ret = -EREMOTEIO;
pr_err("%s: no response for nci cmd, ret: %d\n", __func__, ret);
return ret;
}
/**
* nfcc_vbat_recovery - To recover the nfcc from unresponse state due to low vbat.
*
* send nfcc recovery for NFC_VBAT_MONITOR_MAX_RETRY_COUNT times
*
* @nfc_dev: nfc device data structure
* Return: -EREMOTEIO for transcieve error
* 0 if Success(or no issue)
*/
int nfcc_vbat_recovery(struct nfc_dev *nfc_dev)
{
int ret = -EREMOTEIO;
unsigned char retrycount = 0;
do {
msleep(NFC_RESET_RETRY_DELAY_MS);
ret = perform_nfcc_initialization(nfc_dev);
if (ret == 0) {
pr_err("%s: nfcc recovery is success and vbat irq enabled\n",
__func__);
break;
}
pr_err("%s: recovering from vbat trigger, count: %d ret: %d\n",
__func__, retrycount, ret);
retrycount++;
} while (retrycount < NFC_VBAT_MONITOR_MAX_RETRY_COUNT);
return ret;
}
/**
* nfc_vbat_monitor_irq_handler - Handler function for vbat interrupt
*
* Initialises workqueue after disabling interrupt if present
*
* @irq: interrupt
* @dev_id: nfc device pointer
* Return: Status of type irqreturn_t
*/
irqreturn_t nfc_vbat_monitor_irq_handler(int irq, void *dev_id)
{
unsigned long flags;
struct nfc_dev *nfc_dev = dev_id;
spin_lock_irqsave(
&nfc_dev->nfc_vbat_monitor.nfc_vbat_monitor_enabled_lock,
flags);
disable_irq_nosync(nfc_dev->nfc_vbat_monitor.irq_num);
if (!queue_work(nfc_dev->nfc_vbat_monitor.wq,
&nfc_dev->nfc_vbat_monitor.work))
pr_err("%s: queue_work success\n", __func__);
spin_unlock_irqrestore(
&nfc_dev->nfc_vbat_monitor.nfc_vbat_monitor_enabled_lock,
flags);
return IRQ_HANDLED;
}
/**
* nfc_vbat_monitor_workqueue_handler - Handler for workqueue of vbat interrupt
*
* Enables interrupt workqueue and initialises recovery of nfcc
*
* @work: workqueue structure
*/
static void nfc_vbat_monitor_workqueue_handler(struct work_struct *work)
{
int ret = 0;
struct nfc_vbat_monitor *nfc_vbat_monitor =
container_of(work, struct nfc_vbat_monitor, work);
struct nfc_dev *nfc_dev = container_of(nfc_vbat_monitor, struct nfc_dev,
nfc_vbat_monitor);
pr_err("%s: read pending status flag: %d\n", __func__,
nfc_dev->cold_reset.is_nfc_read_pending);
nfc_dev->nfc_disable_intr(nfc_dev);
mutex_lock(&nfc_dev->write_mutex);
ret = nfcc_vbat_recovery(nfc_dev);
if (ret == 0)
enable_irq(nfc_dev->nfc_vbat_monitor.irq_num);
if (nfc_dev->cold_reset.is_nfc_read_pending == false) {
if (ret != 0) {
pr_err("%s nfcc recovery failed, enabling irq",
__func__);
enable_irq(nfc_dev->nfc_vbat_monitor.irq_num);
}
} else {
nfc_dev->nfc_vbat_monitor.vbat_monitor_status = true;
wake_up(&nfc_dev->read_wq);
}
mutex_unlock(&nfc_dev->write_mutex);
}
/**
* nfc_vbat_monitor_init_workqueue - Workqueue initialiser for vbat interrupt
*
* Allocates workqueue and intiialises it
*
* @nfc_vbat_monitor: nfc_vbat_monitor structure of platform for nfc
* Return: 0 if Success
*/
int nfc_vbat_monitor_init_workqueue(struct nfc_vbat_monitor *nfc_vbat_monitor)
{
nfc_vbat_monitor->wq =
alloc_workqueue(NFC_VBAT_MONITOR_WORKQUEUE_NAME, 0, 0);
if (!nfc_vbat_monitor->wq)
pr_err("%s: failed to allocate workqueue\n", __func__);
INIT_WORK(&nfc_vbat_monitor->work, nfc_vbat_monitor_workqueue_handler);
pr_debug("%s: allocated workqueue\n", __func__);
return 0;
}
/**
* nfc_vbat_monitor_init - interrupt initialization for vbat handling
*
* Configures vbat gpio and assigns an interrupt number, calls for
* workqueue intialization
*
* @nfc_dev: nfc device data structure
* @nfc_gpio: platform gpio structure
* @client: i2c client
* Return: -1 if initialization failed
* 0 if Success(or no issue)
*/
int nfc_vbat_monitor_init(struct nfc_dev *nfc_dev,
struct platform_gpio *nfc_gpio,
struct i2c_client *client)
{
int ret = -1;
do {
ret = configure_gpio(nfc_gpio->vbat_irq, GPIO_IRQ);
if (ret <= 0) {
pr_err("%s: unable to request nfc vbat gpio [%d]\n", __func__,
nfc_gpio->vbat_irq);
break;
}
nfc_dev->nfc_vbat_monitor.irq_num = ret;
/* init mutex and queues */
spin_lock_init(
&nfc_dev->nfc_vbat_monitor.nfc_vbat_monitor_enabled_lock);
nfc_dev->nfc_vbat_monitor.vbat_monitor_status = false;
ret = request_irq(nfc_dev->nfc_vbat_monitor.irq_num,
nfc_vbat_monitor_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
nfc_dev->i2c_dev.client->name, nfc_dev);
if (ret) {
pr_err("%s: irq request failed\n", __func__);
break;
}
ret = nfc_vbat_monitor_init_workqueue(&nfc_dev->nfc_vbat_monitor);
if (ret) {
pr_err("%s: nfc_gpio workqueue init failed\n", __func__);
break;
}
return 0;
} while (0);
pr_err("%s: vbat monitor initialization failed, ret:%d\n", __func__, ret);
return ret;
}
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */

View File

@@ -0,0 +1,47 @@
/******************************************************************************
* Copyright 2024 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
*
******************************************************************************/
//#if IS_ENABLED(CONFIG_NXP_NFC_VBAT_MONITOR)
#ifndef _NFC_VBAT_MONITOR_H_
#define _NFC_VBAT_MONITOR_H_
#include <linux/cdev.h>
#define NXP_NFC_VBAT_MONITOR
#define NFC_VBAT_MONITOR_MAX_RETRY_COUNT (3)
#define NFC_RESET_RETRY_DELAY_MS (500)
#define NFC_RST_CMD_READ_DELAY_MS (50)
#define NFC_VBAT_MONITOR_WORKQUEUE_NAME "nfc_vbat_monitor_workq"
#define DTS_NFC_VBAT_MONITOR_STR "nxp,sn-vbat"
/* vbat monitoring specific parameters*/
struct nfc_vbat_monitor {
spinlock_t nfc_vbat_monitor_enabled_lock;
struct workqueue_struct *wq;
struct work_struct work;
int irq_num;
bool vbat_monitor_status;
};
/* vbat monitoring handling and workqueue functions*/
irqreturn_t nfc_vbat_monitor_irq_handler(int irq, void *dev_id);
int nfc_vbat_monitor_init_workqueue(struct nfc_vbat_monitor *nfc_vbat_monitor);
#endif /* _NFC_VBAT_MONITOR_H_ */
//#endif /* CONFIG_NXP_NFC_VBAT_MONITOR */