Loading drivers/nfc/qti/nfc_common.c +276 −9 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include <linux/of_gpio.h> Loading @@ -8,6 +8,25 @@ #include <linux/delay.h> #include "nfc_common.h" int nfc_read(struct nfc_dev *nfc_dev, char *buf, size_t count) { if (nfc_dev->interface == PLATFORM_IF_I2C) return i2c_read(&nfc_dev->i2c_dev, buf, count); else return i3c_nci_kbuf_retrieve(&nfc_dev->i3c_dev, buf, count); } EXPORT_SYMBOL(nfc_read); int nfc_write(struct nfc_dev *nfc_dev, char *buf, size_t count, uint8_t retry_cnt) { if (nfc_dev->interface == PLATFORM_IF_I2C) return i2c_write(&nfc_dev->i2c_dev, buf, count, retry_cnt); else return i3c_write(&nfc_dev->i3c_dev, buf, count, retry_cnt); } EXPORT_SYMBOL(nfc_write); int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio, uint8_t interface) { Loading Loading @@ -214,13 +233,8 @@ static int send_cold_reset_cmd(struct nfc_dev *nfc_dev) cold_reset_cmd[1] = COLD_RESET_OID; cold_reset_cmd[2] = COLD_RESET_CMD_PAYLOAD_LEN; if (nfc_dev->interface == PLATFORM_IF_I2C) ret = i2c_write(&nfc_dev->i2c_dev, cold_reset_cmd, COLD_RESET_CMD_LEN, MAX_RETRY_COUNT); else ret = i3c_write(&nfc_dev->i3c_dev, cold_reset_cmd, ret = nfc_write(nfc_dev, cold_reset_cmd, COLD_RESET_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) pr_err("%s: write failed after max retry, ret %d\n", __func__, ret); Loading Loading @@ -259,6 +273,7 @@ void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) /* For I3C driver, header is read by the worker thread */ memcpy(cold_reset_rsp, header, NCI_HDR_LEN); } if ((cold_reset_rsp[0] != COLD_RESET_RSP_GID) || (cold_reset_rsp[1] != COLD_RESET_OID)) { pr_err("%s: - invalid response GID or OID for cold_reset\n", Loading @@ -271,6 +286,7 @@ void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) ret = -EINVAL; goto error; } if (nfc_dev->interface == PLATFORM_IF_I2C) ret = i2c_read(&nfc_dev->i2c_dev, &cold_reset_rsp[NCI_PAYLOAD_IDX], Loading Loading @@ -438,6 +454,7 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) */ gpio_set_ven(nfc_dev, 1); if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { gpio_set_value(nfc_dev->gpio.dwl_req, 1); usleep_range(10000, 10100); Loading Loading @@ -503,6 +520,24 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) return ret; } /* * Inside nfc_ioctl_nfcc_info * * @brief nfc_ioctl_nfcc_info * * Check the NFC Chipset and firmware version details */ unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg) { unsigned int r = 0; struct nfc_dev *nfc_dev = filp->private_data; r = nfc_dev->nqx_info.i; pr_debug("nfc : %s r = %d\n", __func__, r); return r; } /** @brief IOCTL function to be used to set or get data from upper layer. * * @param pfile fil node for opened device. Loading Loading @@ -531,6 +566,9 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case ESE_GET_PWR: ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); break; case NFCC_GET_INFO: ret = nfc_ioctl_nfcc_info(pfile, arg); break; default: pr_err("%s bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; Loading Loading @@ -600,3 +638,232 @@ int nfc_dev_close(struct inode *inode, struct file *filp) return 0; } EXPORT_SYMBOL(nfc_dev_close); int is_data_available_for_read(struct nfc_dev *nfc_dev) { int ret; enable_interrupt(nfc_dev); ret = wait_event_interruptible_timeout(nfc_dev->read_wq, !nfc_dev->i2c_dev.irq_enabled, msecs_to_jiffies(MAX_IRQ_WAIT_TIME)); return ret; } /* Check for availability of NFC controller hardware */ int nfcc_hw_check(struct nfc_dev *nfc_dev) { int ret = 0; unsigned char reset_ntf_len = 0; char *nci_reset_cmd = NULL; char *nci_reset_rsp = NULL; char *nci_reset_ntf = NULL; char *nci_get_version_cmd = NULL; char *nci_get_version_rsp = NULL; nci_reset_cmd = kzalloc(NCI_RESET_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_reset_cmd) return -ENOMEM; nci_reset_rsp = kzalloc(NCI_RESET_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_reset_rsp) { ret = -ENOMEM; goto done; } nci_reset_ntf = kzalloc(NCI_RESET_NTF_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_reset_ntf) { ret = -ENOMEM; goto done; } nci_get_version_cmd = kzalloc(NCI_GET_VERSION_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_get_version_cmd) { ret = -ENOMEM; goto done; } nci_get_version_rsp = kzalloc(NCI_GET_VERSION_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_get_version_rsp) { ret = -ENOMEM; goto done; } if (nfc_dev->interface == PLATFORM_IF_I3C) enable_interrupt(nfc_dev); else { /* making sure that the NFCC starts in a clean state. */ gpio_set_ven(nfc_dev, 1);/* HPD : Enable*/ gpio_set_ven(nfc_dev, 0);/* ULPM: Disable */ gpio_set_ven(nfc_dev, 1);/* HPD : Enable*/ } nci_reset_cmd[0] = 0x20; nci_reset_cmd[1] = 0x00; nci_reset_cmd[2] = 0x01; nci_reset_cmd[3] = 0x00; /* send NCI CORE RESET CMD with Keep Config parameters */ ret = nfc_write(nfc_dev, nci_reset_cmd, NCI_RESET_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) { pr_err("%s: - nfc core reset error\n", __func__); if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { gpio_set_value(nfc_dev->gpio.dwl_req, 1); usleep_range(10000, 10100); } if (nfc_dev->interface == PLATFORM_IF_I2C) { gpio_set_ven(nfc_dev, 0); gpio_set_ven(nfc_dev, 1); } nci_get_version_cmd[0] = 0x00; nci_get_version_cmd[1] = 0x04; nci_get_version_cmd[2] = 0xF1; nci_get_version_cmd[3] = 0x00; nci_get_version_cmd[4] = 0x00; nci_get_version_cmd[5] = 0x00; nci_get_version_cmd[6] = 0x6E; nci_get_version_cmd[7] = 0xEF; ret = nfc_write(nfc_dev, nci_get_version_cmd, NCI_GET_VERSION_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) { pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); goto err_nfcc_hw_check; } if (nfc_dev->interface == PLATFORM_IF_I2C) { ret = is_data_available_for_read(nfc_dev); if (ret <= 0) { disable_interrupt(nfc_dev); pr_err("%s: - error waiting for get version rsp ret %d\n", __func__, ret); goto err_nfcc_hw_check; } } ret = nfc_read(nfc_dev, nci_get_version_rsp, NCI_GET_VERSION_RSP_LEN); if (ret <= 0) { pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); goto err_nfcc_hw_check; } else { nfc_dev->nqx_info.info.chip_type = nci_get_version_rsp[3]; nfc_dev->nqx_info.info.rom_version = nci_get_version_rsp[4]; nfc_dev->nqx_info.info.fw_minor = nci_get_version_rsp[6]; nfc_dev->nqx_info.info.fw_major = nci_get_version_rsp[7]; } gpio_set_value(nfc_dev->gpio.dwl_req, 0); goto err_nfcc_reset_failed; } if (nfc_dev->interface == PLATFORM_IF_I2C) { ret = is_data_available_for_read(nfc_dev); if (ret <= 0) { disable_interrupt(nfc_dev); pr_err("%s: - error waiting for core reset rsp ret %d\n", __func__, ret); goto err_nfcc_hw_check; } } /* Read Response of RESET command */ ret = nfc_read(nfc_dev, nci_reset_rsp, NCI_RESET_RSP_LEN); if (ret <= 0) { pr_err("%s: - nfc rst rsp read err %d\n", __func__, ret); goto err_nfcc_hw_check; } if (nfc_dev->interface == PLATFORM_IF_I2C) { ret = is_data_available_for_read(nfc_dev); if (ret <= 0) { pr_err("%s: - error waiting for core reset ntf ret %d\n", __func__, ret); disable_interrupt(nfc_dev); goto err_nfcc_hw_check; } } /* Read Notification of RESET command */ ret = nfc_read(nfc_dev, nci_reset_ntf, NCI_RESET_NTF_LEN); if (ret <= 0) { pr_err("%s: nfc nfc read error %d\n", __func__, ret); goto err_nfcc_hw_check; } reset_ntf_len = NCI_HDR_LEN + nci_reset_ntf[NCI_PAYLOAD_LEN_IDX] - 1; if (reset_ntf_len > NCI_HDR_LEN) { nfc_dev->nqx_info.info.chip_type = nci_reset_ntf[reset_ntf_len - NFC_CHIP_TYPE_OFF]; nfc_dev->nqx_info.info.rom_version = nci_reset_ntf[reset_ntf_len - NFC_ROM_VERSION_OFF]; nfc_dev->nqx_info.info.fw_major = nci_reset_ntf[reset_ntf_len - NFC_FW_MAJOR_OFF]; nfc_dev->nqx_info.info.fw_minor = nci_reset_ntf[reset_ntf_len]; } pr_debug("%s: - NFC reset rsp : NfcNciRx %x %x %x\n", __func__, nci_reset_rsp[0], nci_reset_rsp[1], nci_reset_rsp[2]); err_nfcc_reset_failed: pr_info("NFC chip_type = %x\n", nfc_dev->nqx_info.info.chip_type); pr_info("NFC fw version = %x.%x.%x\n", nfc_dev->nqx_info.info.rom_version, nfc_dev->nqx_info.info.fw_major, nfc_dev->nqx_info.info.fw_minor); switch (nfc_dev->nqx_info.info.chip_type) { case NFCC_SN100_A: case NFCC_SN100_B: pr_debug("%s: ## NFCC == SN100x ##\n", __func__); break; default: pr_err("%s: - NFCC HW not Supported\n", __func__); break; } ret = 0; nfc_dev->nfc_ven_enabled = true; goto disable_i3c_intr; err_nfcc_hw_check: if (nfc_dev->interface == PLATFORM_IF_I2C) gpio_set_ven(nfc_dev, 0); gpio_set_value(nfc_dev->gpio.dwl_req, 0); ret = -ENXIO; pr_debug("%s: - NFCC HW not available\n", __func__); disable_i3c_intr: if (nfc_dev->interface == PLATFORM_IF_I3C) disable_interrupt(nfc_dev); done: kfree(nci_reset_rsp); kfree(nci_reset_ntf); kfree(nci_get_version_cmd); kfree(nci_get_version_rsp); kfree(nci_reset_cmd); return ret; } EXPORT_SYMBOL(nfcc_hw_check); drivers/nfc/qti/nfc_common.h +24 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _NFC_COMMON_H_ Loading @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/nfcinfo.h> #include "nfc_i2c_drv.h" #include "nfc_i3c_drv.h" Loading @@ -38,6 +39,19 @@ // HDR length of NCI packet #define NCI_HDR_LEN 3 #define NCI_PAYLOAD_IDX 3 #define NCI_PAYLOAD_LEN_IDX 2 #define NCI_RESET_CMD_LEN (4) #define NCI_RESET_RSP_LEN (4) #define NCI_RESET_NTF_LEN (13) #define NCI_GET_VERSION_CMD_LEN (8) #define NCI_GET_VERSION_RSP_LEN (12) // Below offsets should be subtracted from core reset ntf len #define NFC_CHIP_TYPE_OFF (3) #define NFC_ROM_VERSION_OFF (2) #define NFC_FW_MAJOR_OFF (1) #define COLD_RESET_CMD_LEN 3 #define COLD_RESET_RSP_LEN 4 Loading Loading @@ -134,6 +148,12 @@ enum gpio_values { GPIO_IRQ = 0x4, }; enum nfcc_chip_variant { NFCC_SN100_A = 0xa3, /**< NFCC SN100_A */ NFCC_SN100_B = 0xa4, /**< NFCC SN100_B */ NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */ }; // NFC GPIO variables struct platform_gpio { unsigned int irq; Loading Loading @@ -175,6 +195,8 @@ struct nfc_dev { /* read buffer*/ size_t kbuflen; u8 *kbuf; union nqx_uinfo nqx_info; }; int nfc_dev_open(struct inode *inode, struct file *filp); Loading @@ -189,5 +211,6 @@ void nfc_misc_remove(struct nfc_dev *nfc_dev, int count); int configure_gpio(unsigned int gpio, int flag); void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header); void gpio_set_ven(struct nfc_dev *nfc_dev, int value); int nfcc_hw_check(struct nfc_dev *nfc_dev); #endif //_NFC_COMMON_H_ drivers/nfc/qti/nfc_i2c_drv.c +27 −21 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include "nfc_common.h" Loading Loading @@ -133,24 +133,26 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, i2c_dev->irq_enabled = true; enable_irq(i2c_dev->client->irq); } if (!gpio_get_value(nfc_dev->gpio.irq)) { ret = wait_event_interruptible(nfc_dev->read_wq, !i2c_dev->irq_enabled); if (ret) { pr_err("error wakeup of read wq\n"); goto err; } } i2c_disable_irq(i2c_dev); if (gpio_get_value(nfc_dev->gpio.irq)) break; if (!gpio_get_value(nfc_dev->gpio.ven)) { pr_info("%s: releasing read\n", __func__); ret = -EIO; pr_info("%s: ven low in read !\n", __func__); ret = -ENODEV; goto err; } if (gpio_get_value(nfc_dev->gpio.irq)) break; pr_warn("%s: spurious interrupt detected\n", __func__); } } Loading Loading @@ -332,20 +334,22 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_nfc_misc_remove; } i2c_disable_irq(i2c_dev); device_init_wakeup(&client->dev, true); device_set_wakeup_capable(&client->dev, true); i2c_set_clientdata(client, nfc_dev); ret = nfcc_hw_check(nfc_dev); if (ret) { pr_err("nfc hw check failed ret %d\n", ret); goto err_nfcc_hw_check; } device_init_wakeup(&client->dev, true); i2c_dev->irq_wake_up = false; //SET VEN GPIO LOW and HIGH gpio_set_value(nfc_dev->gpio.ven, 0); usleep_range(10000, 10100); gpio_set_value(nfc_dev->gpio.ven, 1); usleep_range(10000, 10100); nfc_dev->nfc_ven_enabled = true; pr_info("%s success\n", __func__); return 0; err_nfcc_hw_check: free_irq(client->irq, nfc_dev); err_nfc_misc_remove: nfc_misc_remove(nfc_dev, DEV_COUNT); err_mutex_destroy: Loading Loading @@ -377,6 +381,7 @@ int nfc_i2c_dev_remove(struct i2c_client *client) ret = -ENODEV; return ret; } device_init_wakeup(&client->dev, false); free_irq(client->irq, nfc_dev); nfc_misc_remove(nfc_dev, DEV_COUNT); mutex_destroy(&nfc_dev->dev_ref_mutex); Loading Loading @@ -456,8 +461,9 @@ static int __init nfc_i2c_dev_init(void) { int ret = 0; pr_info("Loading NFC I2C driver\n"); ret = i2c_add_driver(&nfc_i2c_dev_driver); if (ret != 0) pr_err("NFC I2C add driver error ret %d\n", ret); return ret; } Loading @@ -465,7 +471,7 @@ module_init(nfc_i2c_dev_init); static void __exit nfc_i2c_dev_exit(void) { pr_info("Unloading NFC I2C driver\n"); pr_debug("Unloading NFC I2C driver\n"); i2c_del_driver(&nfc_i2c_dev_driver); } Loading drivers/nfc/qti/nfc_i3c_drv.c +19 −12 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include "nfc_common.h" Loading Loading @@ -154,7 +154,7 @@ static ssize_t i3c_kbuf_store(struct i3c_dev *i3c_dev, const char *buf, * * @return number of bytes copied , error code for failures . */ static ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, size_t count) { size_t requested_size = count; Loading Loading @@ -204,7 +204,7 @@ static ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, if (ret != 0) { pr_err("didn't get completion, interrupted!! ret %d\n", ret); return -EINVAL; return ret; } } while (available_size < requested_size); Loading Loading @@ -245,6 +245,7 @@ static ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, pr_debug("%s , count = %zx exit\n", __func__, count); return count; } EXPORT_SYMBOL(i3c_nci_kbuf_retrieve); /** @brief This API can be used to read data from I3C device from HAL layer. * Loading Loading @@ -275,7 +276,7 @@ ssize_t nfc_i3c_dev_read(struct file *filp, char __user *buf, tmp = nfc_dev->kbuf; ret = i3c_nci_kbuf_retrieve(i3c_dev, tmp, count); if (ret != count) { pr_err("%s: buf read from I3C device returned error (%d)\n", pr_err("%s: kbuf read err ret (%d)\n", __func__, ret); ret = -EIO; } else if (copy_to_user(buf, tmp, ret)) { Loading Loading @@ -322,7 +323,7 @@ ssize_t nfc_i3c_dev_write(struct file *filp, const char __user *buf, ret = i3c_write(i3c_dev, tmp, count, NO_RETRY); if (ret != count) { pr_err("%s: failed to write %d\n", __func__, ret); pr_err("%s: i3c_write err ret %d\n", __func__, ret); ret = -EIO; goto out_free; } Loading Loading @@ -364,7 +365,7 @@ static void i3c_workqueue_handler(struct work_struct *work) pr_err("%s: No memory to copy read data\n", __func__); return; } pr_info("%s: hdr_len = %d\n", __func__, hdr_len); pr_debug("%s: hdr_len = %d\n", __func__, hdr_len); memset(tmp, 0x00, i3c_dev->read_kbuf_len); ret = i3c_read(i3c_dev, tmp, hdr_len); Loading Loading @@ -419,7 +420,7 @@ static void i3c_ibi_handler(struct i3c_device *device, struct nfc_dev *nfc_dev = i3cdev_get_drvdata(device); struct i3c_dev *i3c_dev = &nfc_dev->i3c_dev; pr_debug("%s: Received read IBI request from slave\n", __func__); pr_debug("%s\n", __func__); if (device_may_wakeup(&device->dev)) pm_wakeup_event(&device->dev, WAKEUP_SRC_TIMEOUT); Loading Loading @@ -665,15 +666,21 @@ int nfc_i3c_dev_probe(struct i3c_device *device) goto err_nfc_misc_remove; } atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_NORMAL); ret = nfcc_hw_check(nfc_dev); if (ret) { pr_err("nfc hw check failed ret %d\n", ret); goto err_nfcc_hw_check; } atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_NORMAL); device_init_wakeup(&device->dev, true); device_set_wakeup_capable(&device->dev, true); pr_info("%s success\n", __func__); return 0; err_nfcc_hw_check: i3c_device_free_ibi(device); err_nfc_misc_remove: nfc_misc_remove(nfc_dev, DEV_COUNT); err_wq_destroy: Loading Loading @@ -825,9 +832,9 @@ static int __init nfc_dev_i3c_init(void) { int ret = 0; pr_info("Loading NFC I3C driver\n"); ret = i3c_driver_register_with_owner(&nfc_i3c_dev_driver, THIS_MODULE); pr_debug("NFC i3c driver register ret = %d\n", ret); if (ret != 0) pr_err("NFC I3C driver register error ret = %d\n", ret); return ret; } Loading @@ -835,7 +842,7 @@ module_init(nfc_dev_i3c_init); static void __exit nfc_i3c_dev_exit(void) { pr_info("Unloading NFC I3C driver\n"); pr_debug("Unloading NFC I3C driver\n"); i3c_driver_unregister(&nfc_i3c_dev_driver); } Loading drivers/nfc/qti/nfc_i3c_drv.h +10 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _NFC_I3C_DRV_H_ Loading Loading @@ -96,6 +96,8 @@ int i3c_disable_ibi(struct i3c_dev *i3c_dev); ssize_t i3c_write(struct i3c_dev *i3c_dev, const char *buf, const size_t count, int max_retry_cnt); ssize_t i3c_read(struct i3c_dev *i3c_dev, char *buf, size_t count); ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, size_t count); #else Loading @@ -116,7 +118,13 @@ static inline ssize_t i3c_write(struct i3c_dev *i3c_dev, } static inline ssize_t i3c_read(struct i3c_dev *i3c_dev, char *buf, size_t count); char *buf, size_t count) { return -ENXIO; } ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, size_t count) { return -ENXIO; } Loading Loading
drivers/nfc/qti/nfc_common.c +276 −9 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include <linux/of_gpio.h> Loading @@ -8,6 +8,25 @@ #include <linux/delay.h> #include "nfc_common.h" int nfc_read(struct nfc_dev *nfc_dev, char *buf, size_t count) { if (nfc_dev->interface == PLATFORM_IF_I2C) return i2c_read(&nfc_dev->i2c_dev, buf, count); else return i3c_nci_kbuf_retrieve(&nfc_dev->i3c_dev, buf, count); } EXPORT_SYMBOL(nfc_read); int nfc_write(struct nfc_dev *nfc_dev, char *buf, size_t count, uint8_t retry_cnt) { if (nfc_dev->interface == PLATFORM_IF_I2C) return i2c_write(&nfc_dev->i2c_dev, buf, count, retry_cnt); else return i3c_write(&nfc_dev->i3c_dev, buf, count, retry_cnt); } EXPORT_SYMBOL(nfc_write); int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio, uint8_t interface) { Loading Loading @@ -214,13 +233,8 @@ static int send_cold_reset_cmd(struct nfc_dev *nfc_dev) cold_reset_cmd[1] = COLD_RESET_OID; cold_reset_cmd[2] = COLD_RESET_CMD_PAYLOAD_LEN; if (nfc_dev->interface == PLATFORM_IF_I2C) ret = i2c_write(&nfc_dev->i2c_dev, cold_reset_cmd, COLD_RESET_CMD_LEN, MAX_RETRY_COUNT); else ret = i3c_write(&nfc_dev->i3c_dev, cold_reset_cmd, ret = nfc_write(nfc_dev, cold_reset_cmd, COLD_RESET_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) pr_err("%s: write failed after max retry, ret %d\n", __func__, ret); Loading Loading @@ -259,6 +273,7 @@ void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) /* For I3C driver, header is read by the worker thread */ memcpy(cold_reset_rsp, header, NCI_HDR_LEN); } if ((cold_reset_rsp[0] != COLD_RESET_RSP_GID) || (cold_reset_rsp[1] != COLD_RESET_OID)) { pr_err("%s: - invalid response GID or OID for cold_reset\n", Loading @@ -271,6 +286,7 @@ void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) ret = -EINVAL; goto error; } if (nfc_dev->interface == PLATFORM_IF_I2C) ret = i2c_read(&nfc_dev->i2c_dev, &cold_reset_rsp[NCI_PAYLOAD_IDX], Loading Loading @@ -438,6 +454,7 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) */ gpio_set_ven(nfc_dev, 1); if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { gpio_set_value(nfc_dev->gpio.dwl_req, 1); usleep_range(10000, 10100); Loading Loading @@ -503,6 +520,24 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg) return ret; } /* * Inside nfc_ioctl_nfcc_info * * @brief nfc_ioctl_nfcc_info * * Check the NFC Chipset and firmware version details */ unsigned int nfc_ioctl_nfcc_info(struct file *filp, unsigned long arg) { unsigned int r = 0; struct nfc_dev *nfc_dev = filp->private_data; r = nfc_dev->nqx_info.i; pr_debug("nfc : %s r = %d\n", __func__, r); return r; } /** @brief IOCTL function to be used to set or get data from upper layer. * * @param pfile fil node for opened device. Loading Loading @@ -531,6 +566,9 @@ long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) case ESE_GET_PWR: ret = nfc_ese_pwr(nfc_dev, ESE_POWER_STATE); break; case NFCC_GET_INFO: ret = nfc_ioctl_nfcc_info(pfile, arg); break; default: pr_err("%s bad cmd %lu\n", __func__, arg); ret = -ENOIOCTLCMD; Loading Loading @@ -600,3 +638,232 @@ int nfc_dev_close(struct inode *inode, struct file *filp) return 0; } EXPORT_SYMBOL(nfc_dev_close); int is_data_available_for_read(struct nfc_dev *nfc_dev) { int ret; enable_interrupt(nfc_dev); ret = wait_event_interruptible_timeout(nfc_dev->read_wq, !nfc_dev->i2c_dev.irq_enabled, msecs_to_jiffies(MAX_IRQ_WAIT_TIME)); return ret; } /* Check for availability of NFC controller hardware */ int nfcc_hw_check(struct nfc_dev *nfc_dev) { int ret = 0; unsigned char reset_ntf_len = 0; char *nci_reset_cmd = NULL; char *nci_reset_rsp = NULL; char *nci_reset_ntf = NULL; char *nci_get_version_cmd = NULL; char *nci_get_version_rsp = NULL; nci_reset_cmd = kzalloc(NCI_RESET_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_reset_cmd) return -ENOMEM; nci_reset_rsp = kzalloc(NCI_RESET_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_reset_rsp) { ret = -ENOMEM; goto done; } nci_reset_ntf = kzalloc(NCI_RESET_NTF_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_reset_ntf) { ret = -ENOMEM; goto done; } nci_get_version_cmd = kzalloc(NCI_GET_VERSION_CMD_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_get_version_cmd) { ret = -ENOMEM; goto done; } nci_get_version_rsp = kzalloc(NCI_GET_VERSION_RSP_LEN + 1, GFP_DMA | GFP_KERNEL); if (!nci_get_version_rsp) { ret = -ENOMEM; goto done; } if (nfc_dev->interface == PLATFORM_IF_I3C) enable_interrupt(nfc_dev); else { /* making sure that the NFCC starts in a clean state. */ gpio_set_ven(nfc_dev, 1);/* HPD : Enable*/ gpio_set_ven(nfc_dev, 0);/* ULPM: Disable */ gpio_set_ven(nfc_dev, 1);/* HPD : Enable*/ } nci_reset_cmd[0] = 0x20; nci_reset_cmd[1] = 0x00; nci_reset_cmd[2] = 0x01; nci_reset_cmd[3] = 0x00; /* send NCI CORE RESET CMD with Keep Config parameters */ ret = nfc_write(nfc_dev, nci_reset_cmd, NCI_RESET_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) { pr_err("%s: - nfc core reset error\n", __func__); if (gpio_is_valid(nfc_dev->gpio.dwl_req)) { gpio_set_value(nfc_dev->gpio.dwl_req, 1); usleep_range(10000, 10100); } if (nfc_dev->interface == PLATFORM_IF_I2C) { gpio_set_ven(nfc_dev, 0); gpio_set_ven(nfc_dev, 1); } nci_get_version_cmd[0] = 0x00; nci_get_version_cmd[1] = 0x04; nci_get_version_cmd[2] = 0xF1; nci_get_version_cmd[3] = 0x00; nci_get_version_cmd[4] = 0x00; nci_get_version_cmd[5] = 0x00; nci_get_version_cmd[6] = 0x6E; nci_get_version_cmd[7] = 0xEF; ret = nfc_write(nfc_dev, nci_get_version_cmd, NCI_GET_VERSION_CMD_LEN, MAX_RETRY_COUNT); if (ret <= 0) { pr_err("%s: - nfc get version cmd error ret %d\n", __func__, ret); goto err_nfcc_hw_check; } if (nfc_dev->interface == PLATFORM_IF_I2C) { ret = is_data_available_for_read(nfc_dev); if (ret <= 0) { disable_interrupt(nfc_dev); pr_err("%s: - error waiting for get version rsp ret %d\n", __func__, ret); goto err_nfcc_hw_check; } } ret = nfc_read(nfc_dev, nci_get_version_rsp, NCI_GET_VERSION_RSP_LEN); if (ret <= 0) { pr_err("%s: - nfc get version rsp error ret %d\n", __func__, ret); goto err_nfcc_hw_check; } else { nfc_dev->nqx_info.info.chip_type = nci_get_version_rsp[3]; nfc_dev->nqx_info.info.rom_version = nci_get_version_rsp[4]; nfc_dev->nqx_info.info.fw_minor = nci_get_version_rsp[6]; nfc_dev->nqx_info.info.fw_major = nci_get_version_rsp[7]; } gpio_set_value(nfc_dev->gpio.dwl_req, 0); goto err_nfcc_reset_failed; } if (nfc_dev->interface == PLATFORM_IF_I2C) { ret = is_data_available_for_read(nfc_dev); if (ret <= 0) { disable_interrupt(nfc_dev); pr_err("%s: - error waiting for core reset rsp ret %d\n", __func__, ret); goto err_nfcc_hw_check; } } /* Read Response of RESET command */ ret = nfc_read(nfc_dev, nci_reset_rsp, NCI_RESET_RSP_LEN); if (ret <= 0) { pr_err("%s: - nfc rst rsp read err %d\n", __func__, ret); goto err_nfcc_hw_check; } if (nfc_dev->interface == PLATFORM_IF_I2C) { ret = is_data_available_for_read(nfc_dev); if (ret <= 0) { pr_err("%s: - error waiting for core reset ntf ret %d\n", __func__, ret); disable_interrupt(nfc_dev); goto err_nfcc_hw_check; } } /* Read Notification of RESET command */ ret = nfc_read(nfc_dev, nci_reset_ntf, NCI_RESET_NTF_LEN); if (ret <= 0) { pr_err("%s: nfc nfc read error %d\n", __func__, ret); goto err_nfcc_hw_check; } reset_ntf_len = NCI_HDR_LEN + nci_reset_ntf[NCI_PAYLOAD_LEN_IDX] - 1; if (reset_ntf_len > NCI_HDR_LEN) { nfc_dev->nqx_info.info.chip_type = nci_reset_ntf[reset_ntf_len - NFC_CHIP_TYPE_OFF]; nfc_dev->nqx_info.info.rom_version = nci_reset_ntf[reset_ntf_len - NFC_ROM_VERSION_OFF]; nfc_dev->nqx_info.info.fw_major = nci_reset_ntf[reset_ntf_len - NFC_FW_MAJOR_OFF]; nfc_dev->nqx_info.info.fw_minor = nci_reset_ntf[reset_ntf_len]; } pr_debug("%s: - NFC reset rsp : NfcNciRx %x %x %x\n", __func__, nci_reset_rsp[0], nci_reset_rsp[1], nci_reset_rsp[2]); err_nfcc_reset_failed: pr_info("NFC chip_type = %x\n", nfc_dev->nqx_info.info.chip_type); pr_info("NFC fw version = %x.%x.%x\n", nfc_dev->nqx_info.info.rom_version, nfc_dev->nqx_info.info.fw_major, nfc_dev->nqx_info.info.fw_minor); switch (nfc_dev->nqx_info.info.chip_type) { case NFCC_SN100_A: case NFCC_SN100_B: pr_debug("%s: ## NFCC == SN100x ##\n", __func__); break; default: pr_err("%s: - NFCC HW not Supported\n", __func__); break; } ret = 0; nfc_dev->nfc_ven_enabled = true; goto disable_i3c_intr; err_nfcc_hw_check: if (nfc_dev->interface == PLATFORM_IF_I2C) gpio_set_ven(nfc_dev, 0); gpio_set_value(nfc_dev->gpio.dwl_req, 0); ret = -ENXIO; pr_debug("%s: - NFCC HW not available\n", __func__); disable_i3c_intr: if (nfc_dev->interface == PLATFORM_IF_I3C) disable_interrupt(nfc_dev); done: kfree(nci_reset_rsp); kfree(nci_reset_ntf); kfree(nci_get_version_cmd); kfree(nci_get_version_rsp); kfree(nci_reset_cmd); return ret; } EXPORT_SYMBOL(nfcc_hw_check);
drivers/nfc/qti/nfc_common.h +24 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _NFC_COMMON_H_ Loading @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/nfcinfo.h> #include "nfc_i2c_drv.h" #include "nfc_i3c_drv.h" Loading @@ -38,6 +39,19 @@ // HDR length of NCI packet #define NCI_HDR_LEN 3 #define NCI_PAYLOAD_IDX 3 #define NCI_PAYLOAD_LEN_IDX 2 #define NCI_RESET_CMD_LEN (4) #define NCI_RESET_RSP_LEN (4) #define NCI_RESET_NTF_LEN (13) #define NCI_GET_VERSION_CMD_LEN (8) #define NCI_GET_VERSION_RSP_LEN (12) // Below offsets should be subtracted from core reset ntf len #define NFC_CHIP_TYPE_OFF (3) #define NFC_ROM_VERSION_OFF (2) #define NFC_FW_MAJOR_OFF (1) #define COLD_RESET_CMD_LEN 3 #define COLD_RESET_RSP_LEN 4 Loading Loading @@ -134,6 +148,12 @@ enum gpio_values { GPIO_IRQ = 0x4, }; enum nfcc_chip_variant { NFCC_SN100_A = 0xa3, /**< NFCC SN100_A */ NFCC_SN100_B = 0xa4, /**< NFCC SN100_B */ NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */ }; // NFC GPIO variables struct platform_gpio { unsigned int irq; Loading Loading @@ -175,6 +195,8 @@ struct nfc_dev { /* read buffer*/ size_t kbuflen; u8 *kbuf; union nqx_uinfo nqx_info; }; int nfc_dev_open(struct inode *inode, struct file *filp); Loading @@ -189,5 +211,6 @@ void nfc_misc_remove(struct nfc_dev *nfc_dev, int count); int configure_gpio(unsigned int gpio, int flag); void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header); void gpio_set_ven(struct nfc_dev *nfc_dev, int value); int nfcc_hw_check(struct nfc_dev *nfc_dev); #endif //_NFC_COMMON_H_
drivers/nfc/qti/nfc_i2c_drv.c +27 −21 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include "nfc_common.h" Loading Loading @@ -133,24 +133,26 @@ ssize_t nfc_i2c_dev_read(struct file *filp, char __user *buf, i2c_dev->irq_enabled = true; enable_irq(i2c_dev->client->irq); } if (!gpio_get_value(nfc_dev->gpio.irq)) { ret = wait_event_interruptible(nfc_dev->read_wq, !i2c_dev->irq_enabled); if (ret) { pr_err("error wakeup of read wq\n"); goto err; } } i2c_disable_irq(i2c_dev); if (gpio_get_value(nfc_dev->gpio.irq)) break; if (!gpio_get_value(nfc_dev->gpio.ven)) { pr_info("%s: releasing read\n", __func__); ret = -EIO; pr_info("%s: ven low in read !\n", __func__); ret = -ENODEV; goto err; } if (gpio_get_value(nfc_dev->gpio.irq)) break; pr_warn("%s: spurious interrupt detected\n", __func__); } } Loading Loading @@ -332,20 +334,22 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_nfc_misc_remove; } i2c_disable_irq(i2c_dev); device_init_wakeup(&client->dev, true); device_set_wakeup_capable(&client->dev, true); i2c_set_clientdata(client, nfc_dev); ret = nfcc_hw_check(nfc_dev); if (ret) { pr_err("nfc hw check failed ret %d\n", ret); goto err_nfcc_hw_check; } device_init_wakeup(&client->dev, true); i2c_dev->irq_wake_up = false; //SET VEN GPIO LOW and HIGH gpio_set_value(nfc_dev->gpio.ven, 0); usleep_range(10000, 10100); gpio_set_value(nfc_dev->gpio.ven, 1); usleep_range(10000, 10100); nfc_dev->nfc_ven_enabled = true; pr_info("%s success\n", __func__); return 0; err_nfcc_hw_check: free_irq(client->irq, nfc_dev); err_nfc_misc_remove: nfc_misc_remove(nfc_dev, DEV_COUNT); err_mutex_destroy: Loading Loading @@ -377,6 +381,7 @@ int nfc_i2c_dev_remove(struct i2c_client *client) ret = -ENODEV; return ret; } device_init_wakeup(&client->dev, false); free_irq(client->irq, nfc_dev); nfc_misc_remove(nfc_dev, DEV_COUNT); mutex_destroy(&nfc_dev->dev_ref_mutex); Loading Loading @@ -456,8 +461,9 @@ static int __init nfc_i2c_dev_init(void) { int ret = 0; pr_info("Loading NFC I2C driver\n"); ret = i2c_add_driver(&nfc_i2c_dev_driver); if (ret != 0) pr_err("NFC I2C add driver error ret %d\n", ret); return ret; } Loading @@ -465,7 +471,7 @@ module_init(nfc_i2c_dev_init); static void __exit nfc_i2c_dev_exit(void) { pr_info("Unloading NFC I2C driver\n"); pr_debug("Unloading NFC I2C driver\n"); i2c_del_driver(&nfc_i2c_dev_driver); } Loading
drivers/nfc/qti/nfc_i3c_drv.c +19 −12 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #include "nfc_common.h" Loading Loading @@ -154,7 +154,7 @@ static ssize_t i3c_kbuf_store(struct i3c_dev *i3c_dev, const char *buf, * * @return number of bytes copied , error code for failures . */ static ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, size_t count) { size_t requested_size = count; Loading Loading @@ -204,7 +204,7 @@ static ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, if (ret != 0) { pr_err("didn't get completion, interrupted!! ret %d\n", ret); return -EINVAL; return ret; } } while (available_size < requested_size); Loading Loading @@ -245,6 +245,7 @@ static ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, pr_debug("%s , count = %zx exit\n", __func__, count); return count; } EXPORT_SYMBOL(i3c_nci_kbuf_retrieve); /** @brief This API can be used to read data from I3C device from HAL layer. * Loading Loading @@ -275,7 +276,7 @@ ssize_t nfc_i3c_dev_read(struct file *filp, char __user *buf, tmp = nfc_dev->kbuf; ret = i3c_nci_kbuf_retrieve(i3c_dev, tmp, count); if (ret != count) { pr_err("%s: buf read from I3C device returned error (%d)\n", pr_err("%s: kbuf read err ret (%d)\n", __func__, ret); ret = -EIO; } else if (copy_to_user(buf, tmp, ret)) { Loading Loading @@ -322,7 +323,7 @@ ssize_t nfc_i3c_dev_write(struct file *filp, const char __user *buf, ret = i3c_write(i3c_dev, tmp, count, NO_RETRY); if (ret != count) { pr_err("%s: failed to write %d\n", __func__, ret); pr_err("%s: i3c_write err ret %d\n", __func__, ret); ret = -EIO; goto out_free; } Loading Loading @@ -364,7 +365,7 @@ static void i3c_workqueue_handler(struct work_struct *work) pr_err("%s: No memory to copy read data\n", __func__); return; } pr_info("%s: hdr_len = %d\n", __func__, hdr_len); pr_debug("%s: hdr_len = %d\n", __func__, hdr_len); memset(tmp, 0x00, i3c_dev->read_kbuf_len); ret = i3c_read(i3c_dev, tmp, hdr_len); Loading Loading @@ -419,7 +420,7 @@ static void i3c_ibi_handler(struct i3c_device *device, struct nfc_dev *nfc_dev = i3cdev_get_drvdata(device); struct i3c_dev *i3c_dev = &nfc_dev->i3c_dev; pr_debug("%s: Received read IBI request from slave\n", __func__); pr_debug("%s\n", __func__); if (device_may_wakeup(&device->dev)) pm_wakeup_event(&device->dev, WAKEUP_SRC_TIMEOUT); Loading Loading @@ -665,15 +666,21 @@ int nfc_i3c_dev_probe(struct i3c_device *device) goto err_nfc_misc_remove; } atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_NORMAL); ret = nfcc_hw_check(nfc_dev); if (ret) { pr_err("nfc hw check failed ret %d\n", ret); goto err_nfcc_hw_check; } atomic_set(&nfc_dev->i3c_dev.pm_state, PM_STATE_NORMAL); device_init_wakeup(&device->dev, true); device_set_wakeup_capable(&device->dev, true); pr_info("%s success\n", __func__); return 0; err_nfcc_hw_check: i3c_device_free_ibi(device); err_nfc_misc_remove: nfc_misc_remove(nfc_dev, DEV_COUNT); err_wq_destroy: Loading Loading @@ -825,9 +832,9 @@ static int __init nfc_dev_i3c_init(void) { int ret = 0; pr_info("Loading NFC I3C driver\n"); ret = i3c_driver_register_with_owner(&nfc_i3c_dev_driver, THIS_MODULE); pr_debug("NFC i3c driver register ret = %d\n", ret); if (ret != 0) pr_err("NFC I3C driver register error ret = %d\n", ret); return ret; } Loading @@ -835,7 +842,7 @@ module_init(nfc_dev_i3c_init); static void __exit nfc_i3c_dev_exit(void) { pr_info("Unloading NFC I3C driver\n"); pr_debug("Unloading NFC I3C driver\n"); i3c_driver_unregister(&nfc_i3c_dev_driver); } Loading
drivers/nfc/qti/nfc_i3c_drv.h +10 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ #ifndef _NFC_I3C_DRV_H_ Loading Loading @@ -96,6 +96,8 @@ int i3c_disable_ibi(struct i3c_dev *i3c_dev); ssize_t i3c_write(struct i3c_dev *i3c_dev, const char *buf, const size_t count, int max_retry_cnt); ssize_t i3c_read(struct i3c_dev *i3c_dev, char *buf, size_t count); ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, size_t count); #else Loading @@ -116,7 +118,13 @@ static inline ssize_t i3c_write(struct i3c_dev *i3c_dev, } static inline ssize_t i3c_read(struct i3c_dev *i3c_dev, char *buf, size_t count); char *buf, size_t count) { return -ENXIO; } ssize_t i3c_nci_kbuf_retrieve(struct i3c_dev *i3c_dev, char *buf, size_t count) { return -ENXIO; } Loading