mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 08:36:12 -04:00
Update driver version to 2.0.4
Support new ioctl command and compatibale with old one Add interrupt control to solve int can not wake up system issue Change-Id: I3229f343c359ec6075739ea3e2d30554b07052a4 Signed-off-by: Ningkai Zhuang <zhuangnk1@lenovo.com> Reviewed-on: https://gerrit.mot.com/1481162 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Tao Sun <suntao2@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
86d76624d7
commit
a25f827835
2 changed files with 239 additions and 119 deletions
|
|
@ -42,8 +42,9 @@
|
|||
|
||||
|
||||
#define MAX_BUFFER_SIZE 260
|
||||
#define WAKEUP_SRC_TIMEOUT (8000)
|
||||
|
||||
#define DRIVER_VERSION "2.0.1"
|
||||
#define DRIVER_VERSION "2.0.4"
|
||||
|
||||
/* prototypes */
|
||||
static irqreturn_t st21nfc_dev_irq_handler(int irq, void *dev_id);
|
||||
|
|
@ -73,6 +74,7 @@ struct st21nfc_dev {
|
|||
wait_queue_head_t read_wq;
|
||||
struct miscdevice st21nfc_device;
|
||||
bool irq_enabled;
|
||||
bool irq_wake_up;
|
||||
struct st21nfc_platform platform_data;
|
||||
spinlock_t irq_enabled_lock;
|
||||
/* CLK control */
|
||||
|
|
@ -93,23 +95,22 @@ static int st_clock_select(struct st21nfc_dev *st21nfc_dev)
|
|||
|
||||
st21nfc_dev->s_clk = clk_get(&st21nfc_dev->platform_data.client->dev, "nfc_ref_clk");
|
||||
|
||||
/* if s_clk NULL we assume external crystal and dont fail */
|
||||
if (IS_ERR_OR_NULL(st21nfc_dev->s_clk)) {
|
||||
st21nfc_dev->s_clk = NULL;
|
||||
/* if NULL we assume external crystal and dont fail */
|
||||
if ((st21nfc_dev->s_clk == NULL) || IS_ERR(st21nfc_dev->s_clk))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!st21nfc_dev->clk_run) {
|
||||
if (st21nfc_dev->clk_run == false)
|
||||
r = clk_prepare_enable(st21nfc_dev->s_clk);
|
||||
if (r) {
|
||||
// error
|
||||
r = -1;
|
||||
} else {
|
||||
dev_dbg(&st21nfc_dev->platform_data.client->dev,"st21nfc clk enabled\n");
|
||||
st21nfc_dev->clk_run = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (r)
|
||||
goto err_clk;
|
||||
|
||||
st21nfc_dev->clk_run = true;
|
||||
|
||||
return r;
|
||||
|
||||
err_clk:
|
||||
r = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -118,16 +119,24 @@ static int st_clock_select(struct st21nfc_dev *st21nfc_dev)
|
|||
*/
|
||||
static int st_clock_deselect(struct st21nfc_dev *st21nfc_dev)
|
||||
{
|
||||
/* if s_clk is NULL we assume external crystal and dont fail */
|
||||
if (st21nfc_dev->s_clk && st21nfc_dev->clk_run) {
|
||||
clk_disable_unprepare(st21nfc_dev->s_clk);
|
||||
st21nfc_dev->clk_run = false;
|
||||
dev_dbg(&st21nfc_dev->platform_data.client->dev,"st21nfc clk disabled\n");
|
||||
}
|
||||
int r = -1;
|
||||
|
||||
return 0;
|
||||
/* if NULL we assume external crystal and dont fail */
|
||||
if ((st21nfc_dev->s_clk == NULL) || IS_ERR(st21nfc_dev->s_clk))
|
||||
return 0;
|
||||
|
||||
if ((st21nfc_dev->s_clk != NULL) && !IS_ERR(st21nfc_dev->s_clk)) {
|
||||
if (st21nfc_dev->clk_run == true) {
|
||||
clk_disable_unprepare(st21nfc_dev->s_clk);
|
||||
st21nfc_dev->clk_run = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void st21nfc_disable_irq(struct st21nfc_dev *st21nfc_dev);
|
||||
|
||||
static int st21nfc_loc_set_polaritymode(struct st21nfc_dev *st21nfc_dev,
|
||||
int mode)
|
||||
{
|
||||
|
|
@ -164,32 +173,52 @@ static int st21nfc_loc_set_polaritymode(struct st21nfc_dev *st21nfc_dev,
|
|||
st21nfc_dev->irq_enabled = true;
|
||||
|
||||
ret = request_irq(client->irq, st21nfc_dev_irq_handler,
|
||||
st21nfc_dev->platform_data.polarity_mode,
|
||||
st21nfc_dev->platform_data.polarity_mode|IRQF_NO_SUSPEND,
|
||||
client->name, st21nfc_dev);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
irqIsAttached = true;
|
||||
st21nfc_disable_irq(st21nfc_dev);
|
||||
}
|
||||
|
||||
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("IRQ %d\n", st21nfc_dev->platform_data.client->irq);
|
||||
pr_debug("IRQ %d\n",
|
||||
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 void st21nfc_enable_irq(struct st21nfc_dev *st21nfc_dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&st21nfc_dev->irq_enabled_lock, flags);
|
||||
if (!st21nfc_dev->irq_enabled) {
|
||||
st21nfc_dev->irq_enabled = true;
|
||||
enable_irq(st21nfc_dev->platform_data.client->irq);
|
||||
|
||||
}
|
||||
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("enter\n");
|
||||
if (device_may_wakeup(&st21nfc_dev->platform_data.client->dev))
|
||||
pm_wakeup_event(&st21nfc_dev->platform_data.client->dev,
|
||||
WAKEUP_SRC_TIMEOUT);
|
||||
st21nfc_disable_irq(st21nfc_dev);
|
||||
|
||||
/* Wake up waiting readers */
|
||||
|
|
@ -198,6 +227,7 @@ static irqreturn_t st21nfc_dev_irq_handler(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t st21nfc_dev_read(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *offset)
|
||||
{
|
||||
|
|
@ -236,12 +266,15 @@ static ssize_t st21nfc_dev_read(struct file *filp, char __user *buf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define MAX_RETRY_COUNT 3
|
||||
|
||||
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 = NULL;
|
||||
int ret = count;
|
||||
int retry_cnt;
|
||||
|
||||
st21nfc_dev = container_of(filp->private_data,
|
||||
struct st21nfc_dev, st21nfc_device);
|
||||
|
|
@ -260,13 +293,18 @@ static ssize_t st21nfc_dev_write(struct file *filp, const char __user *buf,
|
|||
|
||||
pr_debug("writing %zu bytes.\n", count);
|
||||
/* Write data */
|
||||
ret = i2c_master_send(st21nfc_dev->platform_data.client, tmp, count);
|
||||
for (retry_cnt = 1; retry_cnt <= MAX_RETRY_COUNT; retry_cnt++) {
|
||||
ret = i2c_master_send(st21nfc_dev->platform_data.client, tmp, count);
|
||||
if (ret < 0) {
|
||||
//pr_err("%s : i2c_master_send returned %d (retry (%d)\n", __func__, ret, retry_cnt);
|
||||
usleep_range(1000, 1100);
|
||||
} else if (ret == count)
|
||||
break;
|
||||
}
|
||||
if (ret != count) {
|
||||
// Commenting to reduce logging. Userspace will print the error
|
||||
// pr_err("i2c_master_send returned %d\n", ret);
|
||||
pr_err("i2c_master_send returned %d instead of %zu\n", ret, count);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -281,12 +319,13 @@ static int st21nfc_dev_open(struct inode *inode, struct file *filp)
|
|||
} else {
|
||||
device_open = true;
|
||||
st21nfc_dev = container_of(filp->private_data,
|
||||
struct st21nfc_dev,
|
||||
st21nfc_device);
|
||||
struct st21nfc_dev,
|
||||
st21nfc_device);
|
||||
|
||||
pr_debug("device_open = %d", device_open);
|
||||
pr_debug("%d,%d ", imajor(inode), iminor(inode));
|
||||
pr_debug("st21nfc_dev ptr %p\n", st21nfc_dev);
|
||||
|
||||
pr_debug("device_open = %d", device_open);
|
||||
pr_debug("%d,%d ", imajor(inode), iminor(inode));
|
||||
pr_debug("st21nfc_dev ptr %p\n", st21nfc_dev);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -300,6 +339,22 @@ static int st21nfc_release(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void (*st21nfc_st54spi_cb)(int, void *);
|
||||
static void *st21nfc_st54spi_data;
|
||||
|
||||
void st21nfc_register_st54spi_cb(void (*cb)(int, void *), void *data)
|
||||
{
|
||||
pr_info("%s\n", __func__);
|
||||
st21nfc_st54spi_cb = cb;
|
||||
st21nfc_st54spi_data = data;
|
||||
}
|
||||
void st21nfc_unregister_st54spi_cb(void)
|
||||
{
|
||||
pr_info("%s\n", __func__);
|
||||
st21nfc_st54spi_cb = NULL;
|
||||
st21nfc_st54spi_data = NULL;
|
||||
}
|
||||
|
||||
static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
|
|
@ -308,62 +363,106 @@ static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd,
|
|||
st21nfc_device);
|
||||
|
||||
int ret = 0;
|
||||
u32 tmp;
|
||||
|
||||
pr_debug("cmd=%d", cmd);
|
||||
|
||||
/* Check type and command number */
|
||||
if (_IOC_TYPE(cmd) != ST21NFC_MAGIC)
|
||||
return -ENOTTY;
|
||||
|
||||
/* Check access direction once here; don't repeat below.
|
||||
* IOC_DIR is from the user perspective, while access_ok is
|
||||
* from the kernel perspective; so they look reversed.
|
||||
*/
|
||||
if (_IOC_DIR(cmd) & _IOC_READ)
|
||||
ret = !access_ok(VERIFY_WRITE,
|
||||
(void __user *)arg, _IOC_SIZE(cmd));
|
||||
if (ret == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
|
||||
ret = !access_ok(VERIFY_READ,
|
||||
(void __user *)arg, _IOC_SIZE(cmd));
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case ST21NFC_SET_POLARITY_RISING:
|
||||
pr_info("ST21NFC_SET_POLARITY_RISING\n");
|
||||
case ST21NFC_LEGACY_SET_POLARITY_RISING:
|
||||
pr_info(" ### ST21NFC_SET_POLARITY_RISING ###\n");
|
||||
st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_RISING);
|
||||
break;
|
||||
|
||||
case ST21NFC_SET_POLARITY_HIGH:
|
||||
pr_info("ST21NFC_SET_POLARITY_HIGH\n");
|
||||
case ST21NFC_LEGACY_SET_POLARITY_HIGH:
|
||||
pr_info(" ### ST21NFC_SET_POLARITY_HIGH ###\n");
|
||||
st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_HIGH);
|
||||
break;
|
||||
|
||||
case ST21NFC_PULSE_RESET:
|
||||
case ST21NFC_LEGACY_PULSE_RESET:
|
||||
/* Double pulse is done to exit Quick boot mode.*/
|
||||
pr_info("Double Pulse Request\n");
|
||||
if (st21nfc_dev->platform_data.reset_gpio != 0) {
|
||||
if (st21nfc_st54spi_cb != 0)
|
||||
(*st21nfc_st54spi_cb)(ST54SPI_CB_RESET_START,
|
||||
st21nfc_st54spi_data);
|
||||
/* pulse low for 20 millisecs */
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio, 0);
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
|
||||
0);
|
||||
msleep(20);
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio, 1);
|
||||
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);
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
|
||||
0);
|
||||
msleep(20);
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio, 1);
|
||||
pr_info("ST21NFC_PULSE_RESET\n");
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
|
||||
1);
|
||||
pr_info("done Double Pulse Request\n");
|
||||
if (st21nfc_st54spi_cb != 0)
|
||||
(*st21nfc_st54spi_cb)(ST54SPI_CB_RESET_END,
|
||||
st21nfc_st54spi_data);
|
||||
}
|
||||
break;
|
||||
|
||||
case ST21NFC_GET_WAKEUP:
|
||||
case ST21NFC_LEGACY_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) {
|
||||
if (ret > 0)
|
||||
ret = 1;
|
||||
} else {
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
pr_debug("get gpio result %d\n", ret);
|
||||
pr_debug("irq get gpio result %d\n", ret);
|
||||
break;
|
||||
case ST21NFC_GET_POLARITY:
|
||||
case ST21NFC_LEGACY_GET_POLARITY:
|
||||
ret = st21nfc_dev->platform_data.polarity_mode;
|
||||
pr_debug("get polarity %d\n", ret);
|
||||
break;
|
||||
case ST21NFC_RECOVERY:
|
||||
case ST21NFC_LEGACY_RECOVERY:
|
||||
/* For ST21NFCD usage only */
|
||||
pr_info("Recovery Request\n");
|
||||
if (st21nfc_dev->platform_data.reset_gpio != 0) {
|
||||
if (irqIsAttached) {
|
||||
struct i2c_client *client = st21nfc_dev->platform_data.client;
|
||||
free_irq(client->irq, st21nfc_dev);
|
||||
irqIsAttached = false;
|
||||
pr_debug("IRQ detached\n");
|
||||
}
|
||||
/* 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);
|
||||
/* 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("gpio_direction_output failed\n");
|
||||
ret = -ENODEV;
|
||||
|
|
@ -371,8 +470,9 @@ static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd,
|
|||
}
|
||||
gpio_set_value(st21nfc_dev->platform_data.irq_gpio, 1);
|
||||
msleep(10);
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio, 1);
|
||||
pr_info("Pulse Request done\n");
|
||||
gpio_set_value(st21nfc_dev->platform_data.reset_gpio,
|
||||
1);
|
||||
pr_info("done Pulse Request\n");
|
||||
}
|
||||
msleep(20);
|
||||
gpio_set_value(st21nfc_dev->platform_data.irq_gpio, 0);
|
||||
|
|
@ -388,7 +488,16 @@ static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd,
|
|||
ret = -ENODEV;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST21NFC_USE_ESE:
|
||||
ret = __get_user(tmp, (u32 __user *)arg);
|
||||
if (ret == 0) {
|
||||
if (st21nfc_st54spi_cb != 0)
|
||||
(*st21nfc_st54spi_cb)(tmp ? ST54SPI_CB_ESE_USED
|
||||
: ST54SPI_CB_ESE_NOT_USED,
|
||||
st21nfc_st54spi_data);
|
||||
}
|
||||
pr_debug("use ESE %d : %d\n", ret, tmp);
|
||||
break;
|
||||
default:
|
||||
pr_err("bad ioctl %u\n", cmd);
|
||||
ret = -EINVAL;
|
||||
|
|
@ -418,8 +527,7 @@ static unsigned int st21nfc_poll(struct file *file, poll_table *wait)
|
|||
/* Wake_up_pin is low. Activate ISR */
|
||||
if (!st21nfc_dev->irq_enabled) {
|
||||
pr_debug("enable irq\n");
|
||||
st21nfc_dev->irq_enabled = true;
|
||||
enable_irq(st21nfc_dev->platform_data.client->irq);
|
||||
st21nfc_enable_irq(st21nfc_dev);
|
||||
} else {
|
||||
pr_debug("irq already enabled\n");
|
||||
}
|
||||
|
|
@ -448,7 +556,8 @@ static ssize_t st21nfc_show_i2c_addr(struct device *dev,
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (client != NULL)
|
||||
return sprintf(buf, "0x%.2x\n", client->addr);
|
||||
return snprintf(buf, 6,
|
||||
"0x%.2x\n", client->addr);
|
||||
return 0;
|
||||
} /* st21nfc_show_i2c_addr() */
|
||||
|
||||
|
|
@ -469,13 +578,13 @@ static ssize_t st21nfc_change_i2c_addr(struct device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
} /* st21nfc_change_i2c_addr() */
|
||||
}
|
||||
|
||||
static ssize_t st21nfc_version(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", DRIVER_VERSION);
|
||||
} /* st21nfc_version */
|
||||
return snprintf(buf, strlen(DRIVER_VERSION)+2, "%s\n", DRIVER_VERSION);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(i2c_addr, S_IRUGO | S_IWUSR, st21nfc_show_i2c_addr,
|
||||
st21nfc_change_i2c_addr);
|
||||
|
|
@ -493,40 +602,40 @@ static struct attribute_group st21nfc_attr_grp = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int st21nfc_parse_dt(struct device *dev, struct st21nfc_platform_data *pdata)
|
||||
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("cannot find compatible node \"%s\"", "st,st21nfc");
|
||||
pr_err("[dsc] cannot find compatible node \"%s\"", "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("fail to get reset_gpio\n");
|
||||
pr_err("[dsc]fail to get reset_gpio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pdata->irq_gpio = of_get_named_gpio(np, "st,irq_gpio", 0);
|
||||
if ((!gpio_is_valid(pdata->irq_gpio))) {
|
||||
pr_err("fail to get irq_gpio\n");
|
||||
pr_err("[dsc]fail to get irq_gpio\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata->clkreq_gpio = of_get_named_gpio(np, "st,clkreq_gpio", 0);
|
||||
if ((!gpio_is_valid(pdata->clkreq_gpio))) {
|
||||
pr_err("[OPTIONAL] fail to get clkreq_gpio\n");
|
||||
}
|
||||
if ((!gpio_is_valid(pdata->clkreq_gpio)))
|
||||
pr_err("[dsc][OPTIONAL] fail to get clkreq_gpio\n");
|
||||
|
||||
pdata->polarity_mode = IRQF_TRIGGER_RISING;
|
||||
pr_info("get reset_gpio[%d], irq_gpio[%d], polarity_mode[%d]\n",
|
||||
pdata->reset_gpio, pdata->irq_gpio, pdata->polarity_mode);
|
||||
pr_info("[dsc]get reset_gpio[%d], \
|
||||
irq_gpio[%d], polarity_mode[%d]\n",pdata->reset_gpio,
|
||||
pdata->irq_gpio, pdata->polarity_mode);
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
static int st21nfc_parse_dt(struct device *dev, struct st21nfc_platform_data *pdata)
|
||||
static int nfc_parse_dt(struct device *dev, struct st21nfc_platform_data *pdata)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -540,7 +649,7 @@ static int st21nfc_probe(struct i2c_client *client,
|
|||
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);
|
||||
|
|
@ -549,19 +658,18 @@ static int st21nfc_probe(struct i2c_client *client,
|
|||
"nfc-nci prob: Failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = st21nfc_parse_dt(&client->dev, platform_data);
|
||||
if (ret) {
|
||||
pr_info("Parse st21nfc DTS\n");
|
||||
ret = nfc_parse_dt(&client->dev, platform_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
platform_data = client->dev.platform_data;
|
||||
pr_info("No st21nfc DTS\n");
|
||||
}
|
||||
if (!platform_data) {
|
||||
if (!platform_data)
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_dbg(&client->dev,"nfc-nci probe: %s, inside nfc-nci flags = %x\n",
|
||||
__func__, client->flags);
|
||||
dev_dbg(&client->dev,
|
||||
"nfc-nci probe: inside nfc-nci flags = %x\n", client->flags);
|
||||
|
||||
if (platform_data == NULL) {
|
||||
dev_err(&client->dev, "nfc-nci probe: failed\n");
|
||||
|
|
@ -668,7 +776,6 @@ static int st21nfc_probe(struct i2c_client *client,
|
|||
|
||||
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);
|
||||
|
|
@ -692,6 +799,10 @@ static int st21nfc_probe(struct i2c_client *client,
|
|||
}
|
||||
st21nfc_disable_irq(st21nfc_dev);
|
||||
|
||||
device_init_wakeup(&client->dev, true);
|
||||
device_set_wakeup_capable(&client->dev, true);
|
||||
st21nfc_dev->irq_wake_up = false;
|
||||
|
||||
ret = st_clock_select(st21nfc_dev);
|
||||
if (ret < 0) {
|
||||
pr_err("st_clock_select failed\n");
|
||||
|
|
@ -746,66 +857,54 @@ static int st21nfc_remove(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int st21nfc_suspend(struct device *device)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(device);
|
||||
struct st21nfc_dev *st21nfc_dev = i2c_get_clientdata(client);
|
||||
|
||||
if (device_may_wakeup(&client->dev) && st21nfc_dev->irq_enabled) {
|
||||
if (!enable_irq_wake(client->irq))
|
||||
st21nfc_dev->irq_wake_up = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st21nfc_resume(struct device *device)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(device);
|
||||
struct st21nfc_dev *st21nfc_dev = i2c_get_clientdata(client);
|
||||
|
||||
if (device_may_wakeup(&client->dev) && st21nfc_dev->irq_wake_up) {
|
||||
if (!disable_irq_wake(client->irq))
|
||||
st21nfc_dev->irq_wake_up = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct i2c_device_id st21nfc_id[] = {
|
||||
{"st21nfc", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct of_device_id st21nfc_of_match[] = {
|
||||
{ .compatible = "st,st21nfc",},
|
||||
static const struct of_device_id st21nfc_of_match[] = {
|
||||
{ .compatible = "st,st21nfc", },
|
||||
{}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int st21nfc_suspend(struct device *dev)
|
||||
{
|
||||
struct st21nfc_dev *st21nfc_dev = dev_get_drvdata(dev);
|
||||
if (st21nfc_dev->s_clk && st21nfc_dev->clk_run) {
|
||||
clk_disable_unprepare(st21nfc_dev->s_clk);
|
||||
st21nfc_dev->clk_run = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st21nfc_resume(struct device *dev)
|
||||
{
|
||||
struct st21nfc_dev *st21nfc_dev = dev_get_drvdata(dev);
|
||||
int r = 0;
|
||||
if (st21nfc_dev->s_clk && !st21nfc_dev->clk_run) {
|
||||
r = clk_prepare_enable(st21nfc_dev->s_clk);
|
||||
if (r) {
|
||||
pr_err("clk enable failed\n");
|
||||
} else {
|
||||
st21nfc_dev->clk_run = true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops st21nfc_pm_ops =
|
||||
{
|
||||
.suspend = st21nfc_suspend,
|
||||
.resume = st21nfc_resume,
|
||||
static const struct dev_pm_ops st21nfc_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(st21nfc_suspend, st21nfc_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&st21nfc_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
||||
|
||||
|
||||
static struct i2c_driver st21nfc_driver = {
|
||||
.id_table = st21nfc_id,
|
||||
.driver = {
|
||||
.name = "st21nfc",
|
||||
.pm = DEV_PM_OPS,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = st21nfc_of_match,
|
||||
.pm = &st21nfc_pm_ops,
|
||||
},
|
||||
.probe = st21nfc_probe,
|
||||
.remove = st21nfc_remove,
|
||||
|
|
|
|||
|
|
@ -25,13 +25,27 @@
|
|||
* 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)
|
||||
#define ST21NFC_GET_WAKEUP _IO(ST21NFC_MAGIC, 0x01)
|
||||
#define ST21NFC_PULSE_RESET _IO(ST21NFC_MAGIC, 0x02)
|
||||
#define ST21NFC_SET_POLARITY_RISING _IO(ST21NFC_MAGIC, 0x03)
|
||||
#define ST21NFC_SET_POLARITY_FALLING _IO(ST21NFC_MAGIC, 0x04)
|
||||
#define ST21NFC_SET_POLARITY_HIGH _IO(ST21NFC_MAGIC, 0x05)
|
||||
#define ST21NFC_SET_POLARITY_LOW _IO(ST21NFC_MAGIC, 0x06)
|
||||
#define ST21NFC_GET_POLARITY _IO(ST21NFC_MAGIC, 0x07)
|
||||
#define ST21NFC_RECOVERY _IO(ST21NFC_MAGIC, 0x08)
|
||||
#define ST21NFC_USE_ESE _IOW(ST21NFC_MAGIC, 0x09, unsigned int)
|
||||
|
||||
// Keep compatibility with older user applications.
|
||||
#define ST21NFC_LEGACY_GET_WAKEUP _IOR(ST21NFC_MAGIC, 0x01, unsigned int)
|
||||
#define ST21NFC_LEGACY_PULSE_RESET _IOR(ST21NFC_MAGIC, 0x02, unsigned int)
|
||||
#define ST21NFC_LEGACY_SET_POLARITY_RISING _IOR(ST21NFC_MAGIC, 0x03, \
|
||||
unsigned int)
|
||||
#define ST21NFC_LEGACY_SET_POLARITY_FALLING _IOR(ST21NFC_MAGIC, 0x04, \
|
||||
unsigned int)
|
||||
#define ST21NFC_LEGACY_SET_POLARITY_HIGH _IOR(ST21NFC_MAGIC, 0x05, unsigned int)
|
||||
#define ST21NFC_LEGACY_SET_POLARITY_LOW _IOR(ST21NFC_MAGIC, 0x06, unsigned int)
|
||||
#define ST21NFC_LEGACY_GET_POLARITY _IOR(ST21NFC_MAGIC, 0x07, unsigned int)
|
||||
#define ST21NFC_LEGACY_RECOVERY _IOR(ST21NFC_MAGIC, 0x08, unsigned int)
|
||||
|
||||
struct st21nfc_platform_data {
|
||||
unsigned int irq_gpio;
|
||||
|
|
@ -40,3 +54,10 @@ struct st21nfc_platform_data {
|
|||
unsigned int clkreq_gpio;
|
||||
unsigned int polarity_mode;
|
||||
};
|
||||
|
||||
#define ST54SPI_CB_RESET_END 0
|
||||
#define ST54SPI_CB_RESET_START 1
|
||||
#define ST54SPI_CB_ESE_NOT_USED 2
|
||||
#define ST54SPI_CB_ESE_USED 3
|
||||
void st21nfc_register_st54spi_cb(void (*cb)(int, void *), void *data);
|
||||
void st21nfc_unregister_st54spi_cb(void);
|
||||
|
|
|
|||
Loading…
Reference in a new issue