diff --git a/nfc/common.c b/nfc/common.c index 3932dbeeda..5416ec1b8a 100644 --- a/nfc/common.c +++ b/nfc/common.c @@ -1,6 +1,6 @@ /****************************************************************************** * Copyright (C) 2015, The Linux Foundation. All rights reserved. - * Copyright (C) 2019-2021 NXP + * Copyright (C) 2019-2022 NXP * * 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 @@ -50,22 +50,22 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, if (interface == PLATFORM_IF_I2C) { nfc_gpio->irq = of_get_named_gpio(np, DTS_IRQ_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->irq))) { - pr_err("%s: nfc irq gpio invalid %d\n", __func__, + pr_err("%s: irq gpio invalid %d\n", __func__, nfc_gpio->irq); - return -EINVAL; + return nfc_gpio->irq; } pr_info("%s: irq %d\n", __func__, nfc_gpio->irq); } nfc_gpio->ven = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); if ((!gpio_is_valid(nfc_gpio->ven))) { - pr_err("%s: nfc ven gpio invalid %d\n", __func__, nfc_gpio->ven); - return -EINVAL; + pr_err("%s: ven gpio invalid %d\n", __func__, nfc_gpio->ven); + return nfc_gpio->ven; } /* some products like sn220 does not required fw dwl pin */ nfc_gpio->dwl_req = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); - /* not returning failure for dwl gpio as it is optional for sn220 */ - if ((!gpio_is_valid(nfc_gpio->dwl_req))){ - pr_warn("%s: nfc dwl_req gpio invalid %d\n", __func__, + /* not returning failure for dwl gpio as it is optional for sn220 */ + if ((!gpio_is_valid(nfc_gpio->dwl_req))) { + pr_warn("%s: dwl_req gpio invalid %d\n", __func__, nfc_gpio->dwl_req); } /* Read clkreq GPIO pin number from DTSI */ @@ -166,8 +166,7 @@ int configure_gpio(unsigned int gpio, int flag) } if (ret) { - pr_err("%s: unable to set direction for nfc gpio [%d]\n", - __func__, gpio); + pr_err("%s: unable to set direction for nfc gpio [%d]\n", __func__, gpio); gpio_free(gpio); return ret; } @@ -279,6 +278,46 @@ int nfc_misc_register(struct nfc_dev *nfc_dev, return 0; } +/** + * nfc_gpio_info() - gets the status of nfc gpio pins and encodes into a byte. + * @nfc_dev: nfc device data structure + * @arg: userspace buffer + * + * Encoding can be done in following manner + * 1) map the gpio value into INVALID(-2), SET(1), RESET(0). + * 2) mask the first 2 bits of gpio. + * 3) left shift the 2 bits as multiple of 2. + * 4) multiply factor can be defined as position of gpio pin in struct platform_gpio + * + * Return: -EFAULT, if unable to copy the data from kernel space to userspace, 0 + * if Success(or no issue) + */ + +static int nfc_gpio_info(struct nfc_dev *nfc_dev, unsigned long arg) +{ + unsigned int gpios_status = 0; + int value = 0; + int gpio_no = 0; + int i; + int ret = 0; + struct platform_gpio *nfc_gpio = &nfc_dev->configs.gpio; + + for (i = 0; i < sizeof(struct platform_gpio) / sizeof(unsigned int); + i++) { + gpio_no = *((unsigned int *)nfc_gpio + i); + value = get_valid_gpio(gpio_no); + if (value < 0) + value = -2; + gpios_status |= (value & GPIO_STATUS_MASK_BITS)<<(GPIO_POS_SHIFT_VAL*i); + } + ret = copy_to_user((uint32_t *) arg, &gpios_status, sizeof(value)); + if (ret < 0) { + pr_err("%s : Unable to copy data from kernel space to user space", __func__); + return -EFAULT; + } + return 0; +} + /** * nfc_ioctl_power_states() - power control * @nfc_dev: nfc device data structure @@ -305,12 +344,14 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) set_valid_gpio(nfc_gpio->dwl_req, 0); gpio_set_ven(nfc_dev, 0); nfc_dev->nfc_ven_enabled = false; + nfc_dev->nfc_state = NFC_STATE_NCI; } else if (arg == NFC_POWER_ON) { nfc_dev->nfc_enable_intr(nfc_dev); set_valid_gpio(nfc_gpio->dwl_req, 0); gpio_set_ven(nfc_dev, 1); nfc_dev->nfc_ven_enabled = true; + nfc_dev->nfc_state = NFC_STATE_NCI; } else if (arg == NFC_FW_DWL_VEN_TOGGLE) { /* * We are switching to download Mode, toggle the enable pin @@ -353,8 +394,8 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) } else if (arg == NFC_DISABLE) { /* Setting flag true when NFC is disabled */ nfc_dev->cold_reset.is_nfc_enabled = false; - } else { - pr_err("%s bad arg %lu\n", __func__, arg); + } else { + pr_err("%s: bad arg %lu\n", __func__, arg); ret = -ENOIOCTLCMD; } return ret; @@ -375,10 +416,11 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) * and error ret code otherwise */ long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, - unsigned long arg) + unsigned long arg) { int ret = 0; - arg = (compat_u64)arg; + + arg = (compat_u64) arg; pr_debug("%s: cmd = %x arg = %zx\n", __func__, cmd, arg); ret = nfc_dev_ioctl(pfile, cmd, arg); return ret; @@ -622,25 +664,26 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case NFC_SET_PWR: ret = nfc_ioctl_power_states(nfc_dev, arg); break; - case NFC_SET_RESET_READ_PENDING: - if (arg == NFC_SET_READ_PENDING) { - nfc_dev->cold_reset.is_nfc_read_pending = true; - /* Set default NFC state as NCI for Nfc read pending request */ - nfc_dev->nfc_state = NFC_STATE_NCI; - } - else if (arg == NFC_RESET_READ_PENDING){ - nfc_dev->cold_reset.is_nfc_read_pending = false; - } - else { - ret = -EINVAL; - } - break; + case NFC_SET_RESET_READ_PENDING: + if (arg == NFC_SET_READ_PENDING) { + nfc_dev->cold_reset.is_nfc_read_pending = true; + /* Set default NFC state as NCI for Nfc read pending request */ + nfc_dev->nfc_state = NFC_STATE_NCI; + } else if (arg == NFC_RESET_READ_PENDING) { + nfc_dev->cold_reset.is_nfc_read_pending = false; + } else { + ret = -EINVAL; + } + break; case ESE_SET_PWR: ret = nfc_ese_pwr(nfc_dev, arg); break; case ESE_GET_PWR: ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); break; + case NFC_GET_GPIO_STATUS: + ret = nfc_gpio_info(nfc_dev, arg); + break; case NFCC_GET_INFO: ret = nfc_ioctl_nfcc_info(pfile, arg); break; @@ -663,6 +706,7 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) int nfc_dev_open(struct inode *inode, struct file *filp) { struct nfc_dev *nfc_dev = NULL; + nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); if (!nfc_dev) @@ -719,6 +763,7 @@ int nfc_dev_flush(struct file *pfile, fl_owner_t id) int nfc_dev_close(struct inode *inode, struct file *filp) { struct nfc_dev *nfc_dev = NULL; + nfc_dev = container_of(inode->i_cdev, struct nfc_dev, c_dev); if (!nfc_dev) diff --git a/nfc/common.h b/nfc/common.h index 3bae9b38cb..5f5f5bbdaf 100644 --- a/nfc/common.h +++ b/nfc/common.h @@ -79,13 +79,14 @@ #define MAX_DL_BUFFER_SIZE (DL_HDR_LEN + DL_CRC_LEN + \ MAX_DL_PAYLOAD_LEN) + /* Retry count for normal write */ #define NO_RETRY (1) /* Maximum retry count for standby writes */ #define MAX_RETRY_COUNT (3) #define MAX_WRITE_IRQ_COUNT (5) #define MAX_IRQ_WAIT_TIME (90) -#define WAKEUP_SRC_TIMEOUT (2000) +#define WAKEUP_SRC_TIMEOUT (100) /* command response timeout */ #define NCI_CMD_RSP_TIMEOUT_MS (2000) @@ -104,6 +105,7 @@ #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, uint32_t) #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, uint32_t) #define NFC_SET_RESET_READ_PENDING _IOW(NFC_MAGIC, 0x04, uint32_t) +#define NFC_GET_GPIO_STATUS _IOR(NFC_MAGIC, 0x05, uint32_t) #define NFC_SECURE_ZONE _IOW(NFC_MAGIC, 0x0A, uint32_t) #define DTS_IRQ_GPIO_STR "qcom,sn-irq" @@ -121,6 +123,11 @@ #define NFC_VDDIO_MAX 1950000 //in uV #define NFC_CURRENT_MAX 157000 //in uA +/* Each GPIO occupies consecutive two bits */ +#define GPIO_POS_SHIFT_VAL 2 +/* Two bits to indicate GPIO status (Invalid(-2), Set(1) or Reset(0)) */ +#define GPIO_STATUS_MASK_BITS 3 + //NFC ID for registration with secure libraries #define HW_STATE_UID 0x108 #define HW_OP_GET_STATE 1 @@ -178,8 +185,8 @@ enum nfcc_ioctl_request { }; enum nfc_read_pending { - NFC_RESET_READ_PENDING, - NFC_SET_READ_PENDING, + NFC_RESET_READ_PENDING, + NFC_SET_READ_PENDING, }; /* nfc platform interface type */ @@ -295,7 +302,7 @@ int nfc_dev_open(struct inode *inode, struct file *filp); int nfc_dev_flush(struct file *pfile, fl_owner_t id); int nfc_dev_close(struct inode *inode, struct file *filp); long nfc_dev_compat_ioctl(struct file *pfile, unsigned int cmd, - unsigned long arg); + unsigned long arg); long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg); int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs, uint8_t interface);