Merge "NFC: Implement multiple NFC clock source and patch version"
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index f70d90f..cdd1e68 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -8,6 +8,8 @@
 - reg: NCI i2c slave address.
 - qcom,dis-gpio: specific gpio for hardware reset.
 - qcom,irq-gpio: specific gpio for read interrupt.
+- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", ...)
+- qcom,clk-en-gpio: msm gpio clock,used ony if clock source is msm gpio
 - interrupt-parent: Should be phandle for the interrupt controller
                     that services interrupts for this device.
 - interrupts: should contain the NFC interrupt. NFC has one read interrupt.
@@ -21,6 +23,8 @@
 		reg = <0x0e>;
 		qcom,irq-gpio = <&msmgpio 21 0x00>;
 		qcom,dis-gpio = <&msmgpio 20 0x00>;
+		qcom,clk-src = "BBCLK2";
+		qcom,clk-en-gpio = <&msmgpio 0 0x00>;
 		interrupt-parent = <&msmgpio>;
 		interrupts = <21 0>;
 		qcom,clk-gpio = <&pm8226_gpios 3 0>;
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index 318d4fc..5d98271 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -40,6 +40,8 @@
 			reg = <0x0e>;
 			qcom,irq-gpio = <&msmgpio 21 0x00>;
 			qcom,dis-gpio = <&msmgpio 20 0x00>;
+			qcom,clk-src = "BBCLK2";
+			qcom,clk-en-gpio = <&msmgpio 0 0x00>;
 			interrupt-parent = <&msmgpio>;
 			interrupts = <21 0>;
 			qcom,clk-gpio = <&pm8226_gpios 3 0>;
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 87c7c30..67b057c 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -26,12 +26,15 @@
 #include <linux/of_device.h>
 #include <linux/regulator/consumer.h>
 #include "nfc-nci.h"
+#include <mach/gpiomux.h>
 
 struct qca199x_platform_data {
 	unsigned int irq_gpio;
 	unsigned int dis_gpio;
 	unsigned int ven_gpio;
 	unsigned int reg;
+	const char *clk_src;
+	unsigned int clk_src_gpio;
 };
 
 static struct of_device_id msm_match_table[] = {
@@ -397,7 +400,9 @@
 		gpio_set_value(qca199x_dev->dis_gpio, 1);
 		usleep(1000);
 	} else if (arg == 2) {
+		mutex_lock(&qca199x_dev->read_mutex);
 		r = nfcc_initialise(qca199x_dev->client, 0xE);
+		mutex_unlock(&qca199x_dev->read_mutex);
 		if (r) {
 			dev_err(&qca199x_dev->client->dev,
 					"nfc-nci probe: request nfcc initialise failed\n");
@@ -419,7 +424,6 @@
 	return r;
 }
 
-
 /*
  * Inside nfc_ioctl_nfcc_mode
  *
@@ -477,6 +481,64 @@
 }
 
 /*
+ * Inside nfc_ioctl_nfcc_version
+ *
+ * @brief   nfc_ioctl_nfcc_version
+ *
+ *
+ */
+int nfc_ioctl_nfcc_version(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	int r = 0;
+	unsigned short	slave_addr	=	0xE;
+	unsigned short	curr_addr;
+
+	unsigned char raw_chip_version_addr		= 0x00;
+	unsigned char raw_chip_rev_id_addr		= 0x9C;
+	unsigned char raw_chip_version			= 0xFF;
+
+	struct qca199x_dev *qca199x_dev = filp->private_data;
+	struct qca199x_platform_data *platform_data;
+
+	platform_data = qca199x_dev->client->dev.platform_data;
+
+	if (arg == 0) {
+		curr_addr = qca199x_dev->client->addr;
+		qca199x_dev->client->addr = slave_addr;
+		r = nfc_i2c_write(qca199x_dev->client,
+				&raw_chip_version_addr, 1);
+		if (r < 0)
+			goto invalid_wr;
+		usleep(10);
+		r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
+		/* Restore original NFCC slave I2C address */
+		qca199x_dev->client->addr = curr_addr;
+	}
+	if (arg == 1) {
+		curr_addr = qca199x_dev->client->addr;
+		qca199x_dev->client->addr = slave_addr;
+		r = nfc_i2c_write(qca199x_dev->client,
+				&raw_chip_rev_id_addr, 1);
+		if (r < 0)
+			goto invalid_wr;
+		usleep(10);
+		r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
+		/* Restore original NFCC slave I2C address */
+		qca199x_dev->client->addr = curr_addr;
+	}
+
+	return raw_chip_version;
+invalid_wr:
+	raw_chip_version = 0xFF;
+	dev_err(&qca199x_dev->client->dev,
+			"\nNFCC_INVALID_CHIP_VERSION = %d\n", raw_chip_version);
+	return raw_chip_version;
+}
+
+
+
+/*
  * Inside nfc_ioctl_kernel_logging
  *
  * @brief   nfc_ioctl_kernel_logging
@@ -522,6 +584,9 @@
 	case NFCC_MODE:
 		nfc_ioctl_nfcc_mode(pfile, cmd, arg);
 		break;
+	case NFCC_VERSION:
+		r = nfc_ioctl_nfcc_version(pfile, cmd, arg);
+		break;
 	case NFC_KERNEL_LOGGING_MODE:
 		nfc_ioctl_kernel_logging(arg, pfile);
 		break;
@@ -690,6 +755,14 @@
 	if ((!gpio_is_valid(pdata->irq_gpio)))
 		return -EINVAL;
 
+	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src);
+
+	if (!strcmp(pdata->clk_src, "GPCLK"))
+		pdata->clk_src_gpio = of_get_named_gpio(np,
+				"qcom,clk-en-gpio", 0);
+
+	if (r)
+		return -EINVAL;
 	return r;
 }
 
@@ -698,7 +771,7 @@
 {
 	int r = 0;
 	int irqn = 0;
-	struct clk *nfc_clk;
+	struct clk *nfc_clk = NULL;
 	struct device_node *node = client->dev.of_node;
 	struct qca199x_platform_data *platform_data;
 	struct qca199x_dev *qca199x_dev;
@@ -769,7 +842,7 @@
 			dev_err(&client->dev,
 			"NFC: unable to request gpio [%d]\n",
 				platform_data->dis_gpio);
-			goto err_dis_gpio;
+			goto err_free_dev;
 		}
 		r = gpio_direction_output(platform_data->dis_gpio, 1);
 		if (r) {
@@ -785,15 +858,28 @@
 	gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
 	msleep(20);
 	gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
-
-	nfc_clk  = clk_get(&client->dev, "ref_clk");
-
-	if (nfc_clk == NULL)
-		goto err_dis_gpio;
-
+	if (!strcmp(platform_data->clk_src, "BBCLK2")) {
+		nfc_clk  = clk_get(&client->dev, "ref_clk");
+		if (nfc_clk == NULL)
+			goto err_dis_gpio;
+	} else if (!strcmp(platform_data->clk_src, "RFCLK3")) {
+		nfc_clk  = clk_get(&client->dev, "ref_clk_rf");
+		if (nfc_clk == NULL)
+			goto err_dis_gpio;
+	} else if (!strcmp(platform_data->clk_src, "GPCLK")) {
+		if (gpio_is_valid(platform_data->clk_src_gpio)) {
+			nfc_clk  = clk_get(&client->dev, "core_clk");
+			if (nfc_clk == NULL)
+				goto err_dis_gpio;
+		} else {
+			goto err_dis_gpio;
+		}
+	} else {
+		nfc_clk = NULL;
+	}
 	r = clk_prepare_enable(nfc_clk);
 	if (r)
-		goto err_dis_gpio;
+		goto err_clk;
 
 	platform_data->ven_gpio = of_get_named_gpio(node,
 						"qcom,clk-gpio", 0);
@@ -813,11 +899,9 @@
 						platform_data->ven_gpio);
 			goto err_ven_gpio;
 		}
-
 	} else {
-
 		dev_err(&client->dev, "ven gpio not provided\n");
-		goto err_dis_gpio;
+		goto err_clk;
 	}
 	qca199x_dev->dis_gpio = platform_data->dis_gpio;
 	qca199x_dev->irq_gpio = platform_data->irq_gpio;
@@ -871,7 +955,18 @@
 	mutex_destroy(&qca199x_dev->read_mutex);
 err_ven_gpio:
 	gpio_free(platform_data->ven_gpio);
+err_clk:
+	clk_disable_unprepare(nfc_clk);
 err_dis_gpio:
+	r = gpio_direction_input(platform_data->dis_gpio);
+	if (r)
+		dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
+	if (!strcmp(platform_data->clk_src, "GPCLK")) {
+		r = gpio_direction_input(platform_data->clk_src_gpio);
+		if (r)
+			dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
+		gpio_free(platform_data->clk_src_gpio);
+	}
 	gpio_free(platform_data->dis_gpio);
 err_irq:
 	gpio_free(platform_data->irq_gpio);
diff --git a/drivers/nfc/nfc-nci.h b/drivers/nfc/nfc-nci.h
index c3cabc2..81f2521 100644
--- a/drivers/nfc/nfc-nci.h
+++ b/drivers/nfc/nfc-nci.h
@@ -49,26 +49,27 @@
 	enum ehandler_mode	handle_flavour;
 } tdevicemode;
 
-#define NFC_DRIVER_NAME			"nfc-nci"
+#define NFC_DRIVER_NAME		"nfc-nci"
 #define NFC_I2C_DRIVER_NAME		"NCI NFC I2C Interface",
 
-#define NCI_I2C_SLAVE			(0x2C)
-#define NFC_I2C_BUS			3	/* 6, 10, 4, 5 */
-#define NFC_SET_PWR			_IOW(0xE9, 0x01, unsigned int)
-#define NFCC_MODE			_IOW(0xE9, 0x02, unsigned int)
+#define NCI_I2C_SLAVE	(0x2C)
+#define NFC_I2C_BUS	3	/* 6, 10, 4, 5 */
+#define NFC_SET_PWR	_IOW(0xE9, 0x01, unsigned int)
+#define NFCC_MODE	_IOW(0xE9, 0x02, unsigned int)
 #define NFC_KERNEL_LOGGING_MODE		_IOW(0xE9, 0x03, unsigned int)
-#define SET_RX_BLOCK			_IOW(0xE9, 0x04, unsigned int)
+#define SET_RX_BLOCK	_IOW(0xE9, 0x04, unsigned int)
 #define SET_EMULATOR_TEST_POINT		_IOW(0xE9, 0x05, unsigned int)
+#define NFCC_VERSION				_IOW(0xE9, 0x08, unsigned int)
 
-#define NFC_MAX_I2C_TRANSFER		(0x0400)
-#define NFC_MSG_MAX_SIZE		(0x21)
+#define NFC_MAX_I2C_TRANSFER	(0x0400)
+#define NFC_MSG_MAX_SIZE	(0x21)
 
 #define NFC_RX_BUFFER_CNT_START		(0x0)
 
-#define NFC_RX_BUFFER_BLOCK_SIZE	(0x120)		/* Bytes per Block */
+#define NFC_RX_BUFFER_BLOCK_SIZE	(0x120)	/* Bytes per Block */
 #define NFC_RX_BUFFER_PAGE_SIZE		(0x1000)	/* Page size Bytes */
 #define NFC_RX_BUFFER_PAGES		(0x8)
-#define NFC_RX_ORDER_FREE_PAGES		(0x3)		/* Free 8 Pages */
+#define NFC_RX_ORDER_FREE_PAGES	(0x3)	/* Free 8 Pages */
 
 /* The total no. of Blocks */
 #define NFC_RX_BUFFER_CNT_LIMIT		(unsigned short)(	\
@@ -86,10 +87,10 @@
 
 /** Power Management Related **/
 
-#define NFCC_WAKE			(0x01)
-#define NFCC_SLEEP			(0x00)
+#define NFCC_WAKE				(0x01)
+#define NFCC_SLEEP				(0x00)
 
-#define XTAL_CLOCK			(0X00)
+#define XTAL_CLOCK				(0X00)
 #define REFERENCE_CLOCK			(0X01)
 
 /* LDO Trim Settings */
@@ -122,8 +123,8 @@
 #define LOCALBIASXTAL	(0x20)
 #define BIAS2X_FORCE	(0x10)
 #define BIAS2X		(0x08)
-#define LBIAS2X		(0x04)
-#define SMALLRF		(0x02)
+#define LBIAS2X	(0x04)
+#define SMALLRF	(0x02)
 #define SMALLRBIAS	(0x01)
 
 /* Select as appropriate */