NFC: Implement multiple NFC clock source and patch version
NFC driver to support multiple clock sources and to support patch
version ioctl to be used by the user mode driver.
Change-Id: Idd10fc1284ae1335a3a59179ad6e3e265c952d08
Acked-by: Umesh Jagga <ujagga@qti.qualcomm.com>
Signed-off-by: Bansidhar Gopalachari <bansid@codeaurora.org>
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);