From 424b4b21570347cc2de71b6f75f5cd4661a37e09 Mon Sep 17 00:00:00 2001 From: Gaurav Singhal Date: Wed, 27 Apr 2016 13:18:45 +0530 Subject: [PATCH] NFC: Add eSE power request gpio pin support We can't control eSE power through driver as of now so adding gpio pin support for eSE in NQxxx driver. Multiline comments are updated. Change-Id: I60651052d7bf97a8a0505e76904cebe2b7c69ce2 Signed-off-by: Gaurav Singhal --- .../devicetree/bindings/nfc/nq-nci.txt | 10 +- drivers/nfc/nq-nci.c | 140 ++++++++++++++++-- drivers/nfc/nq-nci.h | 3 +- 3 files changed, 140 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/nfc/nq-nci.txt b/Documentation/devicetree/bindings/nfc/nq-nci.txt index 4d9346a5ad44..af8b81e56333 100644 --- a/Documentation/devicetree/bindings/nfc/nq-nci.txt +++ b/Documentation/devicetree/bindings/nfc/nq-nci.txt @@ -8,6 +8,8 @@ Required properties: - reg: NCI i2c slave address. - qcom,nq-ven: specific gpio for hardware reset. - qcom,nq-irq: specific gpio for read interrupt. +- qcom,nq-firm: gpio for firmware download +- qcom,nq-clkreq: gpio for clock - interrupt-parent: Should be phandle for the interrupt controller that services interrupts for this device. - interrupts: Nfc read interrupt,gpio-clk-req interrupt @@ -22,14 +24,18 @@ Optional properties: - pinctrl-names, pinctrl-0, pincntrl-1: references to our pincntrl settings - clocks, clock-names: must contain the NQxxxx's core clock. +- qcom,nq-esepwr: gpio to control power of secure element Example: nq-nci@2b { compatible = "qcom,nq-nci"; reg = <0x2b>; - qcom,irq-gpio = <&tlmm 29 0x00>; - qcom,en-gpio = <&tlmm 30 0x00>; + qcom,nq-irq = <&tlmm 29 0x00>; + qcom,nq-ven = <&tlmm 30 0x00>; + qcom,nq-firm = <&tlmm 93 0x00>; + qcom,nq-clkreq = <&pmcobalt_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; qcom,clk-src = "BBCLK2"; interrupt-parent = <&tlmm>; interrupts = <29 0>; diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index a2ff438627ed..88011626e05e 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -34,6 +34,7 @@ struct nqx_platform_data { unsigned int en_gpio; unsigned int clkreq_gpio; unsigned int firm_gpio; + unsigned int ese_gpio; const char *clk_src_name; }; @@ -57,6 +58,9 @@ struct nqx_dev { unsigned int en_gpio; unsigned int firm_gpio; unsigned int clkreq_gpio; + unsigned int ese_gpio; + /* NFC VEN pin state powered by Nfc */ + bool nfc_ven_enabled; /* NFC_IRQ state */ bool irq_enabled; spinlock_t irq_enabled_lock; @@ -270,6 +274,63 @@ out: return ret; } +/* + * Power management of the eSE + * NFC & eSE ON : NFC_EN high and eSE_pwr_req high. + * NFC OFF & eSE ON : NFC_EN high and eSE_pwr_req high. + * NFC OFF & eSE OFF : NFC_EN low and eSE_pwr_req low. +*/ +static int nqx_ese_pwr(struct nqx_dev *nqx_dev, unsigned long int arg) +{ + int r = -1; + + /* Let's store the NFC_EN pin state */ + if (arg == 0) { + /* + * We want to power on the eSE and to do so we need the + * eSE_pwr_req pin and the NFC_EN pin to be high + */ + nqx_dev->nfc_ven_enabled = gpio_get_value(nqx_dev->en_gpio); + if (!nqx_dev->nfc_ven_enabled) { + gpio_set_value(nqx_dev->en_gpio, 1); + /* hardware dependent delay */ + usleep_range(1000, 1100); + } + if (gpio_is_valid(nqx_dev->ese_gpio)) { + if (gpio_get_value(nqx_dev->ese_gpio)) { + dev_dbg(&nqx_dev->client->dev, "ese_gpio is already high\n"); + r = 0; + } else { + gpio_set_value(nqx_dev->ese_gpio, 1); + if (gpio_get_value(nqx_dev->ese_gpio)) { + dev_dbg(&nqx_dev->client->dev, "ese_gpio is enabled\n"); + r = 0; + } + } + } + } else if (arg == 1) { + if (gpio_is_valid(nqx_dev->ese_gpio)) { + gpio_set_value(nqx_dev->ese_gpio, 0); + if (!gpio_get_value(nqx_dev->ese_gpio)) { + dev_dbg(&nqx_dev->client->dev, "ese_gpio is disabled\n"); + r = 0; + } + } + if (!nqx_dev->nfc_ven_enabled) { + /* hardware dependent delay */ + usleep_range(1000, 1100); + dev_dbg(&nqx_dev->client->dev, "disabling en_gpio\n"); + gpio_set_value(nqx_dev->en_gpio, 0); + } + } else if (arg == 3) { + if (!nqx_dev->nfc_ven_enabled) + r = 0; + else + r = gpio_get_value(nqx_dev->ese_gpio); + } + return r; +} + static int nfc_open(struct inode *inode, struct file *filp) { int ret = 0; @@ -284,7 +345,7 @@ static int nfc_open(struct inode *inode, struct file *filp) return ret; } -/** +/* * nfc_ioctl_power_states() - power control * @filp: pointer to the file descriptor * @arg: mode that we want to move to @@ -303,7 +364,8 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) struct nqx_dev *nqx_dev = filp->private_data; if (arg == 0) { - /* We are attempting a hardware reset so let us disable + /* + * We are attempting a hardware reset so let us disable * interrupts to avoid spurious notifications to upper * layers. */ @@ -313,10 +375,16 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) __func__, nqx_dev); if (gpio_is_valid(nqx_dev->firm_gpio)) gpio_set_value(nqx_dev->firm_gpio, 0); - gpio_set_value(nqx_dev->en_gpio, 0); + if (!gpio_get_value(nqx_dev->ese_gpio)) { + dev_dbg(&nqx_dev->client->dev, "disabling en_gpio\n"); + gpio_set_value(nqx_dev->en_gpio, 0); + } else { + dev_dbg(&nqx_dev->client->dev, "keeping en_gpio high\n"); + } r = nqx_clock_deselect(nqx_dev); if (r < 0) dev_err(&nqx_dev->client->dev, "unable to disable clock\n"); + nqx_dev->nfc_ven_enabled = false; /* hardware dependent delay */ msleep(100); } else if (arg == 1) { @@ -330,12 +398,17 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) r = nqx_clock_select(nqx_dev); if (r < 0) dev_err(&nqx_dev->client->dev, "unable to enable clock\n"); - + nqx_dev->nfc_ven_enabled = true; msleep(20); } else if (arg == 2) { - /* We are switching to Dowload Mode, toggle the enable pin + /* + * We are switching to Dowload Mode, toggle the enable pin * in order to set the NFCC in the new mode */ + if (gpio_get_value(nqx_dev->ese_gpio)) { + dev_err(&nqx_dev->client->dev, "FW download forbidden while ese is on\n"); + return -EBUSY; /* Device or resource busy */ + } gpio_set_value(nqx_dev->en_gpio, 1); msleep(20); if (gpio_is_valid(nqx_dev->firm_gpio)) @@ -348,6 +421,7 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) } else { r = -ENOIOCTLCMD; } + return r; } @@ -356,12 +430,17 @@ static long nfc_compat_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) { long r = 0; - arg = (compat_u64)arg; switch (cmd) { case NFC_SET_PWR: nfc_ioctl_power_states(pfile, arg); break; + case ESE_SET_PWR: + nqx_ese_pwr(pfile->private_data, arg); + break; + case ESE_GET_PWR: + nqx_ese_pwr(pfile->private_data, 3); + break; case SET_RX_BLOCK: break; case SET_EMULATOR_TEST_POINT: @@ -373,7 +452,7 @@ static long nfc_compat_ioctl(struct file *pfile, unsigned int cmd, } #endif -/** +/* * nfc_ioctl_core_reset_ntf() * @filp: pointer to the file descriptor * @@ -399,7 +478,11 @@ static long nfc_ioctl(struct file *pfile, unsigned int cmd, case NFC_SET_PWR: r = nfc_ioctl_power_states(pfile, arg); break; - case NFC_CLK_REQ: + case ESE_SET_PWR: + r = nqx_ese_pwr(pfile->private_data, arg); + break; + case ESE_GET_PWR: + r = nqx_ese_pwr(pfile->private_data, 3); break; case SET_RX_BLOCK: break; @@ -544,6 +627,13 @@ static int nfc_parse_dt(struct device *dev, struct nqx_platform_data *pdata) pdata->firm_gpio = -EINVAL; } + pdata->ese_gpio = of_get_named_gpio(np, "qcom,nq-esepwr", 0); + if (!gpio_is_valid(pdata->ese_gpio)) { + dev_warn(dev, + "ese GPIO error getting from OF node\n"); + pdata->ese_gpio = -EINVAL; + } + r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name); pdata->clkreq_gpio = of_get_named_gpio(np, "qcom,nq-clkreq", 0); @@ -690,6 +780,29 @@ static int nqx_probe(struct i2c_client *client, "%s: firm gpio not provided\n", __func__); goto err_irq_gpio; } + if (gpio_is_valid(platform_data->ese_gpio)) { + r = gpio_request(platform_data->ese_gpio, + "nfc-ese_pwr"); + if (r) { + dev_err(&client->dev, + "%s: unable to request nfc ese gpio [%d]\n", + __func__, platform_data->ese_gpio); + /* ese gpio optional so we should continue */ + } else { + nqx_dev->ese_gpio = platform_data->ese_gpio; + } + r = gpio_direction_output(platform_data->ese_gpio, 0); + if (r) { + dev_err(&client->dev, + "%s: cannot set direction for nfc ese gpio [%d]\n", + __func__, platform_data->ese_gpio); + /* ese gpio optional so we should continue */ + } + } else { + dev_err(&client->dev, + "%s: ese gpio not provided\n", __func__); + /* ese gpio optional so we should continue */ + } if (gpio_is_valid(platform_data->clkreq_gpio)) { r = gpio_request(platform_data->clkreq_gpio, "nfc_clkreq_gpio"); @@ -697,7 +810,7 @@ static int nqx_probe(struct i2c_client *client, dev_err(&client->dev, "%s: unable to request nfc clkreq gpio [%d]\n", __func__, platform_data->clkreq_gpio); - goto err_firm_gpio; + goto err_ese_gpio; } r = gpio_direction_input(platform_data->clkreq_gpio); if (r) { @@ -709,7 +822,7 @@ static int nqx_probe(struct i2c_client *client, } else { dev_err(&client->dev, "%s: clkreq gpio not provided\n", __func__); - goto err_firm_gpio; + goto err_ese_gpio; } nqx_dev->en_gpio = platform_data->en_gpio; @@ -800,6 +913,10 @@ err_misc_register: mutex_destroy(&nqx_dev->read_mutex); err_clkreq_gpio: gpio_free(platform_data->clkreq_gpio); +err_ese_gpio: + /* optional gpio, not sure was configured in probe */ + if (nqx_dev->ese_gpio) + gpio_free(platform_data->ese_gpio); err_firm_gpio: gpio_free(platform_data->firm_gpio); err_irq_gpio: @@ -838,6 +955,9 @@ static int nqx_remove(struct i2c_client *client) misc_deregister(&nqx_dev->nqx_device); mutex_destroy(&nqx_dev->read_mutex); gpio_free(nqx_dev->clkreq_gpio); + /* optional gpio, not sure was configured in probe */ + if (nqx_dev->ese_gpio) + gpio_free(nqx_dev->ese_gpio); gpio_free(nqx_dev->firm_gpio); gpio_free(nqx_dev->irq_gpio); gpio_free(nqx_dev->en_gpio); diff --git a/drivers/nfc/nq-nci.h b/drivers/nfc/nq-nci.h index e9f4de0aee3a..d62100c2d15a 100644 --- a/drivers/nfc/nq-nci.h +++ b/drivers/nfc/nq-nci.h @@ -24,7 +24,8 @@ #include #define NFC_SET_PWR _IOW(0xE9, 0x01, unsigned int) -#define NFC_CLK_REQ _IOW(0xE9, 0x02, unsigned int) +#define ESE_SET_PWR _IOW(0xE9, 0x02, unsigned int) +#define ESE_GET_PWR _IOR(0xE9, 0x03, unsigned int) #define SET_RX_BLOCK _IOW(0xE9, 0x04, unsigned int) #define SET_EMULATOR_TEST_POINT _IOW(0xE9, 0x05, unsigned int) #define NFCC_INITIAL_CORE_RESET_NTF _IOW(0xE9, 0x10, unsigned int)