diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index d4a4ec0fcf89..36d414f63dbf 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -71,9 +71,18 @@ config NFC_QTI_I2C If unsure, say N. +config NFC_QTI_I3C_GPIO + tristate "QTI Driver to configure NFC GPIOs for SNxxx I3C modules" + help + This enables the QTI driver for SNxxx I3C based devices. + NFC Enable GPIO(NFC_EN) should toggle before I3C enumeration so that NFC + controller gets recognized. + + If unsure, say N. + config NFC_QTI_I3C tristate "QTI NCI based NFC I3C Slave Driver for SNxxx" - depends on I3C + depends on I3C && NFC_QTI_I3C_GPIO help This enables the NFC driver for SNxxx based devices. This is for I3C connected version. NCI protocol logic diff --git a/drivers/nfc/qti/Makefile b/drivers/nfc/qti/Makefile index 0463f8027f04..f8f8ebd419f8 100644 --- a/drivers/nfc/qti/Makefile +++ b/drivers/nfc/qti/Makefile @@ -8,3 +8,5 @@ nfc_i2c-objs:= nfc_common.o nfc_i2c_drv.o obj-$(CONFIG_NFC_QTI_I3C) += nfc_i3c.o nfc_i3c-objs:= nfc_common.o nfc_i3c_drv.o + +obj-$(CONFIG_NFC_QTI_I3C_GPIO) += nfc_i3c_gpio_cfg.o diff --git a/drivers/nfc/qti/nfc_i3c_gpio_cfg.c b/drivers/nfc/qti/nfc_i3c_gpio_cfg.c new file mode 100644 index 000000000000..e6abfd0e651b --- /dev/null +++ b/drivers/nfc/qti/nfc_i3c_gpio_cfg.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +/* NFC I3C DT node name */ +#define NFC_I3C_DT_NODE_STR "sn" + +/* NFC GPIO names in the I3C slave node */ +#define DTS_VEN_GPIO_STR "qcom,sn-ven" +#define DTS_FWDN_GPIO_STR "qcom,sn-firm" + +static int __init nfc_i3c_gpio_cfg_init(void) +{ + int ret = 0; + int ven_gpio = 0, firm_gpio = 0; + struct device_node *np = NULL; + + pr_debug("%s\n", __func__); + + np = of_find_node_by_name(NULL, NFC_I3C_DT_NODE_STR); + if (!np) { + pr_err("finding NFC I3C slave node failed\n"); + return -ENODEV; + } + + ven_gpio = of_get_named_gpio(np, DTS_VEN_GPIO_STR, 0); + pr_debug("NFC VEN %d\n", ven_gpio); + + if ((!gpio_is_valid(ven_gpio))) { + pr_err("invalid ven gpio %d from dt\n", ven_gpio); + return -EINVAL; + } + + firm_gpio = of_get_named_gpio(np, DTS_FWDN_GPIO_STR, 0); + pr_debug("NFC FIRM GPIO %d\n", firm_gpio); + + if ((!gpio_is_valid(firm_gpio))) { + pr_err("invalid firm gpio %d from dt\n", firm_gpio); + return -EINVAL; + } + + ret = gpio_request(firm_gpio, "nfc_fw_gpio"); + if (ret) { + pr_err("NFC firm gpio request failed ret %d\n", ret); + return -EIO; + } + + ret = gpio_direction_output(firm_gpio, 0); + if (ret) { + pr_err("NFC firm gpio direction set failed ret %d\n", ret); + gpio_free(firm_gpio); + return -EIO; + } + + usleep_range(10000, 10100); + pr_debug("NFC firm gpio %d\n", gpio_get_value(firm_gpio)); + + ret = gpio_request(ven_gpio, "nfc_reset_gpio"); + if (ret) { + pr_err("nfc ven gpio req failed ret %d\n", ret); + gpio_set_value(firm_gpio, 0); + gpio_free(firm_gpio); + return -EIO; + } + + ret = gpio_direction_output(ven_gpio, 0); + if (ret) { + pr_err("ven direction set failed ret %d\n", ret); + gpio_set_value(firm_gpio, 0); + gpio_free(firm_gpio); + gpio_free(ven_gpio); + return -EIO; + } + + pr_debug("VEN GPIO level %d\n", gpio_get_value(ven_gpio)); + usleep_range(10000, 10100); + gpio_set_value(ven_gpio, 1); + pr_debug("VEN GPIO level %d\n", gpio_get_value(ven_gpio)); + + gpio_free(ven_gpio); + gpio_free(firm_gpio); + return ret; +} + +module_init(nfc_i3c_gpio_cfg_init); + +static void __exit nfc_i3c_gpio_cfg_exit(void) +{ + pr_debug("Unloading I3C NFC GPIO Config driver\n"); +} + +module_exit(nfc_i3c_gpio_cfg_exit); + +MODULE_DESCRIPTION("QTI NFC I3C GPIO Config driver"); +MODULE_LICENSE("GPL v2");