Browse Source

NFC: Driver: Add SW WAR to enable and disable NFC clock

Added SW WAR to enable NFC clock at NFC ON and disable
NFC clock at NFC OFF.

Change-Id: Id617efb53ba06caa735927b4d271990be7e4766c
Khageswararao Rao B 3 years ago
parent
commit
414ee1d668
4 changed files with 79 additions and 6 deletions
  1. 21 6
      nfc/common.c
  2. 11 0
      nfc/common.h
  3. 41 0
      nfc/common_qcom.c
  4. 6 0
      nfc/i2c_drv.c

+ 21 - 6
nfc/common.c

@@ -66,6 +66,13 @@ int nfc_parse_dt(struct device *dev, struct platform_configs *nfc_configs,
 		pr_warn("%s: nfc dwl_req gpio invalid %d\n", __func__,
 			nfc_gpio->dwl_req);
 
+	if (of_property_read_string(np, DTS_CLKSRC_GPIO_STR, &nfc_configs->clk_src_name)) {
+		nfc_configs->clk_pin_voting = false;
+	}
+	else {
+		nfc_configs->clk_pin_voting = true;
+	}
+
 	pr_info("%s: irq %d, ven %d, dwl %d\n", __func__, nfc_gpio->irq, nfc_gpio->ven,
 		nfc_gpio->dwl_req);
 
@@ -329,14 +336,22 @@ static int nfc_ioctl_power_states(struct nfc_dev *nfc_dev, unsigned long arg)
 		nfc_dev->nfc_state = NFC_STATE_NCI;
 
 	} else if (arg == NFC_ENABLE) {
-		/*
-		 * Setting flag true when NFC is enabled
-		 */
+		if(nfc_dev->configs.clk_pin_voting) {
+			/* Enabling nfc clock */
+			ret = nfc_clock_select(nfc_dev);
+			if (ret)
+				pr_err("%s unable to select clock\n", __func__);
+		}
+		/* Setting flag true when NFC is enabled */
 		nfc_dev->cold_reset.is_nfc_enabled = true;
 	} else if (arg == NFC_DISABLE) {
-		/*
-		 * Setting flag true when NFC is disabled
-		 */
+		if(nfc_dev->configs.clk_pin_voting) {
+			/* Disabling nfc clock */
+			ret = nfc_clock_deselect(nfc_dev);
+			if (ret)
+				pr_err("%s unable to disable clock\n", __func__);
+		}
+		/* 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);

+ 11 - 0
nfc/common.h

@@ -28,6 +28,7 @@
 #include <linux/of_gpio.h>
 #include <linux/delay.h>
 #include <linux/ipc_logging.h>
+#include <linux/clk.h>
 #include <nfcinfo.h>
 #include "i2c_drv.h"
 #include "ese_cold_reset.h"
@@ -111,6 +112,7 @@
 #define DTS_IRQ_GPIO_STR	"qcom,sn-irq"
 #define DTS_VEN_GPIO_STR	"qcom,sn-ven"
 #define DTS_FWDN_GPIO_STR	"qcom,sn-firm"
+#define DTS_CLKSRC_GPIO_STR	"qcom,clk-src"
 #define NFC_LDO_SUPPLY_DT_NAME		"qcom,sn-vdd-1p8"
 #define NFC_LDO_SUPPLY_NAME		"qcom,sn-vdd-1p8-supply"
 #define NFC_LDO_VOL_DT_NAME		"qcom,sn-vdd-1p8-voltage"
@@ -221,6 +223,9 @@ struct platform_ldo {
 struct platform_configs {
 	struct platform_gpio gpio;
 	struct platform_ldo ldo;
+        const char *clk_src_name;
+	/* NFC_CLK pin voting state */
+	bool clk_pin_voting;
 };
 
 
@@ -261,6 +266,10 @@ struct nfc_dev {
 
 	union nqx_uinfo nqx_info;
 
+	/* CLK control */
+	bool clk_run;
+	struct clk *s_clk;
+
 	void *ipcl;
 
 	/* function pointers for the common i2c functionality */
@@ -296,4 +305,6 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg);
 int nfc_ldo_unvote(struct nfc_dev *nfc_dev);
 int is_nfc_data_available_for_read(struct nfc_dev *nfc_dev);
 int validate_nfc_state_nci(struct nfc_dev *nfc_dev);
+int nfc_clock_select(struct nfc_dev *nfc_dev);
+int nfc_clock_deselect(struct nfc_dev *nfc_dev);
 #endif /* _COMMON_H_ */

+ 41 - 0
nfc/common_qcom.c

@@ -161,3 +161,44 @@ int nfc_ldo_unvote(struct nfc_dev *nfc_dev)
 		pr_err("%s: set load failed\n", __func__);
 	return ret;
 }
+
+/*
+ * Routine to enable clock.
+ * this routine can be extended to select from multiple
+ * sources based on clk name.
+ */
+int nfc_clock_select(struct nfc_dev *nfc_dev)
+{
+	int r = 0;
+
+	nfc_dev->s_clk = clk_get(&nfc_dev->i2c_dev.client->dev, "nfc_ref_clk");
+
+	if (IS_ERR(nfc_dev->s_clk))
+		return PTR_ERR(nfc_dev->s_clk);
+
+	if (!nfc_dev->clk_run)
+		r = clk_prepare_enable(nfc_dev->s_clk);
+
+	if (r)
+		return r;
+
+	nfc_dev->clk_run = true;
+	return r;
+}
+
+/*
+ * Routine to disable clocks
+ */
+int nfc_clock_deselect(struct nfc_dev *nfc_dev)
+{
+	int r = -EINVAL;
+
+	if (nfc_dev->s_clk != NULL) {
+		if (nfc_dev->clk_run) {
+			clk_disable_unprepare(nfc_dev->s_clk);
+			nfc_dev->clk_run = false;
+		}
+		return 0;
+	}
+	return r;
+}

+ 6 - 0
nfc/i2c_drv.c

@@ -431,6 +431,12 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		pr_err("nfc hw check failed ret %d\n", ret);
 		goto err_nfcc_hw_check;
 	}
+
+	if(nfc_dev->configs.clk_pin_voting)
+		nfc_dev->clk_run = false;
+	else
+		nfc_dev->clk_run = true;
+
 	gpio_set_ven(nfc_dev, 1);
 	gpio_set_ven(nfc_dev, 0);
 	gpio_set_ven(nfc_dev, 1);