input: touchscreen: Add force fw_update support via sysfs entry

Add sysfs entry for force fw_update support in Goodix
driver.
Change the usage of kstrtoul to sscanf in driver to avoid
portability issues.

CRs-fixed: 579806
Change-Id: I147a3e465170dda7af415ade29c04257d9b11a6b
Signed-off-by: Shantanu Jain <shjain@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index f2ca95b..d0c2b7d 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -29,7 +29,7 @@
 				It is a four tuple consisting of min x,
 				min y, max x and max y values.
  - goodix,i2c-pull-up	: To specify pull up is required.
- - goodix,no-force-update	: To specify force update is allowed.
+ - goodix,force-update	: To specify force update is allowed.
  - goodix,enable-power-off	: Power off touchscreen during suspend.
  - goodix,button-map	: Button map of key codes. The number of key codes
 				depend on panel.
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 912d87c..91d787f 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -1542,15 +1542,14 @@
 				const char *buf, size_t size)
 {
 	struct goodix_ts_data *ts = dev_get_drvdata(dev);
-	unsigned long val;
+	unsigned int val;
 	int ret;
 
 	if (size > 2)
 		return -EINVAL;
 
-	ret = kstrtoul(buf, 10, &val);
-	if (ret != 0)
-		return ret;
+	if (sscanf(buf, "%u", &val) != 1);
+		return -EINVAL;
 
 	if (ts->gtp_is_suspend) {
 		dev_err(&ts->client->dev,
@@ -1576,16 +1575,60 @@
 	return size;
 }
 
+static ssize_t gtp_force_fw_upgrade_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct goodix_ts_data *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int ret;
+
+	if (size > 2)
+		return -EINVAL;
+
+	if (sscanf(buf, "%u", &val) != 1);
+		return -EINVAL;
+
+	if (ts->gtp_is_suspend) {
+		dev_err(&ts->client->dev,
+			"Can't start fw upgrade. Device is in suspend state.");
+		return -EBUSY;
+	}
+
+	mutex_lock(&ts->input_dev->mutex);
+	if (!ts->fw_loading && val) {
+		disable_irq(ts->client->irq);
+		ts->fw_loading = true;
+		ts->force_update = true;
+		if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) {
+			ret = gup_update_proc(NULL);
+			if (ret == FAIL)
+				dev_err(&ts->client->dev,
+				"Fail to force update GTP firmware.\n");
+		}
+		ts->force_update = false;
+		ts->fw_loading = false;
+		enable_irq(ts->client->irq);
+	}
+	mutex_unlock(&ts->input_dev->mutex);
+
+	return size;
+}
+
 static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP),
 			gtp_fw_name_show,
 			gtp_fw_name_store);
 static DEVICE_ATTR(fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP),
 			gtp_fw_upgrade_show,
 			gtp_fw_upgrade_store);
+static DEVICE_ATTR(force_fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP),
+			gtp_fw_upgrade_show,
+			gtp_force_fw_upgrade_store);
 
 static struct attribute *gtp_attrs[] = {
 	&dev_attr_fw_name.attr,
 	&dev_attr_fw_upgrade.attr,
+	&dev_attr_force_fw_upgrade.attr,
 	NULL
 };
 
@@ -1802,8 +1845,8 @@
 	pdata->i2c_pull_up = of_property_read_bool(np,
 						"goodix,i2c-pull-up");
 
-	pdata->no_force_update = of_property_read_bool(np,
-						"goodix,no-force-update");
+	pdata->force_update = of_property_read_bool(np,
+						"goodix,force-update");
 
 	pdata->enable_power_off = of_property_read_bool(np,
 						"goodix,enable-power-off");
@@ -1971,6 +2014,9 @@
 		goto exit_power_off;
 	}
 
+	if (pdata->force_update)
+		ts->force_update = true;
+
 	if (pdata->fw_name)
 		strlcpy(ts->fw_name, pdata->fw_name,
 						strlen(pdata->fw_name) + 1);
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 7a1af23..0ba6895 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -56,7 +56,7 @@
 	u32 panel_miny;
 	u32 panel_maxx;
 	u32 panel_maxy;
-	bool no_force_update;
+	bool force_update;
 	bool i2c_pull_up;
 	bool enable_power_off;
 	size_t config_data_len[GOODIX_MAX_CFG_GROUP];
@@ -94,6 +94,7 @@
 	bool power_on;
 	struct mutex lock;
 	bool fw_loading;
+	bool force_update;
 	struct regulator *avdd;
 	struct regulator *vdd;
 	struct regulator *vcc_i2c;
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
index 71e8a55..af80eef 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -1,7 +1,7 @@
 /* drivers/input/touchscreen/gt9xx_update.c
  *
  * 2010 - 2012 Goodix Technology.
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1432,10 +1432,15 @@
 		goto file_fail;
 	}
 
-	ret = gup_enter_update_judge(ts->client, &fw_head);
-	if (ret == FAIL) {
-		pr_err("Check *.bin file fail.");
-		goto file_fail;
+	if (ts->force_update) {
+		dev_dbg(&ts->client->dev, "Enter force update.");
+	} else {
+		ret = gup_enter_update_judge(ts->client, &fw_head);
+		if (ret == FAIL) {
+			dev_err(&ts->client->dev,
+					"Check *.bin file fail.");
+			goto file_fail;
+		}
 	}
 
 	ts->enter_update = 1;