소스 검색

NFC: FR72092, To move NFC module to vendor techpackage

As a part FR72092 requirement, moved the NFC driver
module out of kernel tree to be compiled as vendor techpackage.

Change-Id: I177d81782a7059bf6b9b4556b384737708c43348
Tapas Dey 3 년 전
부모
커밋
e89ae5f94a
16개의 변경된 파일2470개의 추가작업 그리고 0개의 파일을 삭제
  1. 7 0
      Android.bp
  2. 14 0
      Android.mk
  3. 15 0
      Kbuild
  4. 10 0
      Kconfig
  5. 14 0
      Makefile
  6. 1 0
      config/gki_nfc.conf
  7. 6 0
      config/gki_nfc_conf.h
  8. 26 0
      include/uapi/linux/nfc/nfcinfo.h
  9. 4 0
      nfc_kernel_dlkm_vendor_board.mk
  10. 1 0
      nfc_kernel_dlkm_vendor_product.mk
  11. 336 0
      qti/ese_cold_reset.c
  12. 81 0
      qti/ese_cold_reset.h
  13. 951 0
      qti/nfc_common.c
  14. 346 0
      qti/nfc_common.h
  15. 577 0
      qti/nfc_i2c_drv.c
  16. 81 0
      qti/nfc_i2c_drv.h

+ 7 - 0
Android.bp

@@ -0,0 +1,7 @@
+cc_library_headers {
+    name: "qti_nfc_kernel_headers",
+    export_include_dirs: [
+        "include/uapi/linux/nfc",
+    ],
+    vendor_available: true,
+}

+ 14 - 0
Android.mk

@@ -0,0 +1,14 @@
+# Android makefile for nfc kernel modules
+
+# Path to DLKM make scripts
+DLKM_DIR          :=  $(TOP)/device/qcom/common/dlkm
+
+LOCAL_PATH        := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE      := nfc_i2c.ko
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+LOCAL_SRC_FILES   := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*)
+
+include $(DLKM_DIR)/Build_external_kernelmodule.mk

+ 15 - 0
Kbuild

@@ -0,0 +1,15 @@
+#Makefile for qti nfc drivers
+
+include $(NFC_ROOT)/config/gki_nfc.conf
+
+LINUXINCLUDE    += -I$(NFC_ROOT)/include/uapi/linux/nfc
+
+LINUXINCLUDE   += -include $(NFC_ROOT)/config/gki_nfc_conf.h
+
+obj-$(CONFIG_NFC_QTI_I2C) += nfc_i2c.o
+
+#source files
+nfc_i2c-objs += qti/ese_cold_reset.o \
+                qti/nfc_common.o \
+                qti/nfc_i2c_drv.o
+

+ 10 - 0
Kconfig

@@ -0,0 +1,10 @@
+menuconfig 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.
+

+ 14 - 0
Makefile

@@ -0,0 +1,14 @@
+KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
+
+M ?= $(shell pwd)
+
+KBUILD_OPTIONS+= NFC_ROOT=$(KERNEL_SRC)/$(M)
+
+all:
+	$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
+
+modules_install:
+	$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
+
+clean:
+	$(MAKE) -C $(KERNEL_SRC) M=$(M) clean

+ 1 - 0
config/gki_nfc.conf

@@ -0,0 +1 @@
+export CONFIG_NFC_QTI_I2C=m

+ 6 - 0
config/gki_nfc_conf.h

@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ */
+
+#define CONFIG_NFC_QTI_I2C 1

+ 26 - 0
include/uapi/linux/nfc/nfcinfo.h

@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _UAPI_NFCINFO_H_
+#define _UAPI_NFCINFO_H_
+
+#include <linux/ioctl.h>
+
+#define NFCC_MAGIC 0xE9
+#define NFCC_GET_INFO _IOW(NFCC_MAGIC, 0x09, unsigned int)
+
+struct nqx_devinfo {
+	unsigned char chip_type;
+	unsigned char rom_version;
+	unsigned char fw_major;
+	unsigned char fw_minor;
+};
+
+union nqx_uinfo {
+	unsigned int i;
+	struct nqx_devinfo info;
+};
+
+#endif

+ 4 - 0
nfc_kernel_dlkm_vendor_board.mk

@@ -0,0 +1,4 @@
+# Build NFC kernel driver
+ifeq ($(call is-board-platform-in-list, kalama),true)
+BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/nfc_i2c.ko
+endif

+ 1 - 0
nfc_kernel_dlkm_vendor_product.mk

@@ -0,0 +1 @@
+PRODUCT_PACKAGES += nfc_i2c.ko

+ 336 - 0
qti/ese_cold_reset.c

@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/uaccess.h>
+#include "nfc_common.h"
+
+/**
+ * send_ese_cmd() - Send eSE command to NFC controller.
+ * @nfc_dev: NFC device handle.
+ *
+ * Return: 0 on pass and negative value on failure.
+ */
+static int send_ese_cmd(struct nfc_dev *nfc_dev)
+{
+	int ret;
+
+	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->configs.gpio.ven)) {
+		dev_err(nfc_dev->nfc_device,
+				"cannot send ese cmd as NFCC powered off\n");
+		return -ENODEV;
+	}
+
+	ret = nfc_dev->nfc_write(nfc_dev, nfc_dev->cold_reset.cmd_buf,
+						nfc_dev->cold_reset.cmd_len,
+						MAX_RETRY_COUNT);
+	if (ret <= 0)
+		dev_err(nfc_dev->nfc_device,
+				"%s: write failed after max retry, ret %d\n",
+							__func__, ret);
+
+	return ret;
+}
+
+/**
+ * read_cold_reset_rsp() - Read response of the cold reset command.
+ * @nfc_dev: NFC device handle.
+ * @header:  Pointer to NCI header if it is already read.
+ *
+ * Return: 0 on pass and negative value on failure.
+ */
+int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header)
+{
+	int ret = -EPERM;
+	struct cold_reset *cold_rst = &nfc_dev->cold_reset;
+	char *rsp_buf = NULL;
+
+	rsp_buf = kzalloc(cold_rst->rsp_len, GFP_DMA | GFP_KERNEL);
+	if (!rsp_buf)
+		return -ENOMEM;
+
+	/*
+	 * read header if NFC is disabled
+	 * for enable case, header is read by nfc read thread(for i2c)
+	 */
+	if ((!cold_rst->is_nfc_enabled) &&
+			(nfc_dev->interface == PLATFORM_IF_I2C)) {
+		ret = i2c_master_recv(nfc_dev->i2c_dev.client, rsp_buf, NCI_HDR_LEN);
+		if (ret <= 0) {
+			dev_err(nfc_dev->nfc_device,
+				"%s: failure to read cold reset rsp header\n",
+				 __func__);
+			ret = -EIO;
+			goto error;
+		}
+		/*
+		 * return failure, if packet is not a response packet or
+		 * if response's OID doesn't match with the CMD's OID
+		 */
+		if (!(rsp_buf[0] & NCI_RSP_PKT_TYPE) ||
+			(rsp_buf[1] != cold_rst->cmd_buf[1])) {
+
+			dev_err(nfc_dev->nfc_device,
+				"%s: - invalid cold reset response 0x%x 0x%x\n",
+					__func__, rsp_buf[0], rsp_buf[1]);
+			ret = -EINVAL;
+			goto error;
+		}
+	} else if (header) {
+		memcpy(rsp_buf, header, NCI_HDR_LEN);
+	} else {
+		dev_err(nfc_dev->nfc_device,
+				"%s: - invalid or NULL header\n", __func__);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if ((NCI_HDR_LEN + rsp_buf[NCI_PAYLOAD_LEN_IDX]) >
+						cold_rst->rsp_len) {
+		dev_err(nfc_dev->nfc_device,
+			"%s: - no space for cold_reset resp\n", __func__);
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	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],
+			     NCI_CMD_RSP_TIMEOUT);
+
+		if (ret <= 0) {
+			dev_err(nfc_dev->nfc_device,
+				"%s: failure to read cold reset rsp payload\n",
+				__func__);
+			ret = -EIO;
+			goto error;
+		}
+		ret = cold_rst->status = rsp_buf[NCI_PAYLOAD_IDX];
+
+		pr_debug("nfc ese rsp hdr 0x%x 0x%x 0x%x, payload byte0 0x%x\n",
+				rsp_buf[0], rsp_buf[1], rsp_buf[2], rsp_buf[3]);
+	}
+
+error:
+	kfree(rsp_buf);
+
+	return ret;
+}
+
+
+/**
+ * ese_cold_reset_ioctl() - This function handles the eSE cold reset ioctls.
+ * @nfc_dev: NFC device handle.
+ * @arg: ioctl argument.
+ *
+ * Return: 0 on pass and negative value on failure.
+ */
+
+int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg)
+{
+	int ret;
+	struct ese_ioctl_arg ioctl_arg;
+
+	if (!arg) {
+		dev_err(nfc_dev->nfc_device, "arg is invalid\n");
+		return -EINVAL;
+	}
+
+	ret = copy_from_user((void *)&ioctl_arg, (const void *)arg,
+						sizeof(ioctl_arg));
+	if (ret) {
+		dev_err(nfc_dev->nfc_device,
+				"ese ioctl arg copy from user failed\n");
+		return -EFAULT;
+	}
+
+	nfc_dev->cold_reset.arg = kzalloc(sizeof(struct ese_cold_reset_arg),
+							GFP_KERNEL);
+	if (!nfc_dev->cold_reset.arg)
+		return -ENOMEM;
+
+	ret = copy_struct_from_user(nfc_dev->cold_reset.arg,
+				sizeof(struct ese_cold_reset_arg),
+				u64_to_user_ptr(ioctl_arg.buf),
+				sizeof(struct ese_cold_reset_arg));
+	if (ret) {
+		dev_err(nfc_dev->nfc_device,
+			"ese ioctl arg buffer copy from user failed\n");
+
+		ret = -EFAULT;
+		goto err;
+	}
+
+	switch (nfc_dev->cold_reset.arg->sub_cmd) {
+
+	case ESE_COLD_RESET_DO:
+
+		/*
+		 * cold reset allowed during protection enable, only if the
+		 * source is same as the one which enabled protection.
+		 */
+		if (nfc_dev->cold_reset.is_crp_en &&
+			(nfc_dev->cold_reset.arg->src !=
+				nfc_dev->cold_reset.last_src_ese_prot)) {
+			dev_err(nfc_dev->nfc_device,
+				"cold reset from %d denied, protection is on\n",
+						nfc_dev->cold_reset.arg->src);
+			ret = -EACCES;
+			goto err;
+		}
+
+		nfc_dev->cold_reset.cmd_buf = kzalloc(COLD_RESET_CMD_LEN,
+							GFP_DMA | GFP_KERNEL);
+		if (!nfc_dev->cold_reset.cmd_buf) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		nfc_dev->cold_reset.cmd_buf[0] = PROP_NCI_CMD_GID;
+		nfc_dev->cold_reset.cmd_buf[1] = COLD_RESET_OID;
+		nfc_dev->cold_reset.cmd_buf[2] = COLD_RESET_CMD_PL_LEN;
+		nfc_dev->cold_reset.cmd_len = NCI_HDR_LEN +
+						COLD_RESET_CMD_PL_LEN;
+		nfc_dev->cold_reset.rsp_len = COLD_RESET_RSP_LEN;
+		break;
+
+	case ESE_COLD_RESET_PROTECT_EN:
+
+		if (nfc_dev->cold_reset.is_crp_en) {
+			if (nfc_dev->cold_reset.arg->src !=
+				nfc_dev->cold_reset.last_src_ese_prot) {
+				dev_err(nfc_dev->nfc_device,
+					"ese protection enable denied\n");
+				ret = -EACCES;
+				goto err;
+			}
+			pr_warn("ese protection already enabled\n");
+
+			ret = 0;
+			/* free buffers and exit with pass */
+			goto err;
+		}
+
+	case ESE_COLD_RESET_PROTECT_DIS:
+
+		if (nfc_dev->cold_reset.is_crp_en &&
+			nfc_dev->cold_reset.arg->src !=
+				nfc_dev->cold_reset.last_src_ese_prot) {
+			pr_err("ese cold reset protection disable denied\n");
+			ret = -EACCES;
+			goto err;
+		}
+		nfc_dev->cold_reset.cmd_buf = kzalloc(COLD_RESET_PROT_CMD_LEN,
+							GFP_DMA | GFP_KERNEL);
+		if (!nfc_dev->cold_reset.cmd_buf) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		nfc_dev->cold_reset.cmd_buf[0] = PROP_NCI_CMD_GID;
+		nfc_dev->cold_reset.cmd_buf[1] = COLD_RESET_PROT_OID;
+		nfc_dev->cold_reset.cmd_buf[2] = COLD_RESET_PROT_CMD_PL_LEN;
+		nfc_dev->cold_reset.cmd_len = NCI_HDR_LEN +
+						COLD_RESET_PROT_CMD_PL_LEN;
+		nfc_dev->cold_reset.rsp_len = COLD_RESET_PROT_RSP_LEN;
+		if (nfc_dev->cold_reset.arg->sub_cmd ==
+						ESE_COLD_RESET_PROTECT_EN)
+			nfc_dev->cold_reset.cmd_buf[3] = 0x1;
+		else
+			nfc_dev->cold_reset.cmd_buf[3] = 0x0;
+
+		break;
+
+	default:
+		pr_err("%s invalid ese ioctl sub cmd %d\n", __func__,
+					nfc_dev->cold_reset.arg->sub_cmd);
+		ret = -ENOIOCTLCMD;
+		goto err;
+	}
+
+	pr_debug("nfc ese cmd hdr 0x%x 0x%x 0x%x\n",
+				nfc_dev->cold_reset.cmd_buf[0],
+				nfc_dev->cold_reset.cmd_buf[1],
+				nfc_dev->cold_reset.cmd_buf[2]);
+
+	ret = send_ese_cmd(nfc_dev);
+	if (ret <= 0) {
+		pr_err("failed to send ese command\n");
+		goto err;
+	}
+
+	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 read thread is not active
+		 */
+
+		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);
+				nfc_dev->cold_reset.rsp_pending = false;
+				goto err;
+			}
+
+			ret = read_cold_reset_rsp(nfc_dev, NULL);
+			nfc_dev->cold_reset.rsp_pending = false;
+			if (ret < 0) {
+				pr_err("%s rsp read err\n", __func__);
+				goto err;
+			}
+		} else {
+			/*
+			 * Enable intr as it is disabled when NFC is in disable
+			 * state
+			 */
+			nfc_dev->nfc_enable_intr(nfc_dev);
+
+			wait_event_interruptible(
+				nfc_dev->cold_reset.read_wq,
+				!nfc_dev->cold_reset.rsp_pending);
+		}
+
+		nfc_dev->nfc_disable_intr(nfc_dev);
+	}
+
+	if (nfc_dev->cold_reset.arg->sub_cmd == ESE_COLD_RESET_PROTECT_EN) {
+		nfc_dev->cold_reset.is_crp_en = true;
+		nfc_dev->cold_reset.last_src_ese_prot =
+						nfc_dev->cold_reset.arg->src;
+	} else if (nfc_dev->cold_reset.arg->sub_cmd ==
+						ESE_COLD_RESET_PROTECT_DIS) {
+		nfc_dev->cold_reset.is_crp_en = false;
+		nfc_dev->cold_reset.last_src_ese_prot =
+						ESE_COLD_RESET_ORIGIN_NONE;
+	} else
+		pr_debug("ese cmd is %d\n", nfc_dev->cold_reset.arg->sub_cmd);
+
+	ret = nfc_dev->cold_reset.status;
+err:
+	kfree(nfc_dev->cold_reset.cmd_buf);
+	kfree(nfc_dev->cold_reset.arg);
+	nfc_dev->cold_reset.arg = NULL;
+	nfc_dev->cold_reset.cmd_buf = NULL;
+
+	return ret;
+}

+ 81 - 0
qti/ese_cold_reset.h

@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __ESE_COLD_RESET_H
+#define __ESE_COLD_RESET_H
+
+#include <nfcinfo.h>
+
+#define MAX_BUFF_SIZE 264
+
+/* ESE_COLD_RESET MACROS */
+#define COLD_RESET_CMD_LEN		3
+#define COLD_RESET_RSP_LEN		4
+#define COLD_RESET_PROT_CMD_LEN		4
+#define COLD_RESET_PROT_RSP_LEN		4
+#define PROP_NCI_CMD_GID		0x2F
+#define COLD_RESET_CMD_PL_LEN		0x00
+#define COLD_RESET_PROT_CMD_PL_LEN	0x01
+#define PROP_NCI_RSP_GID		0x4F
+#define COLD_RESET_OID			0x1E
+#define COLD_RESET_PROT_OID		0x1F
+
+#define ESE_COLD_RESET _IOWR(NFCC_MAGIC, 0x08, struct ese_ioctl_arg)
+
+enum ese_ioctl_arg_type {
+	ESE_ARG_TYPE_COLD_RESET = 0,
+};
+
+/* ESE_COLD_RESET ioctl origin, max 4 are supported */
+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,
+};
+
+/* ESE_COLD_RESET ioctl sub commands, max 8 are supported */
+enum ese_cold_reset_sub_cmd {
+	ESE_COLD_RESET_DO = 0,
+	ESE_COLD_RESET_PROTECT_EN,
+	ESE_COLD_RESET_PROTECT_DIS,
+};
+
+/* Data passed in buf of ese cold reset ioctl */
+struct ese_cold_reset_arg {
+	__u8 src;
+	__u8 sub_cmd;
+	__u16 rfu;
+};
+
+/* Argument buffer passed to ese ioctl */
+struct ese_ioctl_arg {
+	__u64 buf;
+	__u32 buf_size;
+	__u8 type;
+};
+
+/* Features specific Parameters */
+struct cold_reset {
+	wait_queue_head_t read_wq;
+	char *cmd_buf;
+	struct ese_cold_reset_arg *arg;
+	uint16_t cmd_len;
+	uint16_t rsp_len;
+	/* Source of last ese protection command */
+	uint8_t last_src_ese_prot;
+	uint8_t status;
+	/* Is cold reset protection enabled */
+	bool is_crp_en;
+	bool rsp_pending;
+	/* Is NFC enabled from UI */
+	bool is_nfc_enabled;
+};
+
+struct nfc_dev;
+int ese_cold_reset_ioctl(struct nfc_dev *nfc_dev, unsigned long arg);
+int read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header);
+
+#endif

+ 951 - 0
qti/nfc_common.c

@@ -0,0 +1,951 @@
+// 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_configs *nfc_configs,
+		 uint8_t interface)
+{
+	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))) {
+			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);
+
+	/* 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)) {
+		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);
+
+	// optional property
+	ret = of_property_read_u32_array(np, NFC_LDO_VOL_DT_NAME,
+			(u32 *) ldo->vdd_levels,
+			ARRAY_SIZE(ldo->vdd_levels));
+	if (ret) {
+		dev_err(dev, "error reading NFC VDDIO min and max value\n");
+		// set default as per datasheet
+		ldo->vdd_levels[0] = NFC_VDDIO_MIN;
+		ldo->vdd_levels[1] = NFC_VDDIO_MAX;
+	}
+
+	// optional property
+	ret = of_property_read_u32(np, NFC_LDO_CUR_DT_NAME, &ldo->max_current);
+	if (ret) {
+		dev_err(dev, "error reading NFC current value\n");
+		// set default as per datasheet
+		ldo->max_current = NFC_CURRENT_MAX;
+	}
+
+	return 0;
+}
+
+/**
+ * nfc_ldo_vote()
+ * @nfc_dev: NFC device containing regulator handle
+ *
+ * LDO voting based on voltage and current entries in DT
+ *
+ * Return: 0 on success and -ve on failure
+ */
+int nfc_ldo_vote(struct nfc_dev *nfc_dev)
+{
+	int ret;
+
+	ret =  regulator_set_voltage(nfc_dev->reg,
+			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->configs.ldo.max_current);
+	if (ret < 0) {
+		pr_err("%s: set load failed\n", __func__);
+		return ret;
+	}
+
+	ret = regulator_enable(nfc_dev->reg);
+	if (ret < 0)
+		pr_err("%s: regulator_enable failed\n", __func__);
+	else
+		nfc_dev->is_vreg_enabled = true;
+	return ret;
+}
+
+/**
+ * nfc_ldo_config()
+ * @dev: device instance to read DT entry
+ * @nfc_dev: NFC device containing regulator handle
+ *
+ * Configure LDO if entry is present in DT file otherwise
+ * return with success as it's optional
+ *
+ * Return: 0 on success and -ve on failure
+ */
+int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev)
+{
+	int ret;
+
+	if (of_get_property(dev->of_node, NFC_LDO_SUPPLY_NAME, NULL)) {
+		// Get the regulator handle
+		nfc_dev->reg = regulator_get(dev, NFC_LDO_SUPPLY_DT_NAME);
+		if (IS_ERR(nfc_dev->reg)) {
+			ret = PTR_ERR(nfc_dev->reg);
+			nfc_dev->reg = NULL;
+			pr_err("%s: regulator_get failed, ret = %d\n",
+				__func__, ret);
+			return ret;
+		}
+	} else {
+		nfc_dev->reg = NULL;
+		pr_err("%s: regulator entry not present\n", __func__);
+		// return success as it's optional to configure LDO
+		return 0;
+	}
+
+	// LDO config supported by platform DT
+	ret = nfc_ldo_vote(nfc_dev);
+	if (ret < 0) {
+		pr_err("%s: LDO voting failed, ret = %d\n", __func__, ret);
+		regulator_put(nfc_dev->reg);
+	}
+	return ret;
+}
+
+/**
+ * nfc_ldo_unvote()
+ * @nfc_dev: NFC device containing regulator handle
+ *
+ * set voltage and load to zero and disable regulator
+ *
+ * Return: 0 on success and -ve on failure
+ */
+int nfc_ldo_unvote(struct nfc_dev *nfc_dev)
+{
+	int ret;
+
+	if (!nfc_dev->is_vreg_enabled) {
+		pr_err("%s: regulator already disabled\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = regulator_disable(nfc_dev->reg);
+	if (ret < 0) {
+		pr_err("%s: regulator_disable failed\n", __func__);
+		return ret;
+	}
+	nfc_dev->is_vreg_enabled = false;
+
+	ret =  regulator_set_voltage(nfc_dev->reg, 0, NFC_VDDIO_MAX);
+	if (ret < 0) {
+		pr_err("%s: set voltage failed\n", __func__);
+		return ret;
+	}
+
+	ret = regulator_set_load(nfc_dev->reg, 0);
+	if (ret < 0)
+		pr_err("%s: set load failed\n", __func__);
+	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)
+{
+	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);
+	}
+}
+
+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));
+			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
+			    ("%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;
+}
+
+void nfc_misc_unregister(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);
+	if (nfc_dev->ipcl)
+		ipc_log_context_destroy(nfc_dev->ipcl);
+}
+
+int nfc_misc_register(struct nfc_dev *nfc_dev,
+		      const struct file_operations *nfc_fops, int count,
+		      char *devname, char *classname)
+{
+	int ret = 0;
+
+	ret = alloc_chrdev_region(&nfc_dev->devno, 0, count, devname);
+	if (ret < 0) {
+		pr_err("%s: failed to alloc chrdev region ret %d\n",
+			__func__, ret);
+		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->ipcl = ipc_log_context_create(NUM_OF_IPC_LOG_PAGES,
+						dev_name(nfc_dev->nfc_device), 0);
+
+	nfc_dev->kbuflen = MAX_BUFFER_SIZE;
+	nfc_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+	if (!nfc_dev->kbuf) {
+		nfc_misc_unregister(nfc_dev, count);
+		return -ENOMEM;
+	}
+
+	nfc_dev->cold_reset.rsp_pending = false;
+	nfc_dev->cold_reset.is_nfc_enabled = false;
+	nfc_dev->cold_reset.is_crp_en = false;
+	nfc_dev->cold_reset.last_src_ese_prot = ESE_COLD_RESET_ORIGIN_NONE;
+
+	init_waitqueue_head(&nfc_dev->cold_reset.read_wq);
+
+	return 0;
+}
+
+/*
+ * 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->configs.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");
+		}
+		nfc_dev->is_ese_session_active = true;
+	} 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");
+		}
+		nfc_dev->is_ese_session_active = false;
+	} else if (arg == ESE_POWER_STATE) {
+		/* 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;
+	}
+	return ret;
+}
+
+/*
+ * 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;
+	struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
+
+	if (arg == NFC_POWER_OFF) {
+		/*
+		 * We are attempting a hardware reset so let us disable
+		 * interrupts to avoid spurious notifications to upper
+		 * layers.
+		 */
+		nfc_dev->nfc_disable_intr(nfc_dev);
+		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);
+		set_valid_gpio(nfc_gpio->dwl_req, 0);
+
+		gpio_set_ven(nfc_dev, 1);
+		nfc_dev->nfc_ven_enabled = true;
+
+	} 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
+		 */
+		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);
+		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");
+		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->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) {
+		/*
+		 * Setting firmware download gpio to LOW
+		 * FW download finished
+		 */
+		pr_debug("set fw gpio LOW\n");
+		set_valid_gpio(nfc_gpio->dwl_req, 0);
+		nfc_dev->nfc_state = NFC_STATE_NCI;
+
+	} 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;
+}
+
+/*
+ * Inside nfc_ioctl_nfcc_info
+ *
+ * @brief   nfc_ioctl_nfcc_info
+ *
+ * Check the NFC Chipset and firmware version details
+ */
+unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg)
+{
+	unsigned int r = 0;
+	struct nfc_dev *nfc_dev = filp->private_data;
+
+	r = nfc_dev->nqx_info.i;
+	pr_debug("nfc : %s r = 0x%x\n", __func__, r);
+
+	return r;
+}
+
+/** @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;
+	case NFCC_GET_INFO:
+		ret = nfc_ioctl_nfcc_info(pfile, arg);
+		break;
+	case NFC_GET_PLATFORM_TYPE:
+		ret = nfc_dev->interface;
+		break;
+	case ESE_COLD_RESET:
+		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 cmd 0x%x, arg %lu\n",
+						__func__, cmd, arg);
+		ret = -ENOIOCTLCMD;
+	}
+	return ret;
+}
+
+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) {
+		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;
+
+	mutex_unlock(&nfc_dev->dev_ref_mutex);
+
+	return 0;
+}
+
+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) {
+		nfc_dev->nfc_disable_intr(nfc_dev);
+		set_valid_gpio(nfc_dev->configs.gpio.dwl_req, 0);
+	}
+
+	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;
+}
+
+int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev)
+{
+	int ret;
+
+	nfc_dev->nfc_enable_intr(nfc_dev);
+
+	ret = wait_event_interruptible_timeout(nfc_dev->read_wq,
+			!nfc_dev->i2c_dev.irq_enabled,
+			msecs_to_jiffies(MAX_IRQ_WAIT_TIME));
+	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;
+	enum nfc_state_flags nfc_state = NFC_STATE_UNKNOWN;
+	enum chip_types chip_type = CHIP_UNKNOWN;
+	struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
+
+	/*get fw version in nci mode*/
+	gpio_set_ven(nfc_dev, 1);
+	gpio_set_ven(nfc_dev, 0);
+	gpio_set_ven(nfc_dev, 1);
+	chip_type = get_nfcc_chip_type(nfc_dev);
+
+	/*get fw version in fw dwl mode*/
+	if (chip_type == CHIP_UNKNOWN) {
+		nfc_dev->nfc_enable_intr(nfc_dev);
+		/*Chip is unknown, initially assume with fw dwl pin enabled*/
+		set_valid_gpio(nfc_gpio->dwl_req, 1);
+		gpio_set_ven(nfc_dev, 0);
+		gpio_set_ven(nfc_dev, 1);
+		chip_type = get_nfcc_chip_type_dl(nfc_dev);
+		/*get the state of nfcc normal/teared in fw dwl mode*/
+	} else {
+		nfc_state = NFC_STATE_NCI;
+	}
+
+	/*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;
+	}
+
+	/*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;
+}

+ 346 - 0
qti/nfc_common.h

@@ -0,0 +1,346 @@
+/* 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_
+
+#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 <nfcinfo.h>
+#include <linux/regulator/consumer.h>
+#include <linux/ipc_logging.h>
+#include "nfc_i2c_drv.h"
+#include "ese_cold_reset.h"
+
+// Max device count for this driver
+#define DEV_COUNT            1
+
+// NFC device class
+#define CLASS_NAME           "qti-nfc"
+
+//  NFC character device name, this will be in /dev/
+#define NFC_CHAR_DEV_NAME	 "nq-nci"
+
+// 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 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)
+
+#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)
+
+/* 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_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)
+
+// Retry count for normal write
+#define NO_RETRY				(1)
+#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
+// 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 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"
+#define DTS_CLKREQ_GPIO_STR	"qcom,sn-clkreq"
+#define DTS_CLKSRC_GPIO_STR	"qcom,clk-src"
+#define NFC_LDO_SUPPLY_DT_NAME	"qcom,sn-vdd-1p8"
+#define NFC_LDO_SUPPLY_NAME	"qcom,sn-vdd-1p8-supply"
+#define NFC_LDO_VOL_DT_NAME	"qcom,sn-vdd-1p8-voltage"
+#define NFC_LDO_CUR_DT_NAME	"qcom,sn-vdd-1p8-current"
+
+//as per SN1x0 datasheet
+#define NFC_VDDIO_MIN		1650000 //in uV
+#define NFC_VDDIO_MAX		1950000 //in uV
+#define NFC_CURRENT_MAX		157000 //in uA
+
+
+#define NUM_OF_IPC_LOG_PAGES	(2)
+#define PKT_MAX_LEN		(4) // no of max bytes to print for cmd/resp
+
+#define GET_IPCLOG_MAX_PKT_LEN(c)	((c > PKT_MAX_LEN) ? PKT_MAX_LEN : c)
+
+#define NFCLOG_IPC(nfc_dev, log_to_dmesg, x...)	\
+do { \
+	ipc_log_string(nfc_dev->ipcl, x); \
+	if (log_to_dmesg) { \
+		if (nfc_dev->nfc_device) \
+			dev_err((nfc_dev->nfc_device), x); \
+		else \
+			pr_err(x); \
+	} \
+} while (0)
+
+enum ese_ioctl_request {
+	/* eSE POWER ON */
+	ESE_POWER_ON = 0,
+	/* eSE POWER OFF */
+	ESE_POWER_OFF,
+	/* 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,
+};
+
+/*nfc platform interface type*/
+enum interface_flags {
+	/*I2C physical IF for NFCC */
+	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,
+	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;
+};
+
+// NFC LDO entries from DT
+struct platform_ldo {
+	int vdd_levels[2];
+	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;
+	struct device *nfc_device;
+	struct cdev c_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_configs configs;
+	struct cold_reset cold_reset;
+	struct regulator *reg;
+
+	/* read buffer*/
+	size_t kbuflen;
+	u8 *kbuf;
+
+	union nqx_uinfo nqx_info;
+
+	void *ipcl;
+
+	int (*nfc_read)(struct nfc_dev *dev, char *buf, size_t count, int timeout);
+	int (*nfc_write)(struct nfc_dev *dev, const char *buf, const size_t count,
+				int max_retry_cnt);
+	int (*nfc_enable_intr)(struct nfc_dev *dev);
+	int (*nfc_disable_intr)(struct nfc_dev *dev);
+};
+
+int nfc_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_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);
+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_

+ 577 - 0
qti/nfc_i2c_drv.c

@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * 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"
+
+/**
+ * i2c_disable_irq()
+ *
+ * Check if interrupt is disabled or not
+ * and disable interrupt
+ *
+ * Return: int
+ */
+int i2c_disable_irq(struct nfc_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags);
+	if (dev->i2c_dev.irq_enabled) {
+		disable_irq_nosync(dev->i2c_dev.client->irq);
+		dev->i2c_dev.irq_enabled = false;
+	}
+	spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags);
+
+	return 0;
+}
+
+/**
+ * i2c_enable_irq()
+ *
+ * Check if interrupt is enabled or not
+ * and enable interrupt
+ *
+ * Return: int
+ */
+int i2c_enable_irq(struct nfc_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->i2c_dev.irq_enabled_lock, flags);
+	if (!dev->i2c_dev.irq_enabled) {
+		dev->i2c_dev.irq_enabled = true;
+		enable_irq(dev->i2c_dev.client->irq);
+	}
+	spin_unlock_irqrestore(&dev->i2c_dev.irq_enabled_lock, flags);
+
+	return 0;
+}
+
+static irqreturn_t i2c_irq_handler(int irq, void *dev_id)
+{
+	struct nfc_dev *nfc_dev = dev_id;
+	struct i2c_dev *i2c_dev = &nfc_dev->i2c_dev;
+
+	if (device_may_wakeup(&i2c_dev->client->dev))
+		pm_wakeup_event(&i2c_dev->client->dev, WAKEUP_SRC_TIMEOUT);
+
+	i2c_disable_irq(nfc_dev);
+	wake_up(&nfc_dev->read_wq);
+
+	return IRQ_HANDLED;
+}
+
+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);
+
+	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: returned %d\n", __func__, ret);
+		goto err;
+	}
+
+	for (i = 0; i < disp_len; i++)
+		NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]);
+
+	/* 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 *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(nfc_dev, false, "%s sending %d B", __func__, count);
+
+	for (i = 0; i < disp_len; i++)
+		NFCLOG_IPC(nfc_dev, false, " %02x", buf[i]);
+
+	for (retry_cnt = 1; retry_cnt <= max_retry_cnt; retry_cnt++) {
+
+		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 ret %d, Maybe in Standby Mode - Retry(%d)\n",
+				__func__, ret, retry_cnt);
+			usleep_range(WRITE_RETRY_WAIT_TIME_USEC,
+				     WRITE_RETRY_WAIT_TIME_USEC + 100);
+		} else if (ret != count) {
+			pr_err("%s: failed to write %d\n", __func__, ret);
+			ret = -EIO;
+		} else if (ret == count)
+			break;
+	}
+	return ret;
+}
+
+ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf,
+			 size_t count, loff_t *offset)
+{
+	int ret = 0;
+	struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data;
+
+	if (filp->f_flags & O_NONBLOCK) {
+		pr_err(":f_flag has O_NONBLOCK. EAGAIN\n");
+		return -EAGAIN;
+	}
+	mutex_lock(&nfc_dev->read_mutex);
+	ret = i2c_read(nfc_dev, nfc_dev->read_kbuf, count, 0);
+	if (ret > 0) {
+		if (copy_to_user(buf, nfc_dev->read_kbuf, ret)) {
+			pr_warn("%s : failed to copy to user space\n", __func__);
+			ret = -EFAULT;
+		}
+	}
+	mutex_unlock(&nfc_dev->read_mutex);
+	return ret;
+}
+
+ssize_t nfc_i2c_dev_write(struct file *filp, const char __user *buf,
+			  size_t count, loff_t *offset)
+{
+	int ret;
+	struct nfc_dev *nfc_dev = (struct nfc_dev *)filp->private_data;
+
+	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;
+	}
+	ret = i2c_write(nfc_dev, nfc_dev->write_kbuf, count, NO_RETRY);
+	mutex_unlock(&nfc_dev->write_mutex);
+	return ret;
+}
+
+static const struct file_operations nfc_i2c_dev_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = nfc_i2c_dev_read,
+	.write = nfc_i2c_dev_write,
+	.open = nfc_dev_open,
+	.release = nfc_dev_close,
+	.unlocked_ioctl = nfc_dev_ioctl,
+};
+
+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_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_configs, PLATFORM_IF_I2C);
+	if (ret) {
+		pr_err("%s : failed to parse dt\n", __func__);
+		goto err;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		pr_err("%s : need I2C_FUNC_I2C\n", __func__);
+		ret = -ENODEV;
+		goto err;
+	}
+	nfc_dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL);
+	if (nfc_dev == NULL) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	nfc_dev->read_kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_DMA | GFP_KERNEL);
+	if (!nfc_dev->read_kbuf) {
+		ret = -ENOMEM;
+		goto err_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;
+	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_write_kbuf;
+	}
+	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);
+		goto err_free_ven;
+	}
+	client->irq = ret;
+	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);
+		//not returning failure here as dwl gpio is a optional gpio for sn220
+	}
+
+	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);
+		goto err_free_dwl_req;
+	}
+
+	/*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_register(nfc_dev, &nfc_i2c_dev_fops, DEV_COUNT,
+				NFC_CHAR_DEV_NAME, CLASS_NAME);
+	if (ret) {
+		pr_err("%s: nfc_misc_register failed\n", __func__);
+		goto err_mutex_destroy;
+	}
+	/* interrupt initializations */
+	pr_info("%s : requesting IRQ %d\n", __func__, client->irq);
+	i2c_dev->irq_enabled = true;
+	ret = request_irq(client->irq, i2c_irq_handler,
+			  IRQF_TRIGGER_HIGH, client->name, nfc_dev);
+	if (ret) {
+		pr_err("%s: request_irq failed\n", __func__);
+		goto err_nfc_misc_unregister;
+	}
+	i2c_disable_irq(nfc_dev);
+	i2c_set_clientdata(client, nfc_dev);
+
+	ret = nfc_ldo_config(&client->dev, nfc_dev);
+	if (ret) {
+		pr_err("LDO config failed\n");
+		goto err_ldo_config_failed;
+	}
+
+	ret = nfcc_hw_check(nfc_dev);
+	if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) {
+		pr_err("nfc hw check failed ret %d\n", ret);
+		goto err_nfcc_hw_check;
+	}
+
+	device_init_wakeup(&client->dev, true);
+	i2c_dev->irq_wake_up = false;
+	nfc_dev->is_ese_session_active = false;
+
+	pr_info("%s success\n", __func__);
+	return 0;
+
+err_nfcc_hw_check:
+	if (nfc_dev->reg) {
+		nfc_ldo_unvote(nfc_dev);
+		regulator_put(nfc_dev->reg);
+	}
+err_ldo_config_failed:
+	free_irq(client->irq, nfc_dev);
+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);
+	mutex_destroy(&nfc_dev->write_mutex);
+	gpio_free(nfc_gpio->clkreq);
+err_free_dwl_req:
+	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_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:
+	pr_err("%s: failed\n", __func__);
+	return ret;
+}
+
+int nfc_i2c_dev_remove(struct i2c_client *client)
+{
+	int ret = 0;
+	struct nfc_dev *nfc_dev = NULL;
+
+	pr_info("%s: remove device\n", __func__);
+	nfc_dev = i2c_get_clientdata(client);
+	if (!nfc_dev) {
+		pr_err("%s: device doesn't exist anymore\n", __func__);
+		ret = -ENODEV;
+		return ret;
+	}
+
+	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) {
+		nfc_ldo_unvote(nfc_dev);
+		regulator_put(nfc_dev->reg);
+	}
+
+	device_init_wakeup(&client->dev, false);
+	free_irq(client->irq, nfc_dev);
+	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->configs.gpio.clkreq))
+		gpio_free(nfc_dev->configs.gpio.clkreq);
+
+	if (gpio_is_valid(nfc_dev->configs.gpio.dwl_req))
+		gpio_free(nfc_dev->configs.gpio.dwl_req);
+
+	if (gpio_is_valid(nfc_dev->configs.gpio.irq))
+		gpio_free(nfc_dev->configs.gpio.irq);
+
+	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;
+}
+
+int nfc_i2c_dev_suspend(struct device *device)
+{
+	struct i2c_client *client = to_i2c_client(device);
+	struct nfc_dev *nfc_dev = i2c_get_clientdata(client);
+	struct i2c_dev *i2c_dev = NULL;
+
+	if (!nfc_dev) {
+		pr_err("%s: device doesn't exist anymore\n", __func__);
+		return -ENODEV;
+	}
+
+	i2c_dev = &nfc_dev->i2c_dev;
+
+	NFCLOG_IPC(nfc_dev, false, "%s: irq_enabled = %d", __func__,
+							i2c_dev->irq_enabled);
+
+	if (device_may_wakeup(&client->dev) && i2c_dev->irq_enabled) {
+		if (!enable_irq_wake(client->irq))
+			i2c_dev->irq_wake_up = true;
+	}
+	return 0;
+}
+
+int nfc_i2c_dev_resume(struct device *device)
+{
+	struct i2c_client *client = to_i2c_client(device);
+	struct nfc_dev *nfc_dev = i2c_get_clientdata(client);
+	struct i2c_dev *i2c_dev = NULL;
+
+	if (!nfc_dev) {
+		pr_err("%s: device doesn't exist anymore\n", __func__);
+		return -ENODEV;
+	}
+
+	i2c_dev = &nfc_dev->i2c_dev;
+
+	NFCLOG_IPC(nfc_dev, false, "%s: irq_wake_up = %d", __func__,
+							i2c_dev->irq_wake_up);
+
+	if (device_may_wakeup(&client->dev) && i2c_dev->irq_wake_up) {
+		if (!disable_irq_wake(client->irq))
+			i2c_dev->irq_wake_up = false;
+	}
+	return 0;
+}
+
+static const struct i2c_device_id nfc_i2c_dev_id[] = {
+	{NFC_I2C_DEV_ID, 0},
+	{}
+};
+
+static const struct of_device_id nfc_i2c_dev_match_table[] = {
+	{.compatible = NFC_I2C_DRV_STR,},
+	{}
+};
+
+static const struct dev_pm_ops nfc_i2c_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(nfc_i2c_dev_suspend, nfc_i2c_dev_resume)
+};
+
+static struct i2c_driver nfc_i2c_dev_driver = {
+	.id_table = nfc_i2c_dev_id,
+	.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,
+	},
+};
+
+MODULE_DEVICE_TABLE(of, nfc_i2c_dev_match_table);
+
+static int __init nfc_i2c_dev_init(void)
+{
+	int ret = 0;
+
+	ret = i2c_add_driver(&nfc_i2c_dev_driver);
+	if (ret != 0)
+		pr_err("NFC I2C add driver error ret %d\n", ret);
+	return ret;
+}
+
+module_init(nfc_i2c_dev_init);
+
+static void __exit nfc_i2c_dev_exit(void)
+{
+	pr_debug("Unloading NFC I2C driver\n");
+	i2c_del_driver(&nfc_i2c_dev_driver);
+}
+
+module_exit(nfc_i2c_dev_exit);
+
+MODULE_DESCRIPTION("QTI NFC I2C driver");
+MODULE_LICENSE("GPL v2");

+ 81 - 0
qti/nfc_i2c_drv.h

@@ -0,0 +1,81 @@
+/* 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_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"
+
+struct nfc_dev;
+
+//Interface specific parameters
+struct i2c_dev {
+	struct i2c_client *client;
+	/*IRQ parameters */
+	bool irq_enabled;
+	spinlock_t irq_enabled_lock;
+	/* NFC_IRQ wake-up state */
+	bool irq_wake_up;
+};
+
+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);
+int nfc_i2c_dev_remove(struct i2c_client *client);
+int nfc_i2c_dev_suspend(struct device *device);
+int nfc_i2c_dev_resume(struct device *device);
+
+#if IS_ENABLED(CONFIG_NFC_QTI_I2C)
+
+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 timeout);
+
+#else
+
+static inline int i2c_enable_irq(struct nfc_dev *dev)
+{
+	return -ENXIO;
+}
+
+static inline int i2c_disable_irq(struct nfc_dev *dev)
+{
+	return -ENXIO;
+}
+
+static inline int i2c_write(struct nfc_dev *dev, const char *buf,
+					size_t count, int max_retry_cnt)
+{
+	return -ENXIO;
+}
+
+static inline int i2c_read(struct nfc_dev *dev, char *buf, size_t count, int timeout)
+{
+	return -ENXIO;
+}
+
+#endif
+
+#endif //_NFC_I2C_DRV_H_