NFC: driver: FR63179 Add NFC dynamic protection control
Implemented NFC dynamic protection control feature in driver; performing Ven GPIO enable/disable post TZ notifications in non-secure/secure zone respectively. Change-Id: I13dedf23987ce0b3b2a53881d35f6c3cf462cd92
This commit is contained in:
127
nfc/common.c
127
nfc/common.c
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
static int secure_zone = 1;
|
||||||
|
|
||||||
int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
|
int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
|
||||||
uint8_t interface)
|
uint8_t interface)
|
||||||
{
|
{
|
||||||
@@ -385,6 +387,120 @@ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nfc_post_init() - Configuraing Ven GPIO and hardware check
|
||||||
|
* @nfc_dev: nfc device data structure
|
||||||
|
*
|
||||||
|
* Configure GPIOs post notification from TZ, ensuring it's a non-secure zone.
|
||||||
|
*
|
||||||
|
* Return: 0 if Success(or no issue) and error ret code otherwise
|
||||||
|
*/
|
||||||
|
int nfc_post_init(struct nfc_dev *nfc_dev)
|
||||||
|
{
|
||||||
|
int ret=0;
|
||||||
|
struct platform_configs nfc_configs;
|
||||||
|
struct platform_gpio *nfc_gpio;
|
||||||
|
|
||||||
|
if (!nfc_dev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
memcpy(&nfc_configs, &nfc_dev->configs, sizeof(struct platform_configs));
|
||||||
|
nfc_gpio = &nfc_configs.gpio;
|
||||||
|
|
||||||
|
ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unable to request nfc reset gpio [%d]\n",
|
||||||
|
__func__, nfc_gpio->ven);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("%s: unable to request nfc firm downl gpio [%d]\n",
|
||||||
|
__func__, nfc_gpio->dwl_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nfcc_hw_check(nfc_dev);
|
||||||
|
if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) {
|
||||||
|
pr_err("nfc hw check failed ret %d\n", ret);
|
||||||
|
gpio_free(nfc_gpio->dwl_req);
|
||||||
|
gpio_free(nfc_gpio->ven);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Initialising sempahore to disbale NFC Ven GPIO only after eSE is power off flag is set */
|
||||||
|
sema_init(&sem_eSE_pwr_off,0);
|
||||||
|
|
||||||
|
pr_info("%s success\n", __func__);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nfc_dynamic_protection_ioctl() - dynamic protection control
|
||||||
|
* @nfc_dev: nfc device data structure
|
||||||
|
* @sec_zone_trans: mode that we want to move to
|
||||||
|
* If sec_zone_trans = 1; transition from non-secure zone to secure zone
|
||||||
|
* If sec_zone_trans = 0; transition from secure zone to non - secure zone
|
||||||
|
*
|
||||||
|
* nfc periheral dynamic protection control. Depending on the sec_zone_trans value, device moves to
|
||||||
|
* secure zone and non-secure zone
|
||||||
|
*
|
||||||
|
* Return: -ENOIOCTLCMD if sec_zone_trans val is not supported, 0 if Success(or no issue)
|
||||||
|
* and error ret code otherwise
|
||||||
|
*/
|
||||||
|
int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
static int init_flag=1;
|
||||||
|
|
||||||
|
struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio;
|
||||||
|
|
||||||
|
if(sec_zone_trans == 1) {
|
||||||
|
/*check NFC is disabled, only then set Ven GPIO low*/
|
||||||
|
if(nfc_dev->cold_reset.is_nfc_enabled == false) {
|
||||||
|
pr_debug("%s: value %d\n", __func__, gpio_get_value(nfc_gpio->ven));
|
||||||
|
|
||||||
|
chk_eSE_pwr_off = 1;
|
||||||
|
/*check if eSE is active, if yes, wait max of 1sec, until it's inactive */
|
||||||
|
if(nfc_dev->is_ese_session_active == true) {
|
||||||
|
if(down_timeout(&sem_eSE_pwr_off, msecs_to_jiffies(1000))) {
|
||||||
|
/*waited for 1sec yet eSE not turned off, so, ignoring eSE power off*/
|
||||||
|
pr_info("Forcefull shutdown of eSE\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = nfc_ioctl_power_states(nfc_dev, 0);
|
||||||
|
/*set driver as secure zone, such that no ioctl calls are allowed*/
|
||||||
|
secure_zone=1;
|
||||||
|
pr_info("Driver Secure flag set successful\n");
|
||||||
|
} else {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(sec_zone_trans == 0) {
|
||||||
|
chk_eSE_pwr_off = 0;
|
||||||
|
secure_zone=0;
|
||||||
|
|
||||||
|
if(init_flag) {
|
||||||
|
/*Initialize once,only during the first non-secure entry*/
|
||||||
|
ret = nfc_post_init(nfc_dev);
|
||||||
|
if(ret == 0)
|
||||||
|
init_flag=0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = nfc_ioctl_power_states(nfc_dev, 1);
|
||||||
|
}
|
||||||
|
pr_info("Func Driver Secure flag clear successful\n");
|
||||||
|
} else {
|
||||||
|
pr_info("INVALID ARG\n");
|
||||||
|
ret = -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nfc_dev_ioctl - used to set or get data from upper layer.
|
* nfc_dev_ioctl - used to set or get data from upper layer.
|
||||||
* @pfile file node for opened device.
|
* @pfile file node for opened device.
|
||||||
@@ -406,6 +522,14 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
|
|||||||
if (!nfc_dev)
|
if (!nfc_dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
/*Avoiding ioctl call in secure zone*/
|
||||||
|
if(secure_zone) {
|
||||||
|
if(cmd!=NFC_SECURE_ZONE) {
|
||||||
|
pr_debug("nfc_dev_ioctl failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg);
|
pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case NFC_SET_PWR:
|
case NFC_SET_PWR:
|
||||||
@@ -424,6 +548,9 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
|
|||||||
pr_debug("nfc ese cold reset ioctl\n");
|
pr_debug("nfc ese cold reset ioctl\n");
|
||||||
ret = ese_cold_reset_ioctl(nfc_dev, arg);
|
ret = ese_cold_reset_ioctl(nfc_dev, arg);
|
||||||
break;
|
break;
|
||||||
|
case NFC_SECURE_ZONE:
|
||||||
|
ret = nfc_dynamic_protection_ioctl(nfc_dev, arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("%s: bad cmd %lu\n", __func__, arg);
|
pr_err("%s: bad cmd %lu\n", __func__, arg);
|
||||||
ret = -ENOIOCTLCMD;
|
ret = -ENOIOCTLCMD;
|
||||||
|
@@ -98,6 +98,7 @@
|
|||||||
#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t)
|
#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, uint32_t)
|
||||||
#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t)
|
#define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t)
|
||||||
#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t)
|
#define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t)
|
||||||
|
#define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t)
|
||||||
|
|
||||||
#define DTS_IRQ_GPIO_STR "qcom,sn-irq"
|
#define DTS_IRQ_GPIO_STR "qcom,sn-irq"
|
||||||
#define DTS_VEN_GPIO_STR "qcom,sn-ven"
|
#define DTS_VEN_GPIO_STR "qcom,sn-ven"
|
||||||
@@ -130,6 +131,9 @@ do { \
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
static struct semaphore sem_eSE_pwr_off;
|
||||||
|
static chk_eSE_pwr_off;
|
||||||
|
|
||||||
enum ese_ioctl_request {
|
enum ese_ioctl_request {
|
||||||
/* eSE POWER ON */
|
/* eSE POWER ON */
|
||||||
ESE_POWER_ON = 0,
|
ESE_POWER_ON = 0,
|
||||||
@@ -297,4 +301,6 @@ int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev);
|
|||||||
int validate_nfc_state_nci(struct nfc_dev *nfc_dev);
|
int validate_nfc_state_nci(struct nfc_dev *nfc_dev);
|
||||||
int nfc_clock_select(struct nfc_dev *nfc_dev);
|
int nfc_clock_select(struct nfc_dev *nfc_dev);
|
||||||
int nfc_clock_deselect(struct nfc_dev *nfc_dev);
|
int nfc_clock_deselect(struct nfc_dev *nfc_dev);
|
||||||
|
int nfc_post_init(struct nfc_dev *nfc_dev);
|
||||||
|
int nfc_dynamic_protection_ioctl(struct nfc_dev *nfc_dev, unsigned long sec_zone_trans);
|
||||||
#endif /* _COMMON_H_ */
|
#endif /* _COMMON_H_ */
|
||||||
|
@@ -47,6 +47,8 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
|
|||||||
pr_debug("keep ven high as NFC is enabled\n");
|
pr_debug("keep ven high as NFC is enabled\n");
|
||||||
}
|
}
|
||||||
nfc_dev->is_ese_session_active = false;
|
nfc_dev->is_ese_session_active = false;
|
||||||
|
if(chk_eSE_pwr_off)
|
||||||
|
up(&sem_eSE_pwr_off);
|
||||||
} else if (arg == ESE_POWER_STATE) {
|
} else if (arg == ESE_POWER_STATE) {
|
||||||
/* get VEN gpio state for eSE, as eSE also enabled through same GPIO */
|
/* get VEN gpio state for eSE, as eSE also enabled through same GPIO */
|
||||||
ret = gpio_get_value(nfc_dev->configs.gpio.ven);
|
ret = gpio_get_value(nfc_dev->configs.gpio.ven);
|
||||||
|
@@ -375,12 +375,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
nfc_dev->nfc_write = i2c_write;
|
nfc_dev->nfc_write = i2c_write;
|
||||||
nfc_dev->nfc_enable_intr = i2c_enable_irq;
|
nfc_dev->nfc_enable_intr = i2c_enable_irq;
|
||||||
nfc_dev->nfc_disable_intr = i2c_disable_irq;
|
nfc_dev->nfc_disable_intr = i2c_disable_irq;
|
||||||
ret = configure_gpio(nfc_gpio->ven, GPIO_OUTPUT);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: unable to request nfc reset gpio [%d]\n", __func__,
|
|
||||||
nfc_gpio->ven);
|
|
||||||
goto err_free_write_kbuf;
|
|
||||||
}
|
|
||||||
ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ);
|
ret = configure_gpio(nfc_gpio->irq, GPIO_IRQ);
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__,
|
pr_err("%s: unable to request nfc irq gpio [%d]\n", __func__,
|
||||||
@@ -388,11 +383,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
goto err_free_gpio;
|
goto err_free_gpio;
|
||||||
}
|
}
|
||||||
client->irq = ret;
|
client->irq = ret;
|
||||||
ret = configure_gpio(nfc_gpio->dwl_req, GPIO_OUTPUT);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: unable to request nfc firm downl gpio [%d]\n",
|
|
||||||
__func__, nfc_gpio->dwl_req);
|
|
||||||
}
|
|
||||||
/* init mutex and queues */
|
/* init mutex and queues */
|
||||||
init_waitqueue_head(&nfc_dev->read_wq);
|
init_waitqueue_head(&nfc_dev->read_wq);
|
||||||
mutex_init(&nfc_dev->read_mutex);
|
mutex_init(&nfc_dev->read_mutex);
|
||||||
@@ -421,20 +412,13 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
pr_err("LDO config failed\n");
|
pr_err("LDO config failed\n");
|
||||||
goto err_ldo_config_failed;
|
goto err_ldo_config_failed;
|
||||||
}
|
}
|
||||||
ret = nfcc_hw_check(nfc_dev);
|
|
||||||
if (ret || nfc_dev->nfc_state == NFC_STATE_UNKNOWN) {
|
|
||||||
pr_err("nfc hw check failed ret %d\n", ret);
|
|
||||||
goto err_nfcc_hw_check;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(nfc_dev->configs.clk_pin_voting)
|
if(nfc_dev->configs.clk_pin_voting)
|
||||||
nfc_dev->clk_run = false;
|
nfc_dev->clk_run = false;
|
||||||
else
|
else
|
||||||
nfc_dev->clk_run = true;
|
nfc_dev->clk_run = true;
|
||||||
|
|
||||||
gpio_set_ven(nfc_dev, 1);
|
|
||||||
gpio_set_ven(nfc_dev, 0);
|
|
||||||
gpio_set_ven(nfc_dev, 1);
|
|
||||||
device_init_wakeup(&client->dev, true);
|
device_init_wakeup(&client->dev, true);
|
||||||
i2c_set_clientdata(client, nfc_dev);
|
i2c_set_clientdata(client, nfc_dev);
|
||||||
i2c_dev->irq_wake_up = false;
|
i2c_dev->irq_wake_up = false;
|
||||||
@@ -443,11 +427,7 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||||||
pr_info("%s: probing nfc i2c successfully\n", __func__);
|
pr_info("%s: probing nfc i2c successfully\n", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_nfcc_hw_check:
|
|
||||||
if (nfc_dev->reg) {
|
|
||||||
nfc_ldo_unvote(nfc_dev);
|
|
||||||
regulator_put(nfc_dev->reg);
|
|
||||||
}
|
|
||||||
err_ldo_config_failed:
|
err_ldo_config_failed:
|
||||||
free_irq(client->irq, nfc_dev);
|
free_irq(client->irq, nfc_dev);
|
||||||
err_nfc_misc_unregister:
|
err_nfc_misc_unregister:
|
||||||
@@ -458,7 +438,6 @@ err_mutex_destroy:
|
|||||||
mutex_destroy(&nfc_dev->write_mutex);
|
mutex_destroy(&nfc_dev->write_mutex);
|
||||||
err_free_gpio:
|
err_free_gpio:
|
||||||
gpio_free_all(nfc_dev);
|
gpio_free_all(nfc_dev);
|
||||||
err_free_write_kbuf:
|
|
||||||
kfree(nfc_dev->write_kbuf);
|
kfree(nfc_dev->write_kbuf);
|
||||||
err_free_read_kbuf:
|
err_free_read_kbuf:
|
||||||
kfree(nfc_dev->read_kbuf);
|
kfree(nfc_dev->read_kbuf);
|
||||||
|
Reference in New Issue
Block a user