aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc/pn65n.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nfc/pn65n.c')
-rw-r--r--drivers/nfc/pn65n.c496
1 files changed, 0 insertions, 496 deletions
diff --git a/drivers/nfc/pn65n.c b/drivers/nfc/pn65n.c
deleted file mode 100644
index 4754c55..0000000
--- a/drivers/nfc/pn65n.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/i2c.h>
-#include <linux/irq.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/miscdevice.h>
-#include <linux/spinlock.h>
-#include <linux/nfc/pn65n.h>
-
-#define MAX_BUFFER_SIZE 512
-
-#define NXP_KR_READ_IRQ_MODIFY
-
-#ifdef NXP_KR_READ_IRQ_MODIFY
-static bool do_reading;
-static bool cancle_read;
-#endif
-
-#define NFC_DEBUG 0
-#define MAX_TRY_I2C_READ 10
-#define I2C_ADDR_READ_L 0x51
-#define I2C_ADDR_READ_H 0x57
-
-
-struct pn65n_dev {
- wait_queue_head_t read_wq;
- struct mutex read_mutex;
- struct i2c_client *client;
- struct miscdevice pn65n_device;
- unsigned int ven_gpio;
- unsigned int firm_gpio;
- unsigned int irq_gpio;
- atomic_t irq_enabled;
-};
-
-static irqreturn_t pn65n_dev_irq_handler(int irq, void *dev_id)
-{
- struct pn65n_dev *pn65n_dev = dev_id;
-
- if (!gpio_get_value(pn65n_dev->irq_gpio)) {
-#if NFC_DEBUG
- pr_err("%s, irq_gpio = %d\n", __func__,
- gpio_get_value(pn65n_dev->irq_gpio));
-#endif
- return IRQ_HANDLED;
- }
-
-#ifdef NXP_KR_READ_IRQ_MODIFY
- do_reading = true;
-#endif
- /* Wake up waiting readers */
- wake_up(&pn65n_dev->read_wq);
-
-#if NFC_DEBUG
- pr_info("%s, IRQ_HANDLED\n", __func__);
-#endif
-
- return IRQ_HANDLED;
-}
-
-static ssize_t pn65n_dev_read(struct file *filp, char __user *buf,
- size_t count, loff_t *offset)
-{
- struct pn65n_dev *pn65n_dev = filp->private_data;
- char tmp[MAX_BUFFER_SIZE];
- int ret = 0;
- int readingWatchdog = 0;
-
- if (count > MAX_BUFFER_SIZE)
- count = MAX_BUFFER_SIZE;
-
-#if NFC_DEBUG
- dev_info(&pn65n_dev->client->dev, "%s : reading %zu bytes. irq=%s\n",
- __func__, count,
- gpio_get_value(pn65n_dev->irq_gpio) ? "1" : "0");
- dev_info(&pn65n_dev->client->dev, "pn65n : + r\n");
-#endif
-
- mutex_lock(&pn65n_dev->read_mutex);
-
-wait_irq:
- if (!gpio_get_value(pn65n_dev->irq_gpio)) {
-#ifdef NXP_KR_READ_IRQ_MODIFY
- do_reading = false;
-#endif
- if (filp->f_flags & O_NONBLOCK) {
- dev_info(&pn65n_dev->client->dev, "%s : O_NONBLOCK\n",
- __func__);
- ret = -EAGAIN;
- goto fail;
- }
-#if NFC_DEBUG
- dev_info(&pn65n_dev->client->dev,
- "wait_event_interruptible : in\n");
-#endif
-
-#ifdef NXP_KR_READ_IRQ_MODIFY
- ret = wait_event_interruptible(pn65n_dev->read_wq,
- do_reading);
-#else
- ret = wait_event_interruptible(pn65n_dev->read_wq,
- gpio_get_value(pn65n_dev->irq_gpio));
-#endif
-
-#if NFC_DEBUG
- dev_info(&pn65n_dev->client->dev,
- "wait_event_interruptible : out\n");
-#endif
-
-#ifdef NXP_KR_READ_IRQ_MODIFY
- if (cancle_read == true) {
- cancle_read = false;
- ret = -1;
- goto fail;
- }
-#endif
-
- if (ret)
- goto fail;
- }
-
- /* Read data */
- ret = i2c_master_recv(pn65n_dev->client, tmp, count);
-
- /* If bad frame(from 0x51 to 0x57) is received from pn65n,
- * we need to read again after waiting that IRQ is down.
- * if data is not ready, pn65n will send from 0x51 to 0x57. */
- if ((I2C_ADDR_READ_L <= tmp[0] && tmp[0] <= I2C_ADDR_READ_H)
- && readingWatchdog < MAX_TRY_I2C_READ) {
- pr_warn("%s: data is not ready yet.data = 0x%x, cnt=%d\n",
- __func__, tmp[0], readingWatchdog);
- usleep_range(2000, 2000); /* sleep 2ms to wait for IRQ */
- readingWatchdog++;
- goto wait_irq;
- }
-
- mutex_unlock(&pn65n_dev->read_mutex);
-
- if (ret < 0) {
- dev_err(&pn65n_dev->client->dev,
- "%s: i2c_master_recv returned %d\n",
- __func__, ret);
- return ret;
- }
- if (ret > count) {
- dev_err(&pn65n_dev->client->dev,
- "%s: received too many bytes from i2c (%d)\n",
- __func__, ret);
- return -EIO;
- }
-
- if (copy_to_user(buf, tmp, ret)) {
- dev_err(&pn65n_dev->client->dev,
- "%s : failed to copy to user space\n",
- __func__);
- return -EFAULT;
- }
- return ret;
-
-fail:
- mutex_unlock(&pn65n_dev->read_mutex);
- return ret;
-}
-
-static ssize_t pn65n_dev_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *offset)
-{
- struct pn65n_dev *pn65n_dev;
- char tmp[MAX_BUFFER_SIZE];
- int ret = 0, retry = 2;
-#if NFC_DEBUG
- int i = 0;
-#endif
-
- pn65n_dev = filp->private_data;
-
-#if NFC_DEBUG
- dev_info(&pn65n_dev->client->dev, "pn65n : + w\n");
- for (i = 0; i < count; i++)
- dev_info(&pn65n_dev->client->dev, "buf[%d] = 0x%x\n",
- i, buf[i]);
-#endif
-
- if (count > MAX_BUFFER_SIZE)
- count = MAX_BUFFER_SIZE;
-
- if (copy_from_user(tmp, buf, count)) {
- dev_err(&pn65n_dev->client->dev,
- "%s : failed to copy from user space\n", __func__);
- return -EFAULT;
- }
-#if NFC_DEBUG
- dev_info(&pn65n_dev->client->dev, "%s : writing %zu bytes.\n", __func__,
- count);
-#endif
- /* Write data */
- do {
- retry--;
- ret = i2c_master_send(pn65n_dev->client, tmp, count);
- if (ret == count)
- break;
- usleep_range(6000, 10000); /* Retry, chip was in standby */
-#if NFC_DEBUG
- dev_info(&pn65n_dev->client->dev, "retry = %d\n", retry);
-#endif
- } while (retry);
-
-#if NFC_DEBUG
- dev_info(&pn65n_dev->client->dev, "pn65n : - w\n");
-#endif
-
- if (ret != count) {
- dev_err(&pn65n_dev->client->dev,
- "%s : i2c_master_send returned %d, %d\n",
- __func__, ret, retry);
- ret = -EIO;
- }
-
- return ret;
-}
-
-static int pn65n_dev_open(struct inode *inode, struct file *filp)
-{
- struct pn65n_dev *pn65n_dev = container_of(filp->private_data,
- struct pn65n_dev,
- pn65n_device);
-
- filp->private_data = pn65n_dev;
-
- dev_info(&pn65n_dev->client->dev, "%s : %d,%d\n", __func__,
- imajor(inode), iminor(inode));
-
- return 0;
-}
-
-static long pn65n_dev_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct pn65n_dev *pn65n_dev = filp->private_data;
-
- switch (cmd) {
- case PN65N_SET_PWR:
- if (arg == 2) {
- /* power on with firmware download (requires hw reset)
- */
- gpio_set_value(pn65n_dev->ven_gpio, 1);
- gpio_set_value(pn65n_dev->firm_gpio, 1);
- usleep_range(10000, 10000);
- gpio_set_value(pn65n_dev->ven_gpio, 0);
- usleep_range(10000, 10000);
- gpio_set_value(pn65n_dev->ven_gpio, 1);
- usleep_range(10000, 10000);
- if (atomic_read(&pn65n_dev->irq_enabled) == 0) {
- atomic_set(&pn65n_dev->irq_enabled, 1);
- enable_irq(pn65n_dev->client->irq);
- enable_irq_wake(pn65n_dev->client->irq);
- }
- dev_info(&pn65n_dev->client->dev,
- "%s power on with firmware, irq=%d\n",
- __func__,
- atomic_read(&pn65n_dev->irq_enabled));
- } else if (arg == 1) {
- /* power on */
- gpio_set_value(pn65n_dev->firm_gpio, 0);
- gpio_set_value(pn65n_dev->ven_gpio, 1);
- usleep_range(10000, 10000);
- if (atomic_read(&pn65n_dev->irq_enabled) == 0) {
- atomic_set(&pn65n_dev->irq_enabled, 1);
- enable_irq(pn65n_dev->client->irq);
- enable_irq_wake(pn65n_dev->client->irq);
- }
- dev_info(&pn65n_dev->client->dev,
- "%s power on, irq=%d\n", __func__,
- atomic_read(&pn65n_dev->irq_enabled));
- } else if (arg == 0) {
- /* power off */
- if (atomic_read(&pn65n_dev->irq_enabled) == 1) {
- disable_irq_wake(pn65n_dev->client->irq);
- disable_irq_nosync(pn65n_dev->client->irq);
- atomic_set(&pn65n_dev->irq_enabled, 0);
- }
- dev_info(&pn65n_dev->client->dev, "%s power off, irq=%d\n",
- __func__,
- atomic_read(&pn65n_dev->irq_enabled));
- gpio_set_value(pn65n_dev->firm_gpio, 0);
- gpio_set_value(pn65n_dev->ven_gpio, 0);
- usleep_range(10000, 10000);
-#ifdef NXP_KR_READ_IRQ_MODIFY
- } else if (arg == 3) {
- pr_info("%s Read Cancle\n", __func__);
- cancle_read = true;
- do_reading = true;
- wake_up(&pn65n_dev->read_wq);
-#endif
- } else {
- dev_err(&pn65n_dev->client->dev, "%s bad arg %lu\n",
- __func__, arg);
- return -EINVAL;
- }
- break;
- default:
- dev_err(&pn65n_dev->client->dev, "%s bad ioctl %u\n", __func__,
- cmd);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const struct file_operations pn65n_dev_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = pn65n_dev_read,
- .write = pn65n_dev_write,
- .open = pn65n_dev_open,
- .unlocked_ioctl = pn65n_dev_ioctl,
-};
-
-static int pn65n_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int ret;
- struct pn65n_i2c_platform_data *platform_data;
- struct pn65n_dev *pn65n_dev;
-
- platform_data = client->dev.platform_data;
-
- if (platform_data == NULL) {
- dev_err(&client->dev, "%s : nfc probe fail\n", __func__);
- return -ENODEV;
- }
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev, "%s : need I2C_FUNC_I2C\n", __func__);
- return -ENODEV;
- }
-
- ret = gpio_request(platform_data->irq_gpio, "nfc_int");
- if (ret)
- return -ENODEV;
- ret = gpio_request(platform_data->ven_gpio, "nfc_ven");
- if (ret)
- goto err_ven;
- ret = gpio_request(platform_data->firm_gpio, "nfc_firm");
- if (ret)
- goto err_firm;
-
- pn65n_dev = kzalloc(sizeof(*pn65n_dev), GFP_KERNEL);
- if (pn65n_dev == NULL) {
- dev_err(&client->dev,
- "failed to allocate memory for module data\n");
- ret = -ENOMEM;
- goto err_exit;
- }
-
- dev_info(&client->dev, "%s : IRQ num %d\n", __func__, client->irq);
-
- pn65n_dev->irq_gpio = platform_data->irq_gpio;
- pn65n_dev->ven_gpio = platform_data->ven_gpio;
- pn65n_dev->firm_gpio = platform_data->firm_gpio;
- pn65n_dev->client = client;
-
- /* init mutex and queues */
- init_waitqueue_head(&pn65n_dev->read_wq);
- mutex_init(&pn65n_dev->read_mutex);
-
- pn65n_dev->pn65n_device.minor = MISC_DYNAMIC_MINOR;
- pn65n_dev->pn65n_device.name = "pn544";
- pn65n_dev->pn65n_device.fops = &pn65n_dev_fops;
-
- ret = misc_register(&pn65n_dev->pn65n_device);
- if (ret) {
- dev_err(&client->dev, "%s : misc_register failed. ret = %d\n",
- __FILE__, ret);
- goto err_misc_register;
- }
-
- i2c_set_clientdata(client, pn65n_dev);
- /* request irq. the irq is set whenever the chip has data available
- * for reading. it is cleared when all data has been read.
- */
- dev_info(&pn65n_dev->client->dev, "%s : requesting IRQ %d\n", __func__,
- client->irq);
- ret = gpio_direction_input(pn65n_dev->irq_gpio);
- if (ret) {
- dev_err(&client->dev, "%s : gpio_direction_input failed. ret = %d\n",
- __FILE__, ret);
- goto err_request_irq_failed;
- }
-
- ret = request_irq(client->irq, pn65n_dev_irq_handler,
- IRQF_TRIGGER_RISING, "pn65n", pn65n_dev);
- if (ret) {
- dev_err(&client->dev, "request_irq failed. ret = %d\n", ret);
- goto err_request_irq_failed;
- }
- disable_irq_nosync(pn65n_dev->client->irq);
- atomic_set(&pn65n_dev->irq_enabled, 0);
-
- return 0;
-
-err_request_irq_failed:
- misc_deregister(&pn65n_dev->pn65n_device);
-err_misc_register:
- mutex_destroy(&pn65n_dev->read_mutex);
- kfree(pn65n_dev);
-err_exit:
- gpio_free(platform_data->firm_gpio);
-err_firm:
- gpio_free(platform_data->ven_gpio);
-err_ven:
- gpio_free(platform_data->irq_gpio);
- return ret;
-}
-
-static int pn65n_remove(struct i2c_client *client)
-{
- struct pn65n_dev *pn65n_dev;
-
- pn65n_dev = i2c_get_clientdata(client);
- free_irq(client->irq, pn65n_dev);
- misc_deregister(&pn65n_dev->pn65n_device);
- mutex_destroy(&pn65n_dev->read_mutex);
- gpio_free(pn65n_dev->irq_gpio);
- gpio_free(pn65n_dev->ven_gpio);
- gpio_free(pn65n_dev->firm_gpio);
- kfree(pn65n_dev);
-
- return 0;
-}
-
-static const struct i2c_device_id pn65n_id[] = {
- { "pn65n", 0 },
- { }
-};
-
-static struct i2c_driver pn65n_driver = {
- .id_table = pn65n_id,
- .probe = pn65n_probe,
- .remove = pn65n_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "pn65n",
- },
-};
-
-/*
- * module load/unload record keeping
- */
-
-static int __init pn65n_dev_init(void)
-{
- pr_info("Loading pn65n driver\n");
- return i2c_add_driver(&pn65n_driver);
-}
-module_init(pn65n_dev_init);
-
-static void __exit pn65n_dev_exit(void)
-{
- pr_info("Unloading pn65n driver\n");
- i2c_del_driver(&pn65n_driver);
-}
-module_exit(pn65n_dev_exit);
-
-MODULE_AUTHOR("Sylvain Fonteneau");
-MODULE_DESCRIPTION("NFC pn65n driver");
-MODULE_LICENSE("GPL");