From eb81b68b141b0a99adb6ebb9676777270f3fda28 Mon Sep 17 00:00:00 2001 From: Karthik Poosa Date: Tue, 7 Jan 2020 23:14:06 +0530 Subject: [PATCH] NFC: Add NFC hardware check and get info ioctl Add nfc hardware check in probe and NFCC_GET_INFO ioctl. Change-Id: If1269ac0b3a786039001d4c759e9c423ddc149db Signed-off-by: Karthik Poosa --- drivers/nfc/qti/nfc_common.c | 285 ++++++++++++++++++++++++++++++- drivers/nfc/qti/nfc_common.h | 25 ++- drivers/nfc/qti/nfc_i2c_drv.c | 50 +++--- drivers/nfc/qti/nfc_i3c_drv.c | 31 ++-- drivers/nfc/qti/nfc_i3c_drv.h | 12 +- include/linux/nfcinfo.h | 11 ++ include/uapi/linux/nfc/nfcinfo.h | 26 +++ 7 files changed, 394 insertions(+), 46 deletions(-) create mode 100644 include/linux/nfcinfo.h create mode 100644 include/uapi/linux/nfc/nfcinfo.h diff --git a/drivers/nfc/qti/nfc_common.c b/drivers/nfc/qti/nfc_common.c index b6b24cf7d99f..5cc17d2c37a3 100644 --- a/drivers/nfc/qti/nfc_common.c +++ b/drivers/nfc/qti/nfc_common.c @@ -1,6 +1,6 @@ // 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 @@ -8,6 +8,25 @@ #include #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) { @@ -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, - COLD_RESET_CMD_LEN, MAX_RETRY_COUNT); - + 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); @@ -248,7 +262,7 @@ void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header) (nfc_dev->interface == PLATFORM_IF_I2C)) { ret = i2c_read(&nfc_dev->i2c_dev, cold_reset_rsp, - NCI_HDR_LEN); + NCI_HDR_LEN); if (ret <= 0) { pr_err("%s: failure to read cold reset rsp header\n", __func__); @@ -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", @@ -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], @@ -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); @@ -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. @@ -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; @@ -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); diff --git a/drivers/nfc/qti/nfc_common.h b/drivers/nfc/qti/nfc_common.h index 7f89783bba07..243ecafb70f3 100644 --- a/drivers/nfc/qti/nfc_common.h +++ b/drivers/nfc/qti/nfc_common.h @@ -1,6 +1,6 @@ /* 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_ @@ -22,6 +22,7 @@ #include #include #include +#include #include "nfc_i2c_drv.h" #include "nfc_i3c_drv.h" @@ -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 @@ -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; @@ -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); @@ -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_ diff --git a/drivers/nfc/qti/nfc_i2c_drv.c b/drivers/nfc/qti/nfc_i2c_drv.c index e71df36947f9..1d235f01fa6c 100644 --- a/drivers/nfc/qti/nfc_i2c_drv.c +++ b/drivers/nfc/qti/nfc_i2c_drv.c @@ -1,6 +1,6 @@ // 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" @@ -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); } - ret = wait_event_interruptible(nfc_dev->read_wq, + 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; - } + if (ret) { + pr_err("error wakeup of read wq\n"); + goto err; + } + } i2c_disable_irq(i2c_dev); - if (!gpio_get_value(nfc_dev->gpio.ven)) { - pr_info("%s: releasing read\n", __func__); - ret = -EIO; - goto err; - } - if (gpio_get_value(nfc_dev->gpio.irq)) break; + if (!gpio_get_value(nfc_dev->gpio.ven)) { + pr_info("%s: ven low in read !\n", __func__); + ret = -ENODEV; + goto err; + } + pr_warn("%s: spurious interrupt detected\n", __func__); } } @@ -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: @@ -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); @@ -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; } @@ -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); } diff --git a/drivers/nfc/qti/nfc_i3c_drv.c b/drivers/nfc/qti/nfc_i3c_drv.c index de05a13f3b13..063ab48fdd85 100644 --- a/drivers/nfc/qti/nfc_i3c_drv.c +++ b/drivers/nfc/qti/nfc_i3c_drv.c @@ -1,6 +1,6 @@ // 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" @@ -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; @@ -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); @@ -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. * @@ -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)) { @@ -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; } @@ -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); @@ -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); @@ -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: @@ -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; } @@ -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); } diff --git a/drivers/nfc/qti/nfc_i3c_drv.h b/drivers/nfc/qti/nfc_i3c_drv.h index 613d457ae9b0..f0a7485b5bae 100644 --- a/drivers/nfc/qti/nfc_i3c_drv.h +++ b/drivers/nfc/qti/nfc_i3c_drv.h @@ -1,6 +1,6 @@ /* 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_ @@ -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 @@ -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; } diff --git a/include/linux/nfcinfo.h b/include/linux/nfcinfo.h new file mode 100644 index 000000000000..d592fbff8b5b --- /dev/null +++ b/include/linux/nfcinfo.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _NFCINFO_H +#define _NFCINFO_H + +#include + +#endif diff --git a/include/uapi/linux/nfc/nfcinfo.h b/include/uapi/linux/nfc/nfcinfo.h new file mode 100644 index 000000000000..aaf78b3928e7 --- /dev/null +++ b/include/uapi/linux/nfc/nfcinfo.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _UAPI_NFCINFO_H_ +#define _UAPI_NFCINFO_H_ + +#include + +#define NFCC_MAGIC 0xE9 +#define NFCC_GET_INFO _IOW(NFCC_MAGIC, 0x09, unsigned int) + +struct nqx_devinfo { + unsigned char chip_type; + unsigned char rom_version; + unsigned char fw_major; + unsigned char fw_minor; +}; + +union nqx_uinfo { + unsigned int i; + struct nqx_devinfo info; +}; + +#endif