diff --git a/drivers/nfc/Android.mk b/drivers/nfc/Android.mk
new file mode 100644
index 000000000000..8c3da5b7f6c8
--- /dev/null
+++ b/drivers/nfc/Android.mk
@@ -0,0 +1,8 @@
+DLKM_DIR := motorola/kernel/modules
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := st21nfc.ko
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
+include $(DLKM_DIR)/AndroidKernelModule.mk
diff --git a/drivers/nfc/Kbuild b/drivers/nfc/Kbuild
new file mode 100644
index 000000000000..8e69b981bb3a
--- /dev/null
+++ b/drivers/nfc/Kbuild
@@ -0,0 +1,5 @@
+# add -Wall to try to catch everything we can.
+EXTRA_CFLAGS += -Wall
+EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
+
+obj-m += st21nfc.o
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
new file mode 100644
index 000000000000..62a13fd28500
--- /dev/null
+++ b/drivers/nfc/Makefile
@@ -0,0 +1,11 @@
+KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
+
+all:
+ $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
+
+modules_install:
+ $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
+
+clean:
+ $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
+
diff --git a/drivers/nfc/st21nfc.c b/drivers/nfc/st21nfc.c
new file mode 100644
index 000000000000..b7bd903836d0
--- /dev/null
+++ b/drivers/nfc/st21nfc.c
@@ -0,0 +1,692 @@
+/*
+ * Copyright (C) 2016 ST Microelectronics S.A.
+ * Copyright (C) 2010 Stollmann E+V GmbH
+ * Copyright (C) 2010 Trusted Logic S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#define MAX_BUFFER_SIZE 260
+
+#define DRIVER_VERSION "2.0.1"
+
+/* prototypes */
+static irqreturn_t st21nfc_dev_irq_handler(int irq, void *dev_id);
+/*
+ * The platform data member 'polarity_mode' defines
+ * how the wakeup pin is configured and handled.
+ * it can take the following values :
+ * IRQF_TRIGGER_RISING
+ * IRQF_TRIGGER_HIGH
+ */
+
+struct st21nfc_platform {
+ struct mutex read_mutex;
+ struct i2c_client *client;
+ unsigned int irq_gpio;
+ unsigned int reset_gpio;
+ unsigned int ena_gpio;
+ unsigned int polarity_mode;
+};
+
+static bool irqIsAttached;
+
+static bool device_open; /* Is device open? */
+
+struct st21nfc_dev {
+ wait_queue_head_t read_wq;
+ struct miscdevice st21nfc_device;
+ bool irq_enabled;
+ struct st21nfc_platform platform_data;
+ spinlock_t irq_enabled_lock;
+};
+
+static int st21nfc_loc_set_polaritymode(struct st21nfc_dev *st21nfc_dev,
+ int mode)
+{
+ struct i2c_client *client = st21nfc_dev->platform_data.client;
+ unsigned int irq_type;
+ int ret;
+
+ st21nfc_dev->platform_data.polarity_mode = mode;
+ /* setup irq_flags */
+ switch (mode) {
+ case IRQF_TRIGGER_RISING:
+ irq_type = IRQ_TYPE_EDGE_RISING;
+ break;
+ case IRQF_TRIGGER_HIGH:
+ irq_type = IRQ_TYPE_LEVEL_HIGH;
+ break;
+ default:
+ irq_type = IRQ_TYPE_EDGE_RISING;
+ break;
+ }
+ if (irqIsAttached) {
+ free_irq(client->irq, st21nfc_dev);
+ irqIsAttached = false;
+ }
+ ret = irq_set_irq_type(client->irq, irq_type);
+ if (ret) {
+ pr_err("%s : set_irq_type failed\n", __FILE__);
+ return -ENODEV;
+ }
+ /* request irq. the irq is set whenever the chip has data available
+ * for reading. it is cleared when all data has been read.
+ */
+ pr_debug("%s : requesting IRQ %d\n", __func__, client->irq);
+ st21nfc_dev->irq_enabled = true;
+
+ ret = request_irq(client->irq, st21nfc_dev_irq_handler,
+ st21nfc_dev->platform_data.polarity_mode,
+ client->name, st21nfc_dev);
+ if (!ret)
+ irqIsAttached = true;
+
+ return ret;
+}
+
+
+static void st21nfc_disable_irq(struct st21nfc_dev *st21nfc_dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&st21nfc_dev->irq_enabled_lock, flags);
+ if (st21nfc_dev->irq_enabled) {
+ pr_debug("%s : IRQ %d\n", __func__,
+ st21nfc_dev->platform_data.client->irq);
+ disable_irq_nosync(st21nfc_dev->platform_data.client->irq);
+ st21nfc_dev->irq_enabled = false;
+ }
+ spin_unlock_irqrestore(&st21nfc_dev->irq_enabled_lock, flags);
+}
+
+static irqreturn_t st21nfc_dev_irq_handler(int irq, void *dev_id)
+{
+ struct st21nfc_dev *st21nfc_dev = dev_id;
+
+ pr_debug("%s : enter\n", __func__);
+ st21nfc_disable_irq(st21nfc_dev);
+
+ /* Wake up waiting readers */
+ wake_up(&st21nfc_dev->read_wq);
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t st21nfc_dev_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct st21nfc_dev *st21nfc_dev = container_of(filp->private_data,
+ struct st21nfc_dev,
+ st21nfc_device);
+ char tmp[MAX_BUFFER_SIZE];
+ int ret;
+
+ if (count > MAX_BUFFER_SIZE)
+ count = MAX_BUFFER_SIZE;
+
+ pr_debug("%s : reading %zu bytes.\n", __func__, count);
+
+ mutex_lock(&st21nfc_dev->platform_data.read_mutex);
+
+ /* Read data */
+ ret = i2c_master_recv(st21nfc_dev->platform_data.client, tmp, count);
+ mutex_unlock(&st21nfc_dev->platform_data.read_mutex);
+
+ if (ret < 0) {
+ pr_err("%s: i2c_master_recv returned %d\n", __func__, ret);
+ return ret;
+ }
+ if (ret > count) {
+ pr_err("%s: received too many bytes from i2c (%d)\n",
+ __func__, ret);
+ return -EIO;
+ }
+ if (copy_to_user(buf, tmp, ret)) {
+ pr_warn("%s : failed to copy to user space\n", __func__);
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static ssize_t st21nfc_dev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct st21nfc_dev *st21nfc_dev;
+ char tmp[MAX_BUFFER_SIZE];
+ int ret = count;
+
+ st21nfc_dev = container_of(filp->private_data,
+ struct st21nfc_dev, st21nfc_device);
+ pr_debug("%s: st21nfc_dev ptr %p\n", __func__, st21nfc_dev);
+
+ if (count > MAX_BUFFER_SIZE)
+ count = MAX_BUFFER_SIZE;
+
+ if (copy_from_user(tmp, buf, count)) {
+ pr_err("%s : failed to copy from user space\n", __func__);
+ return -EFAULT;
+ }
+
+ pr_debug("%s : writing %zu bytes.\n", __func__, count);
+ /* Write data */
+ ret = i2c_master_send(st21nfc_dev->platform_data.client, tmp, count);
+ if (ret != count) {
+ pr_err("%s : i2c_master_send returned %d\n", __func__, ret);
+ ret = -EIO;
+ }
+ return ret;
+}
+
+static int st21nfc_dev_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ struct st21nfc_dev *st21nfc_dev = NULL;
+
+ if (device_open) {
+ ret = -EBUSY;
+ pr_err("%s : device already opened ret= %d\n", __func__, ret);
+ } else {
+ device_open = true;
+ st21nfc_dev = container_of(filp->private_data,
+ struct st21nfc_dev,
+ st21nfc_device);
+
+ pr_debug("%s : device_open = %d", __func__, device_open);
+ pr_debug("%s : %d,%d ", __func__, imajor(inode), iminor(inode));
+
+ pr_debug("%s: st21nfc_dev ptr %p\n", __func__, st21nfc_dev);
+
+ }
+ return ret;
+}
+
+
+static int st21nfc_release(struct inode *inode, struct file *file)
+{
+ device_open = false;
+ pr_debug("%s : device_open = %d\n", __func__, device_open);
+
+ return 0;
+}
+
+static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct st21nfc_dev *st21nfc_dev = container_of(filp->private_data,
+ struct st21nfc_dev,
+ st21nfc_device);
+
+ int ret = 0;
+
+ pr_debug("%s cmd=%d", __func__, cmd);
+
+ switch (cmd) {
+
+ case ST21NFC_SET_POLARITY_RISING:
+ pr_info(" ### ST21NFC_SET_POLARITY_RISING ###");
+ st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_RISING);
+ break;
+
+ case ST21NFC_SET_POLARITY_HIGH:
+ pr_info(" ### ST21NFC_SET_POLARITY_HIGH ###");
+ st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_HIGH);
+ break;
+
+ case ST21NFC_PULSE_RESET:
+ /* Double pulse is done to exit Quick boot mode.*/
+ pr_info("%s Double Pulse Request\n", __func__);
+ if (st21nfc_dev->platform_data.reset_gpio != 0) {
+ /* pulse low for 20 millisecs */
+ gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
+ 0);
+ msleep(20);
+ gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
+ 1);
+ msleep(10);
+ /* pulse low for 20 millisecs */
+ gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
+ 0);
+ msleep(20);
+ gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
+ 1);
+ pr_info("%s done Double Pulse Request\n", __func__);
+ }
+ break;
+
+ case ST21NFC_GET_WAKEUP:
+ /* deliver state of Wake_up_pin as return value of ioctl */
+ ret = gpio_get_value(st21nfc_dev->platform_data.irq_gpio);
+ /*
+ * Warning: depending on gpio_get_value implementation,
+ * it can returns a value different than 1 in case of high level
+ */
+ if (ret > 0)
+ ret = 1;
+ else
+ ret = 0;
+
+ pr_debug("%s get gpio result %d\n", __func__, ret);
+ break;
+
+ case ST21NFC_GET_POLARITY:
+ ret = st21nfc_dev->platform_data.polarity_mode;
+ pr_debug("%s get polarity %d\n", __func__, ret);
+ break;
+
+ case ST21NFC_RECOVERY:
+ /* For ST21NFCD usage only */
+ pr_info("%s Recovery Request\n", __func__);
+ if (st21nfc_dev->platform_data.reset_gpio != 0) {
+ /* pulse low for 20 millisecs */
+ gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
+ 0);
+ msleep(10);
+ /* during the reset, force IRQ OUT as DH output
+ *instead of input in normal usage
+ */
+ ret = gpio_direction_output(
+ st21nfc_dev->platform_data.irq_gpio, 1);
+ if (ret) {
+ pr_err("%s : gpio_direction_output failed\n",
+ __FILE__);
+ ret = -ENODEV;
+ break;
+ }
+ gpio_set_value(st21nfc_dev->platform_data.irq_gpio, 1);
+ msleep(10);
+ gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
+ 1);
+ pr_info("%s done Pulse Request\n", __func__);
+ }
+ msleep(20);
+ gpio_set_value(st21nfc_dev->platform_data.irq_gpio, 0);
+ msleep(20);
+ gpio_set_value(st21nfc_dev->platform_data.irq_gpio, 1);
+ msleep(20);
+ gpio_set_value(st21nfc_dev->platform_data.irq_gpio, 0);
+ msleep(20);
+ pr_info("%s Recovery procedure finished\n", __func__);
+ ret = gpio_direction_input(st21nfc_dev->platform_data.irq_gpio);
+ if (ret) {
+ pr_err("%s : gpio_direction_input failed\n", __FILE__);
+ ret = -ENODEV;
+ }
+ break;
+
+ default:
+ pr_err("%s bad ioctl %u\n", __func__, cmd);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static unsigned int st21nfc_poll(struct file *file, poll_table *wait)
+{
+ struct st21nfc_dev *st21nfc_dev = container_of(file->private_data,
+ struct st21nfc_dev,
+ st21nfc_device);
+ unsigned int mask = 0;
+ int pinlev = 0;
+
+ /* wait for Wake_up_pin == high */
+ poll_wait(file, &st21nfc_dev->read_wq, wait);
+
+ pinlev = gpio_get_value(st21nfc_dev->platform_data.irq_gpio);
+
+ if (pinlev > 0) {
+ pr_debug("%s return ready\n", __func__);
+ mask = POLLIN | POLLRDNORM; /* signal data avail */
+ st21nfc_disable_irq(st21nfc_dev);
+ } else {
+ /* Wake_up_pin is low. Activate ISR */
+ if (!st21nfc_dev->irq_enabled) {
+ pr_debug("%s enable irq\n", __func__);
+ st21nfc_dev->irq_enabled = true;
+ enable_irq(st21nfc_dev->platform_data.client->irq);
+ } else {
+ pr_debug("%s irq already enabled\n", __func__);
+ }
+ }
+ return mask;
+}
+
+static const struct file_operations st21nfc_dev_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = st21nfc_dev_read,
+ .write = st21nfc_dev_write,
+ .open = st21nfc_dev_open,
+ .poll = st21nfc_poll,
+ .release = st21nfc_release,
+
+ .unlocked_ioctl = st21nfc_dev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = st21nfc_dev_ioctl
+#endif
+};
+
+static ssize_t st21nfc_show_i2c_addr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (client != NULL)
+ return snprintf(buf, sizeof(unsigned short),
+ "0x%.2x\n", client->addr);
+ return 0;
+}
+
+static ssize_t st21nfc_change_i2c_addr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct st21nfc_dev *data = dev_get_drvdata(dev);
+ long new_addr = 0;
+
+ if (data != NULL && data->platform_data.client != NULL) {
+ if (!kstrtol(buf, 10, &new_addr)) {
+ mutex_lock(&data->platform_data.read_mutex);
+ data->platform_data.client->addr = new_addr;
+ mutex_unlock(&data->platform_data.read_mutex);
+ return count;
+ }
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static ssize_t st21nfc_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, strlen(DRIVER_VERSION), "%s\n", DRIVER_VERSION);
+}
+
+static DEVICE_ATTR(i2c_addr, S_IRUGO | S_IWUSR, st21nfc_show_i2c_addr,
+ st21nfc_change_i2c_addr);
+
+static DEVICE_ATTR(version, S_IRUGO, st21nfc_version, NULL);
+
+static struct attribute *st21nfc_attrs[] = {
+ &dev_attr_i2c_addr.attr,
+ &dev_attr_version.attr,
+ NULL,
+};
+
+static struct attribute_group st21nfc_attr_grp = {
+ .attrs = st21nfc_attrs,
+};
+
+#ifdef CONFIG_OF
+static int nfc_parse_dt(struct device *dev, struct st21nfc_platform_data *pdata)
+{
+ int r = 0;
+ struct device_node *np = dev->of_node;
+
+ np = of_find_compatible_node(NULL, NULL, "st,st21nfc");
+ if (IS_ERR_OR_NULL(np)) {
+ pr_err("[dsc]%s: cannot find compatible node \"%s\"",
+ __func__, "st,st21nfc");
+ return -ENODEV;
+ }
+
+ pdata->reset_gpio = of_get_named_gpio(np, "st,reset_gpio", 0);
+ if ((!gpio_is_valid(pdata->reset_gpio))) {
+ pr_err("[dsc]%s: fail to get reset_gpio\n", __func__);
+ return -EINVAL;
+ }
+ pdata->irq_gpio = of_get_named_gpio(np, "st,irq_gpio", 0);
+ if ((!gpio_is_valid(pdata->irq_gpio))) {
+ pr_err("[dsc]%s: fail to get irq_gpio\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata->polarity_mode = IRQF_TRIGGER_RISING;
+ pr_debug("[dsc]%s : get reset_gpio[%d], irq_gpio[%d],polarity_mode[%d]\n",
+ __func__, pdata->reset_gpio, pdata->irq_gpio, pdata->polarity_mode);
+ return r;
+}
+#else
+static int nfc_parse_dt(struct device *dev, struct st21nfc_platform_data *pdata)
+{
+ return 0;
+}
+#endif
+
+static int st21nfc_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret = 0;
+ struct st21nfc_platform_data *platform_data;
+ struct st21nfc_dev *st21nfc_dev;
+
+ pr_info("st21nfc_probe\n");
+
+ if (client->dev.of_node) {
+ platform_data = devm_kzalloc(&client->dev,
+ sizeof(struct st21nfc_platform_data), GFP_KERNEL);
+ if (!platform_data) {
+ dev_err(&client->dev,
+ "nfc-nci prob: Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ pr_info("%s : Parse st21nfc DTS\n", __func__);
+ ret = nfc_parse_dt(&client->dev, platform_data);
+ if (ret)
+ return ret;
+ } else {
+ platform_data = client->dev.platform_data;
+ pr_info("%s : No st21nfc DTS\n", __func__);
+ }
+
+ if (!platform_data)
+ return -EINVAL;
+
+ dev_dbg(&client->dev, "nfc-nci probe: %s, inside nfc-nci flags = %x\n",
+ __func__, client->flags);
+
+ if (platform_data == NULL) {
+ dev_err(&client->dev, "nfc-nci probe: failed\n");
+ return -ENODEV;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("%s : need I2C_FUNC_I2C\n", __func__);
+ return -ENODEV;
+ }
+
+ client->adapter->timeout = msecs_to_jiffies(3 * 10); /* 30ms */
+ client->adapter->retries = 0;
+
+ st21nfc_dev = kzalloc(sizeof(*st21nfc_dev), GFP_KERNEL);
+ if (st21nfc_dev == NULL) {
+ dev_err(&client->dev,
+ "failed to allocate memory for module data\n");
+ ret = -ENOMEM;
+ goto err_exit;
+ }
+
+ pr_debug("%s : dev_cb_addr %p\n", __func__, st21nfc_dev);
+
+ /* store for later use */
+ st21nfc_dev->platform_data.irq_gpio = platform_data->irq_gpio;
+ st21nfc_dev->platform_data.ena_gpio = platform_data->ena_gpio;
+ st21nfc_dev->platform_data.reset_gpio = platform_data->reset_gpio;
+ st21nfc_dev->platform_data.polarity_mode = platform_data->polarity_mode;
+ st21nfc_dev->platform_data.client = client;
+
+ ret = gpio_request(platform_data->irq_gpio, "irq_gpio");
+ if (ret) {
+ pr_err("%s : gpio_request failed\n", __FILE__);
+ ret = -ENODEV;
+ goto err_free_buffer;
+ }
+
+ ret = gpio_direction_input(platform_data->irq_gpio);
+ if (ret) {
+ pr_err("%s : gpio_direction_input failed\n", __FILE__);
+ ret = -ENODEV;
+ goto err_free_buffer;
+ }
+
+ /* initialize irqIsAttached variable */
+ irqIsAttached = false;
+
+ /* initialize device_open variable */
+ device_open = 0;
+
+ /* handle optional RESET */
+ if (platform_data->reset_gpio != 0) {
+ ret = gpio_request(platform_data->reset_gpio, "reset_gpio");
+ if (ret) {
+ pr_err("%s : reset gpio_request failed\n", __FILE__);
+ ret = -ENODEV;
+ goto err_free_buffer;
+ }
+ ret = gpio_direction_output(platform_data->reset_gpio, 1);
+ if (ret) {
+ pr_err("%s : reset gpio_direction_output failed\n",
+ __FILE__);
+ ret = -ENODEV;
+ goto err_free_buffer;
+ }
+ /* low active */
+ gpio_set_value(st21nfc_dev->platform_data.reset_gpio, 1);
+ }
+
+ client->irq = gpio_to_irq(platform_data->irq_gpio);
+
+ enable_irq_wake(client->irq);
+ /* init mutex and queues */
+ init_waitqueue_head(&st21nfc_dev->read_wq);
+ mutex_init(&st21nfc_dev->platform_data.read_mutex);
+ spin_lock_init(&st21nfc_dev->irq_enabled_lock);
+ st21nfc_dev->st21nfc_device.minor = MISC_DYNAMIC_MINOR;
+ st21nfc_dev->st21nfc_device.name = "st21nfc";
+ st21nfc_dev->st21nfc_device.fops = &st21nfc_dev_fops;
+ st21nfc_dev->st21nfc_device.parent = &client->dev;
+
+ i2c_set_clientdata(client, st21nfc_dev);
+ ret = misc_register(&st21nfc_dev->st21nfc_device);
+ if (ret) {
+ pr_err("%s : misc_register failed\n", __FILE__);
+ goto err_misc_register;
+ }
+
+ if (sysfs_create_group(&client->dev.kobj, &st21nfc_attr_grp)) {
+ pr_err("%s : sysfs_create_group failed\n", __FILE__);
+ goto err_request_irq_failed;
+ }
+ st21nfc_disable_irq(st21nfc_dev);
+ pr_info("%s:successfully\n", __func__);
+
+ return 0;
+
+err_request_irq_failed:
+ misc_deregister(&st21nfc_dev->st21nfc_device);
+err_misc_register:
+ mutex_destroy(&st21nfc_dev->platform_data.read_mutex);
+err_free_buffer:
+ kfree(st21nfc_dev);
+err_exit:
+ gpio_free(platform_data->irq_gpio);
+ if (platform_data->ena_gpio != 0)
+ gpio_free(platform_data->ena_gpio);
+ return ret;
+}
+
+static int st21nfc_remove(struct i2c_client *client)
+{
+ struct st21nfc_dev *st21nfc_dev;
+
+ st21nfc_dev = i2c_get_clientdata(client);
+ free_irq(client->irq, st21nfc_dev);
+ misc_deregister(&st21nfc_dev->st21nfc_device);
+ mutex_destroy(&st21nfc_dev->platform_data.read_mutex);
+ gpio_free(st21nfc_dev->platform_data.irq_gpio);
+ if (st21nfc_dev->platform_data.ena_gpio != 0)
+ gpio_free(st21nfc_dev->platform_data.ena_gpio);
+ kfree(st21nfc_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id st21nfc_id[] = {
+ {"st21nfc", 0},
+ {}
+};
+
+static const struct of_device_id st21nfc_of_match[] = {
+ { .compatible = "st,st21nfc",},
+ {}
+};
+
+static struct i2c_driver st21nfc_driver = {
+ .id_table = st21nfc_id,
+ .driver = {
+ .name = "st21nfc",
+ .owner = THIS_MODULE,
+ .of_match_table = st21nfc_of_match,
+ },
+ .probe = st21nfc_probe,
+ .remove = st21nfc_remove,
+};
+
+/*
+ * module load/unload record keeping
+ */
+
+static int __init st21nfc_dev_init(void)
+{
+ pr_info("%s: Loading st21nfc driver\n", __func__);
+ return i2c_add_driver(&st21nfc_driver);
+}
+
+module_init(st21nfc_dev_init);
+
+static void __exit st21nfc_dev_exit(void)
+{
+ pr_debug("Unloading st21nfc driver\n");
+ i2c_del_driver(&st21nfc_driver);
+}
+
+module_exit(st21nfc_dev_exit);
+
+MODULE_AUTHOR("STMicroelectronics");
+MODULE_DESCRIPTION("NFC ST21NFC driver");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/include/linux/st21nfc.h b/include/linux/st21nfc.h
new file mode 100644
index 000000000000..309a28eae643
--- /dev/null
+++ b/include/linux/st21nfc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2013 ST Microelectronics S.A.
+ * Copyright (C) 2010 Stollmann E+V GmbH
+ * 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.
+ *
+ */
+
+#define ST21NFC_MAGIC 0xEA
+
+#define ST21NFC_NAME "st21nfc"
+/*
+ * ST21NFC power control via ioctl
+ * ST21NFC_GET_WAKEUP : poll gpio-level for Wakeup pin
+ */
+#define ST21NFC_GET_WAKEUP _IOR(ST21NFC_MAGIC, 0x01, unsigned int)
+#define ST21NFC_PULSE_RESET _IOR(ST21NFC_MAGIC, 0x02, unsigned int)
+#define ST21NFC_SET_POLARITY_RISING _IOR(ST21NFC_MAGIC, 0x03, unsigned int)
+#define ST21NFC_SET_POLARITY_HIGH _IOR(ST21NFC_MAGIC, 0x05, unsigned int)
+#define ST21NFC_GET_POLARITY _IOR(ST21NFC_MAGIC, 0x07, unsigned int)
+#define ST21NFC_RECOVERY _IOR(ST21NFC_MAGIC, 0x08, unsigned int)
+
+
+struct st21nfc_platform_data {
+ unsigned int irq_gpio;
+ unsigned int ena_gpio;
+ unsigned int reset_gpio;
+ unsigned int polarity_mode;
+};