android_kernel_samsung_hero.../drivers/nfc/bu80003gul.c
2016-08-17 16:41:52 +08:00

486 lines
12 KiB
C

/*
* BU80003GUL NFC RF Controller
*
* Copyright (C) 2015 Samsung Electronics Co.Ltd
* Author: Kyungmin Park <kmini.park@samsung.com>
*
* 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/wait.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/sec_nfc.h>
#include <linux/of_gpio.h>
#include <linux/miscdevice.h>
/*
* Security START
* #include <mach/scm.h>
* Needs to be changed as per the qualcomm's recommendation
* Security END
*/
#include <linux/regulator/consumer.h>
#include <linux/wakelock.h>
#define BU80003GUL_DEBUG
#include "bu80003gul.h"
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/i2c.h>
#ifdef BU80003GUL_DEBUG
#define EPC_DEBUG(fmt, args...) printk(KERN_DEBUG fmt, ## args)
#define EPC_INFO(fmt, args...) printk(KERN_INFO fmt, ## args)
#define EPC_ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
#else
#define EPC_DEBUG(fmt, args...)
#define EPC_INFO(fmt, args...)
#define EPC_ERR(fmt, args...)
#endif
#define I2C_ADDR (0x56 >> 1)
#define I2C_LOCK_ADDR 0x02
#define I2C_ANT_ADDR 0x01
/* extern unsigned int system_rev; Not using system_rev anymore */
#undef FEATURE_SET_DEFAULT_ANT_VAL
#ifdef CONFIG_NFC_EDC_TUNING
static unsigned char user_ant = 10;
#endif
static int felica_epc_ant_read(unsigned char *read_buff);
static int felica_epc_ant_write(char ant);
int felica_epc_reset(void);
static struct class *eeprom_class;
/*
* I2C device_id table
*/
static struct i2c_client *bu80003gul_i2c_client;
static const struct i2c_device_id bu80003gul_i2c_idtable[] = {
{BU80003GUL_I2C_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, bu80003gul_i2c_idtable);
/*
* I2C match table
*/
static struct of_device_id bu80003gul_i2c_match_table[] = {
{ .compatible = "felica,felica-i2c",},
{},
};
/*
* I2C driver
*/
static struct i2c_driver bu80003gul_i2c_driver = {
.probe = bu80003gul_i2c_probe,
.remove = bu80003gul_i2c_remove,
.id_table = bu80003gul_i2c_idtable,
.driver = {
.name = BU80003GUL_I2C_NAME,
.owner = THIS_MODULE,
.of_match_table = bu80003gul_i2c_match_table,
},
};
/* felica_ant device related */
static dev_t dev_id_felica_epc;
static struct cdev cdev_felica_epc;
static const struct file_operations fops_felica_epc = {
.owner = THIS_MODULE,
.open = felica_epc_open,
.read = felica_epc_read,
.write = felica_epc_write,
/* .unlocked_ioctl = felica_epc_ioctl, */
.release = felica_epc_close,
};
int felica_epc_set_lock_state(int state)
{
int ret;
unsigned char write_buff[2];
struct i2c_msg write_msgs[] = {
{
.addr = I2C_ADDR,
.flags = 0,
.len = 2,
.buf = NULL,
},
};
write_buff[0] = 0x02;
write_buff[1] = state;
write_msgs[0].buf = &write_buff[0];
ret = i2c_transfer(bu80003gul_i2c_client->adapter, write_msgs, 1);
if (ret < 0) {
EPC_ERR(" %s ERROR(i2c_transfer), ret=[%d]",
__func__, ret);
return -EIO;
}
return ret;
}
int felica_epc_reset(void)
{
int ret;
unsigned char write_buff[2];
struct i2c_msg write_msgs[] = {
{
.addr = I2C_ADDR,
.flags = 0,
.len = 2,
.buf = NULL,
},
};
write_buff[0] = 0x00;
write_buff[1] = 1;
write_msgs[0].buf = &write_buff[0];
ret = i2c_transfer(bu80003gul_i2c_client->adapter, write_msgs, 1);
if (ret < 0) {
EPC_ERR(" %s ERROR(i2c_transfer), ret=[%d]",
__func__, ret);
return -EIO;
}
return ret;
}
static int felica_epc_register(void)
{
struct device *device_felica_epc;
int ret;
dev_id_felica_epc = MKDEV(FELICA_EPC_MAJOR, FELICA_EPC_MINOR);
ret = alloc_chrdev_region(&dev_id_felica_epc, FELICA_EPC_BASEMINOR,
FELICA_EPC_MINOR_COUNT, FELICA_EPC_NAME);
if (ret < 0) {
EPC_ERR("[MFDD] %s ERROR(alloc_chrdev_region), ret=[%d]",
__func__, ret);
return ret;
}
cdev_init(&cdev_felica_epc, &fops_felica_epc);
ret = cdev_add(&cdev_felica_epc, dev_id_felica_epc, FELICA_EPC_MINOR_COUNT);
if (ret < 0) {
unregister_chrdev_region(dev_id_felica_epc, FELICA_EPC_MINOR_COUNT);
EPC_ERR("[MFDD] %s ERROR(cdev_add), ret=[%d]", __func__, ret);
return -EIO;
}
eeprom_class = class_create(THIS_MODULE, "felica_eeprom");
if (IS_ERR(eeprom_class)) {
EPC_ERR("[MFDD] %s ERROR(class_create)", __func__);
return PTR_ERR(eeprom_class);
}
device_felica_epc = device_create(eeprom_class, NULL,
dev_id_felica_epc, NULL,
FELICA_EPC_NAME);
if (IS_ERR(device_felica_epc)) {
cdev_del(&cdev_felica_epc);
unregister_chrdev_region(dev_id_felica_epc, FELICA_EPC_MINOR_COUNT);
EPC_ERR("[MFDD] %s ERROR(device_create)", __func__);
return -EINVAL;
}
EPC_DEBUG("[MFDD] %s END, major=[%d], minor=[%d]", __func__,
MAJOR(dev_id_felica_epc), MINOR(dev_id_felica_epc));
return 0;
}
static void felica_epc_deregister(void)
{
EPC_DEBUG("[MFDD] %s START", __func__);
device_destroy(eeprom_class, dev_id_felica_epc);
cdev_del(&cdev_felica_epc);
unregister_chrdev_region(dev_id_felica_epc, FELICA_EPC_MINOR_COUNT);
EPC_DEBUG("[MFDD] %s END", __func__);
return;
}
static int felica_epc_open(struct inode *inode, struct file *file)
{
if (felica_epc_set_lock_state(0x81) < 0)
EPC_ERR("[MFDD} Failed to UnLock the EEPROM.\n");
return 0;
}
static int felica_epc_close(struct inode *inode, struct file *file)
{
if (felica_epc_set_lock_state(0x80) < 0)
EPC_ERR("[MFDD} Failed to UnLock the EEPROM.\n");
return 0;
}
static int felica_epc_ant_read(unsigned char *read_buff)
{
int ret;
unsigned char address = I2C_ANT_ADDR;
struct i2c_msg read_msgs[] = {
{
.addr = I2C_ADDR,
.flags = 0,
.len = 1,
.buf = &address,
},
{
.addr = I2C_ADDR,
.flags = I2C_M_RD,
.len = 1,
.buf = read_buff,
},
};
if (bu80003gul_i2c_client == NULL) {
EPC_ERR("[MFDD] bu80003gul_i2c_client is NULL %s -EIO", __func__);
return -EIO;
}
*read_buff = 0;
ret = i2c_transfer(bu80003gul_i2c_client->adapter, &read_msgs[0], 1);
if (ret < 0) {
EPC_ERR("[MFDD] %s ERROR(i2c_transfer[0]), ret=[%d]",
__func__, ret);
return -EIO;
}
ret = i2c_transfer(bu80003gul_i2c_client->adapter, &read_msgs[1], 1);
if (ret < 0) {
EPC_ERR("[MFDD] %s ERROR(i2c_transfer[1]), ret=[%d]",
__func__, ret);
return -EIO;
}
pr_info("%s : ant : %d\n", __func__, *read_buff);
return 0;
}
static int felica_epc_ant_write(char ant)
{
int ret = 0;
char write_buff[2];
struct i2c_msg write_msgs[] = {
{
.addr = I2C_ADDR,
.flags = 0,
.len = 2,
.buf = NULL,
},
};
if (bu80003gul_i2c_client == NULL) {
EPC_ERR("[MFDD] bu80003gul_i2c_client is NULL %s", __func__);
return -EIO;
}
/* why is bit 7 set ? */
pr_info("%s : ant : %d\n", __func__, ant&0x7F);
write_buff[0] = I2C_ANT_ADDR;
write_buff[1] = ant;
write_msgs[0].buf = &write_buff[0];
ret = i2c_transfer(bu80003gul_i2c_client->adapter, &write_msgs[0], 1);
if (ret < 0) {
EPC_ERR("[MFDD] %s ERROR(i2c_transfer), ret=[%d]",
__func__, ret);
return -EIO;
}
return ret;
}
static ssize_t felica_epc_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
int ret;
unsigned char read_buff = 0;
ret = felica_epc_ant_read(&read_buff);
if (ret < 0) {
EPC_ERR("[MFDD] %s felica_epc_ant_read fail, ret=[%d]",
__func__, ret);
return -EFAULT;
}
if (len > sizeof(read_buff))
len = sizeof(read_buff);
ret = copy_to_user(buf, &read_buff, len);
if (ret != 0) {
EPC_ERR("[MFDD] %s ERROR(copy_to_user), ret=[%d]",
__func__, ret);
return -EFAULT;
}
*ppos += 1;
EPC_INFO("[MFDD] %s read=%d END\n", __func__, read_buff);
return 1; /* Only one byte at a time will be read. Hence return 1 on success. */
}
static ssize_t felica_epc_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
int ret;
char ant;
if (len > sizeof(ant))
len = sizeof(ant);
ret = copy_from_user(&ant, data, len);
if (ret != 0) {
EPC_ERR("[MFDD] %s ERROR(copy_from_user), ret=[%d]",
__func__, ret);
return -EFAULT;
}
ret = felica_epc_ant_write(ant);
if (ret < 0) {
EPC_ERR("[MFDD] %s felica_epc_ant_write fail, ret=[%d]",
__func__, ret);
return -EFAULT;
}
#ifdef CONFIG_NFC_EDC_TUNING
user_ant = ant & 0x7F;
#endif
EPC_INFO("[MFDD] %s END\n", __func__);
return 1;
}
#ifdef CONFIG_NFC_EDC_TUNING
static void felica_ant_tuning_work(struct work_struct *work)
{
int i, ret;
char ant;
ant = user_ant;
for (i = 0; i < 10; i++) {
if (ant_tune_req != 1)
break;
ant = ant > 2 ? ant - 2 : 1;
ret = felica_epc_ant_write(ant);
pr_info("%s : felica_tune_work ant: %d\n", __func__, ant);
msleep(1000);
}
ret = felica_epc_ant_write(user_ant);
ant_tune_req = 0;
}
static DECLARE_DELAYED_WORK(felica_ant_work, felica_ant_tuning_work);
int felica_ant_tuning(int evt)
{
pr_info("%s : felica_tune_req : %d, event: %d\n", __func__, ant_tune_req, evt);
ant_tune_req = evt;
if (evt == 1) {
schedule_delayed_work(&felica_ant_work, 0);
}
return 1;
}
EXPORT_SYMBOL(felica_ant_tuning);
#endif
/*
* Name : bu80003gul_i2c_probe
* Description : Probe the I2C device.
*/
static int bu80003gul_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *devid)
{
int ret;
bu80003gul_i2c_client = client;
if (!bu80003gul_i2c_client) {
EPC_ERR("[MFDD] %s ERROR(bu80003gul_i2c_client==NULL)",
__func__);
return -EINVAL;
}
ret = felica_epc_register();
if (ret < 0) {
EPC_ERR("[MFDD] %s Failed to register the device[ret:%d]\n",
__func__, ret);
}
#ifdef FEATURE_SET_DEFAULT_ANT_VAL
/* set default value temporarily */
ret = felica_epc_ant_write(FEATURE_SET_DEFAULT_ANT_VAL);
if (ret < 0) {
EPC_ERR("[MFDD] %s felica_epc_ant_write fail, ret=[%d]",
__func__, ret);
return -EFAULT;
}
#endif
#ifdef CONFIG_NFC_EDC_TUNING
ret = felica_epc_reset();
if (ret < 0) {
EPC_ERR("[MFDD] %s felica_epc_reset fail, ret=[%d]",
__func__, ret);
}
ret = felica_epc_ant_read(&user_ant);
if (ret < 0) {
EPC_ERR("[MFDD] %s felica_epc_ant_read fail, ret=[%d]",
__func__, ret);
user_ant = 10;
return -EFAULT;
}
pr_info("%s : felica_ant : %d\n", __func__, user_ant);
#endif
EPC_INFO("[MFDD] %s END", __func__);
return 0;
}
/*
* Name : bu80003gul_i2c_remove
* Description : Remove the I2C device.
*/
static int bu80003gul_i2c_remove(struct i2c_client *client)
{
bu80003gul_i2c_client = NULL;
EPC_DEBUG("[MFDD] %s END", __func__);
i2c_del_driver(&bu80003gul_i2c_driver);
felica_epc_deregister();
class_destroy(eeprom_class);
#ifdef CONFIG_NFC_EDC_TUNING
ant_tune_req = 0;
flush_delayed_work(&felica_ant_work);
#endif
return 0;
}
static int __init bu80003gul_init(void)
{
return i2c_add_driver(&bu80003gul_i2c_driver);
}
static void __exit bu80003gul_exit(void)
{
return i2c_del_driver(&bu80003gul_i2c_driver);
}
module_init(bu80003gul_init);
module_exit(bu80003gul_exit);
MODULE_DESCRIPTION("Samsung sec_nfc bu80003gul driver");
MODULE_LICENSE("GPL");