diff mbox series

[net-next,1/2] nfc: s3fwrn82: Add driver for Samsung S3FWRN82 NFC Chip

Message ID 20201113050719epcms2p7ba0a549e386259a01753714da1b79ea3@epcms2p7
State Superseded
Headers show
Series [net-next,1/2] nfc: s3fwrn82: Add driver for Samsung S3FWRN82 NFC Chip | expand

Commit Message

Bongsu Jeon Nov. 13, 2020, 5:07 a.m. UTC
Add driver for Samsung S3FWRN82 NFC controller.
S3FWRN82 is using NCI protocol and I2C communication interface.

Signed-off-by: Bongsu Jeon <bongsu.jeon@samsung.com>
---
 drivers/nfc/Kconfig             |   1 +
 drivers/nfc/Makefile            |   1 +
 drivers/nfc/s3fwrn82/Kconfig    |  15 ++
 drivers/nfc/s3fwrn82/Makefile   |  10 ++
 drivers/nfc/s3fwrn82/core.c     | 133 +++++++++++++++
 drivers/nfc/s3fwrn82/i2c.c      | 288 ++++++++++++++++++++++++++++++++
 drivers/nfc/s3fwrn82/s3fwrn82.h |  86 ++++++++++
 7 files changed, 534 insertions(+)
 create mode 100644 drivers/nfc/s3fwrn82/Kconfig
 create mode 100644 drivers/nfc/s3fwrn82/Makefile
 create mode 100644 drivers/nfc/s3fwrn82/core.c
 create mode 100644 drivers/nfc/s3fwrn82/i2c.c
 create mode 100644 drivers/nfc/s3fwrn82/s3fwrn82.h

--

Comments

Krzysztof Kozlowski Nov. 13, 2020, 7:25 a.m. UTC | #1
On Fri, 13 Nov 2020 at 06:09, Bongsu Jeon <bongsu.jeon@samsung.com> wrote:
>
>
> Add driver for Samsung S3FWRN82 NFC controller.
> S3FWRN82 is using NCI protocol and I2C communication interface.
>
> Signed-off-by: Bongsu Jeon <bongsu.jeon@samsung.com>
> ---
>  drivers/nfc/Kconfig             |   1 +
>  drivers/nfc/Makefile            |   1 +
>  drivers/nfc/s3fwrn82/Kconfig    |  15 ++
>  drivers/nfc/s3fwrn82/Makefile   |  10 ++
>  drivers/nfc/s3fwrn82/core.c     | 133 +++++++++++++++
>  drivers/nfc/s3fwrn82/i2c.c      | 288 ++++++++++++++++++++++++++++++++
>  drivers/nfc/s3fwrn82/s3fwrn82.h |  86 ++++++++++
>  7 files changed, 534 insertions(+)
>  create mode 100644 drivers/nfc/s3fwrn82/Kconfig
>  create mode 100644 drivers/nfc/s3fwrn82/Makefile
>  create mode 100644 drivers/nfc/s3fwrn82/core.c
>  create mode 100644 drivers/nfc/s3fwrn82/i2c.c
>  create mode 100644 drivers/nfc/s3fwrn82/s3fwrn82.h

No, this is a copy of existing s3fwrn5.

Please do not add drivers which are duplicating existing ones but
instead work on extending them.

Best regards,
Krzysztof
Bongsu Jeon Nov. 15, 2020, 12:54 a.m. UTC | #2
On Fri, Nov 13, 2020 at 4:26 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On Fri, 13 Nov 2020 at 06:09, Bongsu Jeon <bongsu.jeon@samsung.com> wrote:
> >
> >
> > Add driver for Samsung S3FWRN82 NFC controller.
> > S3FWRN82 is using NCI protocol and I2C communication interface.
> >
> > Signed-off-by: Bongsu Jeon <bongsu.jeon@samsung.com>
> > ---
> >  drivers/nfc/Kconfig             |   1 +
> >  drivers/nfc/Makefile            |   1 +
> >  drivers/nfc/s3fwrn82/Kconfig    |  15 ++
> >  drivers/nfc/s3fwrn82/Makefile   |  10 ++
> >  drivers/nfc/s3fwrn82/core.c     | 133 +++++++++++++++
> >  drivers/nfc/s3fwrn82/i2c.c      | 288 ++++++++++++++++++++++++++++++++
> >  drivers/nfc/s3fwrn82/s3fwrn82.h |  86 ++++++++++
> >  7 files changed, 534 insertions(+)
> >  create mode 100644 drivers/nfc/s3fwrn82/Kconfig
> >  create mode 100644 drivers/nfc/s3fwrn82/Makefile
> >  create mode 100644 drivers/nfc/s3fwrn82/core.c
> >  create mode 100644 drivers/nfc/s3fwrn82/i2c.c
> >  create mode 100644 drivers/nfc/s3fwrn82/s3fwrn82.h
>
> No, this is a copy of existing s3fwrn5.
>
> Please do not add drivers which are duplicating existing ones but
> instead work on extending them.
>
> Best regards,
> Krzysztof

I'm bongsu jeon and working for samsung nfc chip development.
If I extend the code for another nfc chip model, Could I change the
s3fwrn5 directory and Module name?
I think the name would confuse some people if they use the other nfc
chip like s3fwrn82.

Best regards,
bongsu.
Krzysztof Kozlowski Nov. 15, 2020, 10:21 a.m. UTC | #3
On Sun, 15 Nov 2020 at 01:54, Bongsu Jeon <bs.jeon87@gmail.com> wrote:
>
> On Fri, Nov 13, 2020 at 4:26 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
> >
> > On Fri, 13 Nov 2020 at 06:09, Bongsu Jeon <bongsu.jeon@samsung.com> wrote:
> > >
> > >
> > > Add driver for Samsung S3FWRN82 NFC controller.
> > > S3FWRN82 is using NCI protocol and I2C communication interface.
> > >
> > > Signed-off-by: Bongsu Jeon <bongsu.jeon@samsung.com>
> > > ---
> > >  drivers/nfc/Kconfig             |   1 +
> > >  drivers/nfc/Makefile            |   1 +
> > >  drivers/nfc/s3fwrn82/Kconfig    |  15 ++
> > >  drivers/nfc/s3fwrn82/Makefile   |  10 ++
> > >  drivers/nfc/s3fwrn82/core.c     | 133 +++++++++++++++
> > >  drivers/nfc/s3fwrn82/i2c.c      | 288 ++++++++++++++++++++++++++++++++
> > >  drivers/nfc/s3fwrn82/s3fwrn82.h |  86 ++++++++++
> > >  7 files changed, 534 insertions(+)
> > >  create mode 100644 drivers/nfc/s3fwrn82/Kconfig
> > >  create mode 100644 drivers/nfc/s3fwrn82/Makefile
> > >  create mode 100644 drivers/nfc/s3fwrn82/core.c
> > >  create mode 100644 drivers/nfc/s3fwrn82/i2c.c
> > >  create mode 100644 drivers/nfc/s3fwrn82/s3fwrn82.h
> >
> > No, this is a copy of existing s3fwrn5.
> >
> > Please do not add drivers which are duplicating existing ones but
> > instead work on extending them.
> >
> > Best regards,
> > Krzysztof
>
> I'm bongsu jeon and working for samsung nfc chip development.
> If I extend the code for another nfc chip model, Could I change the
> s3fwrn5 directory and Module name?
> I think the name would confuse some people if they use the other nfc
> chip like s3fwrn82.

Hi,

Renaming would only make git history trickier to follow. Multiple
drivers get extended and not renamed. Anyone configuring the kernel
should check through Kconfig description, compatibles or description
in bindings, so name of directory does not matter when looking for HW
support. Then someone would add different chip support, and you would
rename as well? So no, do not rename it.

Best regards,
Krzysztof
Bongsu Jeon Nov. 16, 2020, 1:59 a.m. UTC | #4
On Fri, Nov 13, 2020, 4:26 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:

> On Fri, 13 Nov 2020 at 06:09, Bongsu Jeon <bongsu.jeon@samsung.com> wrote:
> >
> >
> > Add driver for Samsung S3FWRN82 NFC controller.
> > S3FWRN82 is using NCI protocol and I2C communication interface.
> >
> > Signed-off-by: Bongsu Jeon <bongsu.jeon@samsung.com>
> > ---
> >  drivers/nfc/Kconfig             |   1 +
> >  drivers/nfc/Makefile            |   1 +
> >  drivers/nfc/s3fwrn82/Kconfig    |  15 ++
> >  drivers/nfc/s3fwrn82/Makefile   |  10 ++
> >  drivers/nfc/s3fwrn82/core.c     | 133 +++++++++++++++
> >  drivers/nfc/s3fwrn82/i2c.c      | 288 ++++++++++++++++++++++++++++++++
> >  drivers/nfc/s3fwrn82/s3fwrn82.h |  86 ++++++++++
> >  7 files changed, 534 insertions(+)
> >  create mode 100644 drivers/nfc/s3fwrn82/Kconfig
> >  create mode 100644 drivers/nfc/s3fwrn82/Makefile
> >  create mode 100644 drivers/nfc/s3fwrn82/core.c
> >  create mode 100644 drivers/nfc/s3fwrn82/i2c.c
> >  create mode 100644 drivers/nfc/s3fwrn82/s3fwrn82.h
>
> No, this is a copy of existing s3fwrn5.
>
> Please do not add drivers which are duplicating existing ones but
> instead work on extending them.
>
> Best regards,
> Krzysztof
>

I understand your explain.
Actually I thought that generic name like samsung-nci would be better
than samsung's nfc chip name.
diff mbox series

Patch

diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 75c65d339018..102654909d3a 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -59,4 +59,5 @@  source "drivers/nfc/st-nci/Kconfig"
 source "drivers/nfc/nxp-nci/Kconfig"
 source "drivers/nfc/s3fwrn5/Kconfig"
 source "drivers/nfc/st95hf/Kconfig"
+source "drivers/nfc/s3fwrn82/Kconfig"
 endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 5393ba59b17d..518d83301ad2 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -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-$(CONFIG_NFC_S3FWRN82)	+= s3fwrn82/
diff --git a/drivers/nfc/s3fwrn82/Kconfig b/drivers/nfc/s3fwrn82/Kconfig
new file mode 100644
index 000000000000..afbad659cf07
--- /dev/null
+++ b/drivers/nfc/s3fwrn82/Kconfig
@@ -0,0 +1,15 @@ 
+# SPDX-License-Identifier: GPL-2.0-only
+config NFC_S3FWRN82
+	tristate
+
+config NFC_S3FWRN82_I2C
+	tristate "Samsung S3FWRN82 I2C support"
+	depends on NFC_NCI && I2C
+	select NFC_S3FWRN82
+	help
+	  This module adds support for an I2C interface to the S3FWRN82 chip.
+	  Select this if your platform is using the I2C bus.
+
+	  To compile this driver as a module, choose m here. The module will
+	  be called s3fwrn82_i2c.ko.
+	  Say N if unsure.
diff --git a/drivers/nfc/s3fwrn82/Makefile b/drivers/nfc/s3fwrn82/Makefile
new file mode 100644
index 000000000000..198e2cd85e91
--- /dev/null
+++ b/drivers/nfc/s3fwrn82/Makefile
@@ -0,0 +1,10 @@ 
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for Samsung S3FWRN82 NFC driver
+#
+
+s3fwrn82-objs = core.o
+s3fwrn82_i2c-objs = i2c.o
+
+obj-$(CONFIG_NFC_S3FWRN82) += s3fwrn82.o
+obj-$(CONFIG_NFC_S3FWRN82_I2C) += s3fwrn82_i2c.o
diff --git a/drivers/nfc/s3fwrn82/core.c b/drivers/nfc/s3fwrn82/core.c
new file mode 100644
index 000000000000..e01e02c758ab
--- /dev/null
+++ b/drivers/nfc/s3fwrn82/core.c
@@ -0,0 +1,133 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * NCI based driver for Samsung S3FWRN82 NFC chip
+ *
+ * Copyright (C) 2020 Samsung Electrnoics
+ * Bongsu Jeon <bongsu.jeon@samsung.com>
+ */
+
+#include <linux/module.h>
+#include <net/nfc/nci_core.h>
+
+#include "s3fwrn82.h"
+
+#define S3FWRN82_NFC_PROTOCOLS  (NFC_PROTO_JEWEL_MASK | \
+				NFC_PROTO_MIFARE_MASK | \
+				NFC_PROTO_FELICA_MASK | \
+				NFC_PROTO_ISO14443_MASK | \
+				NFC_PROTO_ISO14443_B_MASK | \
+				NFC_PROTO_ISO15693_MASK)
+
+static int s3fwrn82_nci_open(struct nci_dev *ndev)
+{
+	struct s3fwrn82_info *info = nci_get_drvdata(ndev);
+
+	if (s3fwrn82_get_mode(info) != S3FWRN82_MODE_COLD)
+		return -EBUSY;
+
+	s3fwrn82_set_mode(info, S3FWRN82_MODE_NCI);
+	s3fwrn82_set_wake(info, true);
+
+	return 0;
+}
+
+static int s3fwrn82_nci_close(struct nci_dev *ndev)
+{
+	struct s3fwrn82_info *info = nci_get_drvdata(ndev);
+
+	s3fwrn82_set_wake(info, false);
+	s3fwrn82_set_mode(info, S3FWRN82_MODE_COLD);
+
+	return 0;
+}
+
+static int s3fwrn82_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
+{
+	struct s3fwrn82_info *info = nci_get_drvdata(ndev);
+	int ret;
+
+	mutex_lock(&info->mutex);
+
+	if (s3fwrn82_get_mode(info) != S3FWRN82_MODE_NCI) {
+		mutex_unlock(&info->mutex);
+		return -EINVAL;
+	}
+
+	ret = s3fwrn82_write(info, skb);
+	if (ret < 0)
+		kfree_skb(skb);
+
+	mutex_unlock(&info->mutex);
+	return ret;
+}
+
+static struct nci_ops s3fwrn82_nci_ops = {
+	.open = s3fwrn82_nci_open,
+	.close = s3fwrn82_nci_close,
+	.send = s3fwrn82_nci_send,
+};
+
+int s3fwrn82_probe(struct nci_dev **ndev,
+		   void *phy_id,
+		   struct device *pdev,
+		   const struct s3fwrn82_phy_ops *phy_ops)
+{
+	struct s3fwrn82_info *info;
+	int ret;
+
+	info = devm_kzalloc(pdev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->phy_id = phy_id;
+	info->pdev = pdev;
+	info->phy_ops = phy_ops;
+	mutex_init(&info->mutex);
+
+	s3fwrn82_set_mode(info, S3FWRN82_MODE_COLD);
+
+	info->ndev = nci_allocate_device(&s3fwrn82_nci_ops, S3FWRN82_NFC_PROTOCOLS, 0, 0);
+	if (!info->ndev)
+		return -ENOMEM;
+
+	nci_set_parent_dev(info->ndev, pdev);
+	nci_set_drvdata(info->ndev, info);
+
+	ret = nci_register_device(info->ndev);
+	if (ret < 0) {
+		nci_free_device(info->ndev);
+		return ret;
+	}
+
+	*ndev = info->ndev;
+
+	return ret;
+}
+EXPORT_SYMBOL(s3fwrn82_probe);
+
+void s3fwrn82_remove(struct nci_dev *ndev)
+{
+	struct s3fwrn82_info *info = nci_get_drvdata(ndev);
+
+	s3fwrn82_set_mode(info, S3FWRN82_MODE_COLD);
+
+	nci_unregister_device(ndev);
+	nci_free_device(ndev);
+}
+EXPORT_SYMBOL(s3fwrn82_remove);
+
+int s3fwrn82_recv_frame(struct nci_dev *ndev, struct sk_buff *skb, enum s3fwrn82_mode mode)
+{
+	switch (mode) {
+	case S3FWRN82_MODE_NCI:
+		return nci_recv_frame(ndev, skb);
+	default:
+		kfree_skb(skb);
+		return -ENODEV;
+	}
+}
+EXPORT_SYMBOL(s3fwrn82_recv_frame);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Samsung S3FWRN82 NFC driver");
+MODULE_AUTHOR("Bongsu Jeon <bongsu.jeon@samsung.com>");
diff --git a/drivers/nfc/s3fwrn82/i2c.c b/drivers/nfc/s3fwrn82/i2c.c
new file mode 100644
index 000000000000..ea50c0165865
--- /dev/null
+++ b/drivers/nfc/s3fwrn82/i2c.c
@@ -0,0 +1,288 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * I2C Link Layer for Samsung S3FWRN82 NCI based Driver
+ *
+ * Copyright (C) 2020 Samsung Electrnoics
+ * Bongsu Jeon <bongsu.jeon@samsung.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/module.h>
+
+#include <net/nfc/nfc.h>
+
+#include "s3fwrn82.h"
+
+#define S3FWRN82_I2C_DRIVER_NAME "s3fwrn82_i2c"
+
+#define S3FWRN82_EN_WAIT_TIME 20
+
+struct s3fwrn82_i2c_phy {
+	struct i2c_client *i2c_dev;
+	struct nci_dev *ndev;
+
+	unsigned int gpio_en;
+	unsigned int gpio_fw_wake;
+
+	/* use this mutex for syncronization of phy */
+	struct mutex mutex;
+
+	enum s3fwrn82_mode mode;
+	unsigned int irq_skip:1;
+};
+
+static void s3fwrn82_i2c_set_wake(void *phy_id, bool wake)
+{
+	struct s3fwrn82_i2c_phy *phy = phy_id;
+
+	mutex_lock(&phy->mutex);
+	gpio_set_value(phy->gpio_fw_wake, wake);
+	if (wake)
+		msleep(S3FWRN82_EN_WAIT_TIME);
+	mutex_unlock(&phy->mutex);
+}
+
+static void s3fwrn82_i2c_set_mode(void *phy_id, enum s3fwrn82_mode mode)
+{
+	struct s3fwrn82_i2c_phy *phy = phy_id;
+
+	mutex_lock(&phy->mutex);
+
+	if (phy->mode == mode)
+		goto out;
+
+	phy->mode = mode;
+
+	gpio_set_value(phy->gpio_en, 1);
+	gpio_set_value(phy->gpio_fw_wake, 0);
+
+	if (mode != S3FWRN82_MODE_COLD) {
+		msleep(S3FWRN82_EN_WAIT_TIME);
+		gpio_set_value(phy->gpio_en, 0);
+		msleep(S3FWRN82_EN_WAIT_TIME / 2);
+	}
+
+	phy->irq_skip = true;
+
+out:
+	mutex_unlock(&phy->mutex);
+}
+
+static enum s3fwrn82_mode s3fwrn82_i2c_get_mode(void *phy_id)
+{
+	struct s3fwrn82_i2c_phy *phy = phy_id;
+	enum s3fwrn82_mode mode;
+
+	mutex_lock(&phy->mutex);
+
+	mode = phy->mode;
+
+	mutex_unlock(&phy->mutex);
+
+	return mode;
+}
+
+static int s3fwrn82_i2c_write(void *phy_id, struct sk_buff *skb)
+{
+	struct s3fwrn82_i2c_phy *phy = phy_id;
+	int ret;
+
+	mutex_lock(&phy->mutex);
+
+	phy->irq_skip = false;
+
+	ret = i2c_master_send(phy->i2c_dev, skb->data, skb->len);
+	mutex_unlock(&phy->mutex);
+
+	if (ret < 0)
+		return ret;
+
+	if (ret != skb->len)
+		return -EREMOTEIO;
+
+	return 0;
+}
+
+static const struct s3fwrn82_phy_ops i2c_phy_ops = {
+	.set_wake = s3fwrn82_i2c_set_wake,
+	.set_mode = s3fwrn82_i2c_set_mode,
+	.get_mode = s3fwrn82_i2c_get_mode,
+	.write = s3fwrn82_i2c_write,
+};
+
+static int s3fwrn82_i2c_read(struct s3fwrn82_i2c_phy *phy)
+{
+	struct sk_buff *skb;
+	size_t hdr_size;
+	size_t data_len;
+	char hdr[4];
+	int ret;
+
+	hdr_size = NCI_CTRL_HDR_SIZE;
+	ret = i2c_master_recv(phy->i2c_dev, hdr, hdr_size);
+	if (ret < 0)
+		return ret;
+
+	if (ret < hdr_size)
+		return -EBADMSG;
+
+	data_len = ((struct nci_ctrl_hdr *)hdr)->plen;
+
+	skb = alloc_skb(hdr_size + data_len, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_put_data(skb, hdr, hdr_size);
+
+	if (data_len == 0)
+		goto out;
+
+	ret = i2c_master_recv(phy->i2c_dev, skb_put(skb, data_len), data_len);
+	if (ret != data_len) {
+		kfree_skb(skb);
+		return -EBADMSG;
+	}
+
+out:
+	return s3fwrn82_recv_frame(phy->ndev, skb, phy->mode);
+}
+
+static irqreturn_t s3fwrn82_i2c_irq_thread_fn(int irq, void *phy_id)
+{
+	struct s3fwrn82_i2c_phy *phy = phy_id;
+
+	if (!phy || !phy->ndev) {
+		WARN_ON_ONCE(1);
+		return IRQ_NONE;
+	}
+
+	mutex_lock(&phy->mutex);
+
+	if (phy->irq_skip)
+		goto out;
+
+	switch (phy->mode) {
+	case S3FWRN82_MODE_NCI:
+		s3fwrn82_i2c_read(phy);
+		break;
+	case S3FWRN82_MODE_COLD:
+		break;
+	}
+
+out:
+	mutex_unlock(&phy->mutex);
+
+	return IRQ_HANDLED;
+}
+
+static int s3fwrn82_i2c_parse_dt(struct i2c_client *client)
+{
+	struct s3fwrn82_i2c_phy *phy = i2c_get_clientdata(client);
+	struct device_node *np = client->dev.of_node;
+
+	if (!np)
+		return -ENODEV;
+
+	phy->gpio_en = of_get_named_gpio(np, "en-gpios", 0);
+	if (!gpio_is_valid(phy->gpio_en))
+		return -ENODEV;
+
+	phy->gpio_fw_wake = of_get_named_gpio(np, "wake-gpios", 0);
+	if (!gpio_is_valid(phy->gpio_fw_wake))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int s3fwrn82_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	struct s3fwrn82_i2c_phy *phy;
+	int ret;
+
+	phy = devm_kzalloc(&client->dev, sizeof(*phy), GFP_KERNEL);
+	if (!phy)
+		return -ENOMEM;
+
+	mutex_init(&phy->mutex);
+	phy->mode = S3FWRN82_MODE_COLD;
+	phy->irq_skip = true;
+
+	phy->i2c_dev = client;
+	i2c_set_clientdata(client, phy);
+
+	ret = s3fwrn82_i2c_parse_dt(client);
+	if (ret < 0)
+		return ret;
+
+	ret = devm_gpio_request_one(&phy->i2c_dev->dev,
+				    phy->gpio_en,
+				    GPIOF_OUT_INIT_HIGH,
+				    "s3fwrn82_en");
+	if (ret < 0)
+		return ret;
+
+	ret = devm_gpio_request_one(&phy->i2c_dev->dev,
+				    phy->gpio_fw_wake,
+				    GPIOF_OUT_INIT_LOW,
+				    "s3fwrn82_fw_wake");
+	if (ret < 0)
+		return ret;
+
+	ret = s3fwrn82_probe(&phy->ndev, phy, &phy->i2c_dev->dev, &i2c_phy_ops);
+	if (ret < 0)
+		return ret;
+
+	ret = devm_request_threaded_irq(&client->dev,
+					phy->i2c_dev->irq,
+					NULL,
+					s3fwrn82_i2c_irq_thread_fn,
+					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					S3FWRN82_I2C_DRIVER_NAME,
+					phy);
+	if (ret)
+		s3fwrn82_remove(phy->ndev);
+
+	return ret;
+}
+
+static int s3fwrn82_i2c_remove(struct i2c_client *client)
+{
+	struct s3fwrn82_i2c_phy *phy = i2c_get_clientdata(client);
+
+	s3fwrn82_remove(phy->ndev);
+
+	return 0;
+}
+
+static const struct i2c_device_id s3fwrn82_i2c_id_table[] = {
+	{S3FWRN82_I2C_DRIVER_NAME, 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, s3fwrn82_i2c_id_table);
+
+static const struct of_device_id of_s3fwrn82_i2c_match[] = {
+	{ .compatible = "samsung,s3fwrn82-i2c", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, of_s3fwrn82_i2c_match);
+
+static struct i2c_driver s3fwrn82_i2c_driver = {
+	.driver = {
+		.name = S3FWRN82_I2C_DRIVER_NAME,
+		.of_match_table = of_match_ptr(of_s3fwrn82_i2c_match),
+	},
+	.probe = s3fwrn82_i2c_probe,
+	.remove = s3fwrn82_i2c_remove,
+	.id_table = s3fwrn82_i2c_id_table,
+};
+
+module_i2c_driver(s3fwrn82_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("I2C driver for Samsung S3FWRN82");
+MODULE_AUTHOR("Bongsu Jeon <bongsu.jeon@samsung.com>");
diff --git a/drivers/nfc/s3fwrn82/s3fwrn82.h b/drivers/nfc/s3fwrn82/s3fwrn82.h
new file mode 100644
index 000000000000..4c19d1fafde6
--- /dev/null
+++ b/drivers/nfc/s3fwrn82/s3fwrn82.h
@@ -0,0 +1,86 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * NCI based driver for Samsung S3FWRN82 NFC chip
+ *
+ * Copyright (C) 2020 Samsung Electrnoics
+ * Bongsu Jeon <bongsu.jeon@samsung.com>
+ */
+
+#ifndef __LOCAL_S3FWRN82_H_
+#define __LOCAL_S3FWRN82_H_
+
+#include <linux/nfc.h>
+
+#include <net/nfc/nci_core.h>
+
+enum s3fwrn82_mode {
+	S3FWRN82_MODE_COLD,
+	S3FWRN82_MODE_NCI,
+};
+
+struct s3fwrn82_phy_ops {
+	void (*set_wake)(void *id, bool sleep);
+	void (*set_mode)(void *id, enum s3fwrn82_mode);
+	enum s3fwrn82_mode (*get_mode)(void *id);
+	int (*write)(void *id, struct sk_buff *skb);
+};
+
+struct s3fwrn82_info {
+	struct nci_dev *ndev;
+	void *phy_id;
+	struct device *pdev;
+
+	const struct s3fwrn82_phy_ops *phy_ops;
+
+	/* use this mutex for syncronization of nci write */
+	struct mutex mutex;
+};
+
+static inline int s3fwrn82_set_mode(struct s3fwrn82_info *info,
+				    enum s3fwrn82_mode mode)
+{
+	if (!info->phy_ops->set_mode)
+		return -EOPNOTSUPP;
+
+	info->phy_ops->set_mode(info->phy_id, mode);
+
+	return 0;
+}
+
+static inline enum s3fwrn82_mode s3fwrn82_get_mode(struct s3fwrn82_info *info)
+{
+	if (!info->phy_ops->get_mode)
+		return -EOPNOTSUPP;
+
+	return info->phy_ops->get_mode(info->phy_id);
+}
+
+static inline int s3fwrn82_set_wake(struct s3fwrn82_info *info, bool wake)
+{
+	if (!info->phy_ops->set_wake)
+		return -EOPNOTSUPP;
+
+	info->phy_ops->set_wake(info->phy_id, wake);
+
+	return 0;
+}
+
+static inline int s3fwrn82_write(struct s3fwrn82_info *info, struct sk_buff *skb)
+{
+	if (!info->phy_ops->write)
+		return -EOPNOTSUPP;
+
+	return info->phy_ops->write(info->phy_id, skb);
+}
+
+int s3fwrn82_probe(struct nci_dev **ndev,
+		   void *phy_id,
+		   struct device *pdev,
+		   const struct s3fwrn82_phy_ops *phy_ops);
+void s3fwrn82_remove(struct nci_dev *ndev);
+
+int s3fwrn82_recv_frame(struct nci_dev *ndev,
+			struct sk_buff *skb,
+			enum s3fwrn82_mode mode);
+
+#endif /* __LOCAL_S3FWRN82_H_ */