Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f984fe46 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "NFC: Add NFC I2C and I3C drivers for SNxxx"

parents 7effb8fd c872c472
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -60,3 +60,21 @@ source "drivers/nfc/nxp-nci/Kconfig"
source "drivers/nfc/s3fwrn5/Kconfig"
source "drivers/nfc/st95hf/Kconfig"
endmenu

config NFC_QTI_I2C
	tristate "QTI NCI based NFC I2C Slave Driver for SNxxx"
	depends on I2C
	help
	  This enables the NFC driver for SNxxx based devices.
	  This is for I2C connected version. NCI protocol logic
	  resides in the usermode and it has no other NFC dependencies.

	  If unsure, say N.

config NFC_QTI_I3C
	tristate "QTI NCI based NFC I3C Slave Driver for SNxxx"
	depends on I3C
	help
	  This enables the NFC driver for SNxxx based devices.
	  This is for I3C connected version. NCI protocol logic
	  resides in the usermode and it has no other NFC dependencies.
+1 −0
Original line number Diff line number Diff line
@@ -17,3 +17,4 @@ obj-$(CONFIG_NFC_ST_NCI) += st-nci/
obj-$(CONFIG_NFC_NXP_NCI)	+= nxp-nci/
obj-$(CONFIG_NFC_S3FWRN5)	+= s3fwrn5/
obj-$(CONFIG_NFC_ST95HF)	+= st95hf/
obj-y				+= qti/
+10 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for qti nfc drivers
#

obj-$(CONFIG_NFC_QTI_I2C)	+= nfc_i2c_drv.o
nfc_i2c_drv-objs:= nfc_common.o nfc_i2c_drv.o

obj-$(CONFIG_NFC_QTI_I3C)	+= nfc_i3c_drv.o
nfc_i3c_drv-objs:= nfc_common.o nfc_i3c_drv.o
+602 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 */

#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,
		 uint8_t interface)
{
	struct device_node *np = dev->of_node;

	if (!np) {
		pr_err("nfc of_node NULL\n");
		return -EINVAL;
	}

	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))) {
			pr_err("nfc irq gpio invalid %d\n", nfc_gpio->irq);
			return -EINVAL;
		}
		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);
		return -EINVAL;
	}

	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;
	}

	nfc_gpio->clkreq = of_get_named_gpio(np, DTS_CLKREQ_GPIO_STR, 0);
	if (!gpio_is_valid(nfc_gpio->clkreq)) {
		dev_err(dev, "clkreq gpio invalid %d\n", nfc_gpio->dwl_req);
		return -EINVAL;
	}

	pr_info("%s: ven %d, dwl req %d, clkreq %d\n", __func__,
		nfc_gpio->ven, nfc_gpio->dwl_req, nfc_gpio->clkreq);

	return 0;
}
EXPORT_SYMBOL(nfc_parse_dt);

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);
	}
}

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");
		if (ret) {
			pr_err("%s: unable to request nfc gpio [%d]\n",
			       __func__, gpio);
			return ret;
		}
		// set direction and value for output pin
		if (flag & GPIO_OUTPUT)
			ret = gpio_direction_output(gpio, (GPIO_HIGH & flag));
		else
			ret = gpio_direction_input(gpio);

		if (ret) {
			pr_err
			    ("%s: unable to set direction for nfc gpio [%d]\n",
			     __func__, gpio);
			gpio_free(gpio);
			return ret;
		}
		// Consider value as control for input IRQ pin
		if (flag & GPIO_IRQ) {
			ret = gpio_to_irq(gpio);
			if (ret < 0) {
				pr_err("%s: unable to set irq for nfc gpio [%d]\n",
				     __func__, gpio);
				gpio_free(gpio);
				return ret;
			}
			pr_debug
			    ("%s: gpio_to_irq successful [%d]\n",
			     __func__, gpio);
			return ret;
		}
	} else {
		pr_err("%s: invalid gpio\n", __func__);
		ret = -EINVAL;
	}
	return ret;
}
EXPORT_SYMBOL(configure_gpio);

void nfc_misc_remove(struct nfc_dev *nfc_dev, int count)
{
	pr_debug("%s: entry\n", __func__);

	kfree(nfc_dev->kbuf);
	device_destroy(nfc_dev->nfc_class, nfc_dev->devno);
	cdev_del(&nfc_dev->c_dev);
	class_destroy(nfc_dev->nfc_class);
	unregister_chrdev_region(nfc_dev->devno, count);
}
EXPORT_SYMBOL(nfc_misc_remove);

int nfc_misc_probe(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);
		return ret;
	}
	nfc_dev->nfc_class = class_create(THIS_MODULE, classname);
	if (IS_ERR(nfc_dev->nfc_class)) {
		ret = PTR_ERR(nfc_dev->nfc_class);
		pr_err("%s: failed to register device class ret %d\n",
			__func__, ret);
		unregister_chrdev_region(nfc_dev->devno, count);
		return ret;
	}
	cdev_init(&nfc_dev->c_dev, nfc_fops);
	ret = cdev_add(&nfc_dev->c_dev, nfc_dev->devno, count);
	if (ret < 0) {
		pr_err("%s: failed to add cdev ret %d\n", __func__, ret);
		class_destroy(nfc_dev->nfc_class);
		unregister_chrdev_region(nfc_dev->devno, count);
		return ret;
	}
	nfc_dev->nfc_device = device_create(nfc_dev->nfc_class, NULL,
					    nfc_dev->devno, nfc_dev, devname);
	if (IS_ERR(nfc_dev->nfc_device)) {
		ret = PTR_ERR(nfc_dev->nfc_device);
		pr_err("%s: failed to create the device ret %d\n",
			__func__, ret);
		cdev_del(&nfc_dev->c_dev);
		class_destroy(nfc_dev->nfc_class);
		unregister_chrdev_region(nfc_dev->devno, count);
		return ret;
	}

	nfc_dev->kbuflen = MAX_BUFFER_SIZE;
	nfc_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
	if (!nfc_dev->kbuf)
		return -ENOMEM;

	nfc_dev->cold_reset.rsp_pending = false;
	nfc_dev->cold_reset.is_nfc_enabled = false;
	init_waitqueue_head(&nfc_dev->cold_reset.read_wq);

	return 0;
}
EXPORT_SYMBOL(nfc_misc_probe);

static void enable_interrupt(struct nfc_dev *nfc_dev)
{
	if (nfc_dev->interface == PLATFORM_IF_I2C)
		i2c_enable_irq(&nfc_dev->i2c_dev);
	else
		i3c_enable_ibi(&nfc_dev->i3c_dev);
}

static void disable_interrupt(struct nfc_dev *nfc_dev)
{
	if (nfc_dev->interface == PLATFORM_IF_I2C)
		i2c_disable_irq(&nfc_dev->i2c_dev);
	else
		i3c_disable_ibi(&nfc_dev->i3c_dev);
}

static int send_cold_reset_cmd(struct nfc_dev *nfc_dev)
{
	int ret = 0;
	char *cold_reset_cmd = NULL;

	cold_reset_cmd = kzalloc(COLD_RESET_CMD_LEN, GFP_DMA | GFP_KERNEL);
	if (!cold_reset_cmd)
		return -ENOMEM;

	if (gpio_get_value(nfc_dev->gpio.dwl_req)) {
		pr_err("FW download in-progress\n");
		ret = -EBUSY;
		goto error;
	}
	if (!gpio_get_value(nfc_dev->gpio.ven)) {
		pr_err("VEN LOW - NFCC powered off\n");
		ret = -ENODEV;
		goto error;
	}

	cold_reset_cmd[0] = COLD_RESET_CMD_GID;
	cold_reset_cmd[1] = COLD_RESET_OID;
	cold_reset_cmd[2] = COLD_RESET_CMD_PAYLOAD_LEN;

	if (nfc_dev->interface == PLATFORM_IF_I2C)
		ret = i2c_write(&nfc_dev->i2c_dev, cold_reset_cmd,
			      COLD_RESET_CMD_LEN, MAX_RETRY_COUNT);
	else
		ret = i3c_write(&nfc_dev->i3c_dev, cold_reset_cmd,
			      COLD_RESET_CMD_LEN, MAX_RETRY_COUNT);

	if (ret <= 0)
		pr_err("%s: write failed after max retry, ret %d\n",
			__func__, ret);

error:
	kfree(cold_reset_cmd);
	return ret;
}

void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header)
{
	int ret = -1;
	char *cold_reset_rsp = NULL;
	struct cold_reset *cold_reset = &nfc_dev->cold_reset;

	cold_reset_rsp = kzalloc(COLD_RESET_RSP_LEN, GFP_DMA | GFP_KERNEL);
	if (!cold_reset_rsp)
		return;

	/*
	 * read header also if NFC is disabled
	 * for enable case, will be taken care by nfc read thread
	 */
	if ((!cold_reset->is_nfc_enabled) &&
		(nfc_dev->interface == PLATFORM_IF_I2C)) {

		ret = i2c_read(&nfc_dev->i2c_dev, cold_reset_rsp,
							NCI_HDR_LEN);
		if (ret <= 0) {
			pr_err("%s: failure to read cold reset rsp header\n",
			       __func__);
			goto error;
		}
	} else {

		/* For I3C driver, header is read by the worker thread */
		memcpy(cold_reset_rsp, header, NCI_HDR_LEN);
	}
	if ((cold_reset_rsp[0] != COLD_RESET_RSP_GID)
	    || (cold_reset_rsp[1] != COLD_RESET_OID)) {
		pr_err("%s: - invalid response GID or OID for cold_reset\n",
		       __func__);
		ret = -EINVAL;
		goto error;
	}
	if ((NCI_HDR_LEN + cold_reset_rsp[2]) > COLD_RESET_RSP_LEN) {
		pr_err("%s: - invalid response for cold_reset\n", __func__);
		ret = -EINVAL;
		goto error;
	}
	if (nfc_dev->interface == PLATFORM_IF_I2C)
		ret = i2c_read(&nfc_dev->i2c_dev,
			     &cold_reset_rsp[NCI_PAYLOAD_IDX],
			     cold_reset_rsp[2]);
	else
		ret = i3c_read(&nfc_dev->i3c_dev,
			     &cold_reset_rsp[NCI_PAYLOAD_IDX],
			     cold_reset_rsp[2]);

	if (ret <= 0) {
		pr_err("%s: failure to read cold reset rsp payload\n",
			__func__);
		goto error;
	}
	cold_reset->status = cold_reset_rsp[NCI_PAYLOAD_IDX];

error:
	kfree(cold_reset_rsp);
}
EXPORT_SYMBOL(read_cold_reset_rsp);

/*
 * Power management of the eSE
 * eSE and NFCC both are powered using VEN gpio,
 * VEN HIGH - eSE and NFCC both are powered on
 * VEN LOW - eSE and NFCC both are power down
 */
int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
{
	int ret = 0;

	if (arg == ESE_POWER_ON) {
		/*
		 * Let's store the NFC VEN pin state
		 * will check stored value in case of eSE power off request,
		 * to find out if NFC MW also sent request to set VEN HIGH
		 * 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);
		if (!nfc_dev->nfc_ven_enabled) {
			pr_debug("eSE HAL service setting ven HIGH\n");
			gpio_set_ven(nfc_dev, 1);
		} else {
			pr_debug("ven already HIGH\n");
		}
	} else if (arg == ESE_POWER_OFF) {
		if (!nfc_dev->nfc_ven_enabled) {
			pr_debug("NFC not enabled, disabling ven\n");
			gpio_set_ven(nfc_dev, 0);
		} else {
			pr_debug("keep ven high as NFC is enabled\n");
		}
	} else if (arg == ESE_COLD_RESET) {

		// set default value for status as failure
		nfc_dev->cold_reset.status = -EIO;

		ret = send_cold_reset_cmd(nfc_dev);
		if (ret <= 0) {
			pr_err("failed to send cold reset command\n");
			return nfc_dev->cold_reset.status;
		}

		nfc_dev->cold_reset.rsp_pending = true;

		// check if NFC is enabled
		if (nfc_dev->cold_reset.is_nfc_enabled) {

			/*
			 * nfc_read thread will initiate cold reset response
			 * and it will signal for data available
			 */
			wait_event_interruptible(nfc_dev->cold_reset.read_wq,
				!nfc_dev->cold_reset.rsp_pending);

		} else {

			// Read data as NFC thread is not active

			enable_interrupt(nfc_dev);

			if (nfc_dev->interface == PLATFORM_IF_I2C) {
				ret = wait_event_interruptible_timeout(
					nfc_dev->read_wq,
					!nfc_dev->i2c_dev.irq_enabled,
					msecs_to_jiffies(MAX_IRQ_WAIT_TIME));
				if (ret <= 0) {
					disable_interrupt(nfc_dev);
					nfc_dev->cold_reset.rsp_pending = false;
					return nfc_dev->cold_reset.status;
				}
				read_cold_reset_rsp(nfc_dev, NULL);
				nfc_dev->cold_reset.rsp_pending = false;
			} else {
				wait_event_interruptible(
					nfc_dev->cold_reset.read_wq,
					!nfc_dev->cold_reset.rsp_pending);
				disable_interrupt(nfc_dev);
			}
		}

		ret = nfc_dev->cold_reset.status;

	} else if (arg == ESE_POWER_STATE) {
		// eSE power state
		ret = gpio_get_value(nfc_dev->gpio.ven);
	} else {
		pr_err("%s bad arg %lu\n", __func__, arg);
		ret = -ENOIOCTLCMD;
	}
	return ret;
}
EXPORT_SYMBOL(nfc_ese_pwr);

/*
 * nfc_ioctl_power_states() - power control
 * @nfc_dev:    nfc device data structure
 * @arg:    mode that we want to move to
 *
 * Device power control. Depending on the arg value, device moves to
 * different states, refer nfcc_ioctl_request in nfc_common.h for args
 *
 * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case
 */
static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg)
{
	int ret = 0;

	if (arg == NFC_POWER_OFF) {
		/*
		 * We are attempting a hardware reset so let us disable
		 * interrupts to avoid spurious notifications to upper
		 * layers.
		 */
		disable_interrupt(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");
		gpio_set_ven(nfc_dev, 0);

		nfc_dev->nfc_ven_enabled = false;

	} else if (arg == NFC_POWER_ON) {
		enable_interrupt(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);
		}
		gpio_set_ven(nfc_dev, 1);
		nfc_dev->nfc_ven_enabled = true;

		if (nfc_dev->interface == PLATFORM_IF_I3C)
			nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN;

	} else if (arg == NFC_FW_DWL_VEN_TOGGLE) {
		/*
		 * We are switching to download Mode, toggle the enable pin
		 * in order to set the NFCC in the new mode
		 */

		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);
		}

	} 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");

	} else if (arg == NFC_VEN_FORCED_HARD_RESET
		   && nfc_dev->interface == PLATFORM_IF_I2C) {
		/*
		 * TODO: Enable Ven reset for I3C, after hot join integration
		 */

		gpio_set_value(nfc_dev->gpio.ven, 0);
		usleep_range(10000, 10100);
		gpio_set_value(nfc_dev->gpio.ven, 1);
		usleep_range(10000, 10100);
		pr_info("%s VEN forced reset done\n", __func__);

	} else if (arg == NFC_FW_DWL_LOW) {
		/*
		 * Setting firmware download gpio to LOW
		 * FW download finished
		 */
		pr_debug("set fw gpio LOW\n");
		gpio_set_value(nfc_dev->gpio.dwl_req, 0);
		usleep_range(10000, 10100);

		if (nfc_dev->interface == PLATFORM_IF_I3C)
			nfc_dev->i3c_dev.read_hdr = NCI_HDR_LEN;

	} else if (arg == NFC_FW_HDR_LEN) {
		if (nfc_dev->interface == PLATFORM_IF_I3C)
			nfc_dev->i3c_dev.read_hdr = FW_HDR_LEN;
	} else if (arg == NFC_ENABLE) {
		/*
		 * Setting flag true when NFC is enabled
		 */
		nfc_dev->cold_reset.is_nfc_enabled = true;
	} else if (arg == NFC_DISABLE) {
		/*
		 * Setting flag true when NFC is disabled
		 */
		nfc_dev->cold_reset.is_nfc_enabled = false;
	}  else {
		pr_err("%s bad arg %lu\n", __func__, arg);
		ret = -ENOIOCTLCMD;
	}
	return ret;
}

/** @brief   IOCTL function  to be used to set or get data from upper layer.
 *
 *  @param   pfile  fil node for opened device.
 *  @cmd     IOCTL type from upper layer.
 *  @arg     IOCTL arg from upper layer.
 *
 *  @return 0 on success, error code for failures.
 */
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;

	pr_debug("%s cmd = %x arg = %zx\n", __func__, cmd, arg);

	switch (cmd) {
	case NFC_SET_PWR:
		ret = nfc_ioctl_power_states(nfc_dev, arg);
		break;
	case ESE_SET_PWR:
		ret = nfc_ese_pwr(nfc_dev, arg);
		break;
	case ESE_GET_PWR:
		ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE);
		break;
	default:
		pr_err("%s bad cmd %lu\n", __func__, arg);
		ret = -ENOIOCTLCMD;
	}
	return ret;
}
EXPORT_SYMBOL(nfc_dev_ioctl);

int nfc_dev_open(struct inode *inode, struct file *filp)
{
	struct nfc_dev *nfc_dev = container_of(inode->i_cdev,
					struct nfc_dev, c_dev);

	if (!nfc_dev)
		return -ENODEV;

	pr_debug("%s: %d, %d\n", __func__, imajor(inode), iminor(inode));

	mutex_lock(&nfc_dev->dev_ref_mutex);

	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);
		}
		enable_interrupt(nfc_dev);
	}
	nfc_dev->dev_ref_count = nfc_dev->dev_ref_count + 1;

	mutex_unlock(&nfc_dev->dev_ref_mutex);

	return 0;
}
EXPORT_SYMBOL(nfc_dev_open);

int nfc_dev_close(struct inode *inode, struct file *filp)
{
	struct nfc_dev *nfc_dev = container_of(inode->i_cdev,
					struct nfc_dev, c_dev);

	if (!nfc_dev)
		return -ENODEV;

	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) {

		disable_interrupt(nfc_dev);

		if (gpio_is_valid(nfc_dev->gpio.dwl_req)) {
			gpio_set_value(nfc_dev->gpio.dwl_req, 0);
			usleep_range(10000, 10100);
		}
	}

	if (nfc_dev->dev_ref_count > 0)
		nfc_dev->dev_ref_count = nfc_dev->dev_ref_count - 1;

	filp->private_data = NULL;

	mutex_unlock(&nfc_dev->dev_ref_mutex);

	return 0;
}
EXPORT_SYMBOL(nfc_dev_close);
+193 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 */

#ifndef _NFC_COMMON_H_
#define _NFC_COMMON_H_

#include <linux/types.h>
#include <linux/version.h>
#include <linux/semaphore.h>
#include <linux/completion.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

#include "nfc_i2c_drv.h"
#include "nfc_i3c_drv.h"

// Max device count for this driver
#define DEV_COUNT            1

// NFC device class
#define CLASS_NAME           "nfc"

//  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 COLD_RESET_CMD_LEN		3
#define COLD_RESET_RSP_LEN		4
#define COLD_RESET_CMD_GID		0x2F
#define COLD_RESET_CMD_PAYLOAD_LEN	0x00
#define COLD_RESET_RSP_GID		0x4F
#define COLD_RESET_OID			0x1E

#define MAX_NCI_PAYLOAD_LEN		(255)
#define MAX_BUFFER_SIZE			(NCI_HDR_LEN + MAX_NCI_PAYLOAD_LEN)

// Maximum retry count for standby writes
#define MAX_RETRY_COUNT			(3)

// Retry count for normal write
#define NO_RETRY				(1)
#define MAX_IRQ_WAIT_TIME		(90)
#define WAKEUP_SRC_TIMEOUT		(2000)

#define NFC_MAGIC 0xE9

// Ioctls
// The type should be aligned with MW HAL definitions

#define NFC_SET_PWR		_IOW(NFC_MAGIC, 0x01, unsigned int)
#define ESE_SET_PWR		_IOW(NFC_MAGIC, 0x02, unsigned int)
#define ESE_GET_PWR		_IOR(NFC_MAGIC, 0x03, unsigned int)

#define DTS_IRQ_GPIO_STR	"qcom,sn-irq"
#define DTS_VEN_GPIO_STR	"qcom,sn-ven"
#define DTS_FWDN_GPIO_STR	"qcom,sn-firm"
#define DTS_CLKREQ_GPIO_STR	"qcom,sn-clkreq"
#define DTS_CLKSRC_GPIO_STR	"qcom,clk-src"

enum ese_ioctl_request {
	/* eSE POWER ON */
	ESE_POWER_ON = 0,
	/* eSE POWER OFF */
	ESE_POWER_OFF,
	/* eSE COLD RESET */
	ESE_COLD_RESET,
	/* eSE POWER STATE */
	ESE_POWER_STATE
};

enum nfcc_ioctl_request {
	/* NFC disable request with VEN LOW */
	NFC_POWER_OFF = 0,
	/* NFC enable request with VEN Toggle */
	NFC_POWER_ON,
	/* firmware download request with VEN Toggle */
	NFC_FW_DWL_VEN_TOGGLE,
	/* ISO reset request */
	NFC_ISO_RESET,
	/* request for firmware download gpio HIGH */
	NFC_FW_DWL_HIGH,
	/* VEN hard reset request */
	NFC_VEN_FORCED_HARD_RESET,
	/* request for firmware download gpio LOW */
	NFC_FW_DWL_LOW,
	/* NFC enable without VEN gpio modification */
	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*/
enum interface_flags {
	/*I2C physical IF for NFCC */
	PLATFORM_IF_I2C = 0,
	/*I3C physical IF for NFCC */
	PLATFORM_IF_I3C,
};

/*
 * 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,
	PM_STATE_IBI_BEFORE_RESUME,
};

/* Enum for GPIO values*/
enum gpio_values {
	GPIO_INPUT = 0x0,
	GPIO_OUTPUT = 0x1,
	GPIO_HIGH = 0x2,
	GPIO_OUTPUT_HIGH = 0x3,
	GPIO_IRQ = 0x4,
};

// NFC GPIO variables
struct platform_gpio {
	unsigned int irq;
	unsigned int ven;
	unsigned int clkreq;
	unsigned int dwl_req;
};

//Features specific Parameters
struct cold_reset {
	wait_queue_head_t read_wq;
	bool rsp_pending;
	uint8_t status;
	/* Is NFC enabled from UI */
	bool is_nfc_enabled;
};

/* Device specific structure */
struct nfc_dev {
	wait_queue_head_t read_wq;
	struct mutex read_mutex;
	struct mutex dev_ref_mutex;
	unsigned int dev_ref_count;
	struct class *nfc_class;
	struct device *nfc_device;
	struct cdev c_dev;
	dev_t devno;
	/* Interface flag */
	uint8_t interface;
	/* NFC VEN pin state */
	bool nfc_ven_enabled;
	union {
		struct i2c_dev i2c_dev;
		struct i3c_dev i3c_dev;
	};
	struct platform_gpio gpio;
	struct cold_reset cold_reset;

	/* read buffer*/
	size_t kbuflen;
	u8 *kbuf;
};

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,
		 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 configure_gpio(unsigned int gpio, int flag);
void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header);
void gpio_set_ven(struct nfc_dev *nfc_dev, int value);

#endif //_NFC_COMMON_H_
Loading