input: synaptics_i2c_rmi4: Add device tree support

To work with device tree framework, support must be added
in driver.  Read in properties such as gpios, x/y size and
soft button mapping.  Also, enable multitouch with protocol
B.

Change-Id: I17f41105c57f22db1623d03627ca89f47ef57a8b
Signed-off-by: Amy Maloche <amaloche@codeaurora.org>
Signed-off-by: Shantanu Jain <shjain@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
new file mode 100644
index 0000000..b31ec30
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_i2c_rmi4.txt
@@ -0,0 +1,52 @@
+Synaptics touch controller
+
+Required properties:
+
+ - compatible	: should be "synaptics,rmi4"
+ - reg			: i2c slave address of the device
+ - interrupt-parent	: parent of interrupt
+ - interrupts		: touch sample interrupt to indicate presense or release
+				of fingers on the panel.
+ - synaptics,irq-gpio	: irq gpio
+ - synaptics,reset-gpio	: reset gpio
+
+Optional property:
+ - vdd-supply		: Analog power supply needed to power device
+ - synaptics,reg-en	: specify to indicate regulator is needed
+ - vcc_i2c-supply		: Power source required to pull up i2c bus
+ - synaptics,i2c-pull-up	: specify to indicate pull up is needed
+ - synaptics,button-map		: virtual key code mappings to be used
+ - synaptics,x-flip		: modify orientation of the x axis
+ - synaptics,y-flip		: modify orientation of the y axis
+ - synaptics,panel-x		: panel x dimension
+ - synaptics,panel-y		: panel y dimension
+
+Example:
+	i2c@f9927000 { /* BLSP1 QUP5 */
+		cell-index = <5>;
+		compatible = "qcom,i2c-qup";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg-names = "qup_phys_addr";
+		reg = <0xf9927000 0x1000>;
+		interrupt-names = "qup_err_intr";
+		interrupts = <0 99 0>;
+		gpios = <&msmgpio 19 0>, /* SCL */
+			<&msmgpio 18 0>; /* SDA */
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <19200000>;
+
+		synaptics@20 {
+			compatible = "synaptics,rmi4"
+			reg = <0x20>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <17 0x2>;
+			vdd-supply = <&pm8226_l19>;
+			vcc_i2c-supply = <&pm8226_lvs1>;
+			synaptics,reset-gpio = <&msmgpio 16 0x00>;
+			synaptics,irq-gpio = <&msmgpio 17 0x00>;
+			synaptics,button-map = [8B 66 9E];
+			synaptics,i2c-pull-up;
+			synaptics,reg-en;
+		};
+	};
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 2c79276..775d62a 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -28,17 +28,13 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/input/synaptics_dsx.h>
+#include <linux/of_gpio.h>
 #include "synaptics_i2c_rmi4.h"
-#ifdef KERNEL_ABOVE_2_6_38
 #include <linux/input/mt.h>
-#endif
 
 #define DRIVER_NAME "synaptics_rmi4_i2c"
 #define INPUT_PHYS_NAME "synaptics_rmi4_i2c/input0"
-
-#ifdef KERNEL_ABOVE_2_6_38
 #define TYPE_B_PROTOCOL
-#endif
 
 #define NO_0D_WHILE_2D
 /*
@@ -655,10 +651,6 @@
 					finger_status,
 					x, y, wx, wy);
 
-			input_report_key(rmi4_data->input_dev,
-					BTN_TOUCH, 1);
-			input_report_key(rmi4_data->input_dev,
-					BTN_TOOL_FINGER, 1);
 			input_report_abs(rmi4_data->input_dev,
 					ABS_MT_POSITION_X, x);
 			input_report_abs(rmi4_data->input_dev,
@@ -677,6 +669,10 @@
 		}
 	}
 
+	input_report_key(rmi4_data->input_dev, BTN_TOUCH, touch_count > 0);
+	input_report_key(rmi4_data->input_dev,
+			BTN_TOOL_FINGER, touch_count > 0);
+
 #ifndef TYPE_B_PROTOCOL
 	if (!touch_count)
 		input_mt_sync(rmi4_data->input_dev);
@@ -909,6 +905,80 @@
 	return IRQ_HANDLED;
 }
 
+static int synaptics_rmi4_parse_dt(struct device *dev,
+				struct synaptics_rmi4_platform_data *rmi4_pdata)
+{
+	struct device_node *np = dev->of_node;
+	struct property *prop;
+	u32 temp_val, num_buttons;
+	u32 button_map[MAX_NUMBER_OF_BUTTONS];
+	int rc, i;
+
+	rmi4_pdata->i2c_pull_up = of_property_read_bool(np,
+			"synaptics,i2c-pull-up");
+	rmi4_pdata->regulator_en = of_property_read_bool(np,
+			"synaptics,reg-en");
+	rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
+	rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
+
+	rc = of_property_read_u32(np, "synaptics,panel-x", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read panel X dimension\n");
+		return rc;
+	} else {
+		rmi4_pdata->panel_x = temp_val;
+	}
+
+	rc = of_property_read_u32(np, "synaptics,panel-y", &temp_val);
+	if (rc && (rc != -EINVAL)) {
+		dev_err(dev, "Unable to read panel Y dimension\n");
+		return rc;
+	} else {
+		rmi4_pdata->panel_y = temp_val;
+	}
+
+	/* reset, irq gpio info */
+	rmi4_pdata->reset_gpio = of_get_named_gpio_flags(np,
+			"synaptics,reset-gpio", 0, &rmi4_pdata->reset_flags);
+	rmi4_pdata->irq_gpio = of_get_named_gpio_flags(np,
+			"synaptics,irq-gpio", 0, &rmi4_pdata->irq_flags);
+
+	prop = of_find_property(np, "synaptics,button-map", NULL);
+	if (prop) {
+		num_buttons = prop->length / sizeof(temp_val);
+
+		rmi4_pdata->capacitance_button_map = devm_kzalloc(dev,
+			sizeof(*rmi4_pdata->capacitance_button_map),
+			GFP_KERNEL);
+		if (!rmi4_pdata->capacitance_button_map)
+			return -ENOMEM;
+
+		rmi4_pdata->capacitance_button_map->map = devm_kzalloc(dev,
+			sizeof(*rmi4_pdata->capacitance_button_map->map) *
+			MAX_NUMBER_OF_BUTTONS, GFP_KERNEL);
+		if (!rmi4_pdata->capacitance_button_map->map)
+			return -ENOMEM;
+
+		if (num_buttons <= MAX_NUMBER_OF_BUTTONS) {
+			rc = of_property_read_u32_array(np,
+				"synaptics,button-map", button_map,
+				num_buttons);
+			if (rc) {
+				dev_err(dev, "Unable to read key codes\n");
+				return rc;
+			}
+			for (i = 0; i < num_buttons; i++)
+				rmi4_pdata->capacitance_button_map->map[i] =
+					button_map[i];
+			rmi4_pdata->capacitance_button_map->nbuttons =
+				num_buttons;
+		} else {
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
  /**
  * synaptics_rmi4_irq_enable()
  *
@@ -924,8 +994,6 @@
 {
 	int retval = 0;
 	unsigned char intr_status;
-	const struct synaptics_rmi4_platform_data *platform_data =
-			rmi4_data->i2c_client->dev.platform_data;
 
 	if (enable) {
 		if (rmi4_data->irq_enabled)
@@ -940,7 +1008,8 @@
 			return retval;
 
 		retval = request_threaded_irq(rmi4_data->irq, NULL,
-				synaptics_rmi4_irq, platform_data->irq_flags,
+				synaptics_rmi4_irq,
+				rmi4_data->board->irq_flags,
 				DRIVER_NAME, rmi4_data);
 		if (retval < 0) {
 			dev_err(&rmi4_data->i2c_client->dev,
@@ -1663,6 +1732,7 @@
 			}
 		}
 	}
+	return 0;
 
 err_set_vtg_i2c:
 	if (rmi4_data->board->i2c_pull_up)
@@ -1786,7 +1856,7 @@
 	struct synaptics_rmi4_fn *fhandler;
 	struct synaptics_rmi4_data *rmi4_data;
 	struct synaptics_rmi4_device_info *rmi;
-	const struct synaptics_rmi4_platform_data *platform_data =
+	struct synaptics_rmi4_platform_data *platform_data =
 			client->dev.platform_data;
 
 	if (!i2c_check_functionality(client->adapter,
@@ -1797,6 +1867,22 @@
 		return -EIO;
 	}
 
+	if (client->dev.of_node) {
+		platform_data = devm_kzalloc(&client->dev,
+			sizeof(*platform_data),
+			GFP_KERNEL);
+		if (!platform_data) {
+			dev_err(&client->dev, "Failed to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		retval = synaptics_rmi4_parse_dt(&client->dev, platform_data);
+		if (retval)
+			return retval;
+	} else {
+		platform_data = client->dev.platform_data;
+	}
+
 	if (!platform_data) {
 		dev_err(&client->dev,
 				"%s: No platform data found\n",
@@ -1853,23 +1939,6 @@
 	set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
 #endif
 
-	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_X, 0,
-			rmi4_data->sensor_max_x, 0, 0);
-	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_POSITION_Y, 0,
-			rmi4_data->sensor_max_y, 0, 0);
-#ifdef REPORT_2D_W
-	input_set_abs_params(rmi4_data->input_dev,
-			ABS_MT_TOUCH_MAJOR, 0,
-			MAX_ABS_MT_TOUCH_MAJOR, 0, 0);
-#endif
-
-#ifdef TYPE_B_PROTOCOL
-	input_mt_init_slots(rmi4_data->input_dev,
-			rmi4_data->num_of_fingers);
-#endif
-
 	retval = synaptics_rmi4_regulator_configure(rmi4_data, true);
 	if (retval < 0) {
 		dev_err(&client->dev, "Failed to configure regulators\n");
@@ -1888,18 +1957,18 @@
 		if (retval) {
 			dev_err(&client->dev, "unable to request gpio [%d]\n",
 						platform_data->irq_gpio);
-			goto err_query_device;
+			goto err_irq_gpio_req;
 		}
 		retval = gpio_direction_input(platform_data->irq_gpio);
 		if (retval) {
 			dev_err(&client->dev,
 				"unable to set direction for gpio [%d]\n",
 				platform_data->irq_gpio);
-			goto err_irq_gpio_req;
+			goto err_irq_gpio_dir;
 		}
 	} else {
 		dev_err(&client->dev, "irq gpio not provided\n");
-		goto err_query_device;
+		goto err_irq_gpio_req;
 	}
 
 	if (gpio_is_valid(platform_data->reset_gpio)) {
@@ -1909,7 +1978,7 @@
 		if (retval) {
 			dev_err(&client->dev, "unable to request gpio [%d]\n",
 						platform_data->reset_gpio);
-			goto err_irq_gpio_req;
+			goto err_irq_gpio_dir;
 		}
 
 		retval = gpio_direction_output(platform_data->reset_gpio, 1);
@@ -1917,7 +1986,7 @@
 			dev_err(&client->dev,
 				"unable to set direction for gpio [%d]\n",
 				platform_data->reset_gpio);
-			goto err_reset_gpio_req;
+			goto err_reset_gpio_dir;
 		}
 
 		gpio_set_value(platform_data->reset_gpio, 0);
@@ -1935,9 +2004,26 @@
 		dev_err(&client->dev,
 				"%s: Failed to query device\n",
 				__func__);
-		goto err_reset_gpio_req;
+		goto err_reset_gpio_dir;
 	}
 
+	input_set_abs_params(rmi4_data->input_dev,
+			ABS_MT_POSITION_X, 0,
+			rmi4_data->sensor_max_x, 0, 0);
+	input_set_abs_params(rmi4_data->input_dev,
+			ABS_MT_POSITION_Y, 0,
+			rmi4_data->sensor_max_y, 0, 0);
+#ifdef REPORT_2D_W
+	input_set_abs_params(rmi4_data->input_dev,
+			ABS_MT_TOUCH_MAJOR, 0,
+			MAX_ABS_MT_TOUCH_MAJOR, 0, 0);
+#endif
+
+#ifdef TYPE_B_PROTOCOL
+	input_mt_init_slots(rmi4_data->input_dev,
+			rmi4_data->num_of_fingers);
+#endif
+
 	i2c_set_clientdata(client, rmi4_data);
 
 	f1a = NULL;
@@ -2016,6 +2102,9 @@
 	}
 
 err_enable_irq:
+	cancel_delayed_work_sync(&rmi4_data->det_work);
+	flush_workqueue(rmi4_data->det_workqueue);
+	destroy_workqueue(rmi4_data->det_workqueue);
 	input_unregister_device(rmi4_data->input_dev);
 
 err_register_input:
@@ -2028,13 +2117,13 @@
 			kfree(fhandler);
 		}
 	}
-err_reset_gpio_req:
+err_reset_gpio_dir:
 	if (gpio_is_valid(platform_data->reset_gpio))
 		gpio_free(platform_data->reset_gpio);
-err_irq_gpio_req:
+err_irq_gpio_dir:
 	if (gpio_is_valid(platform_data->irq_gpio))
 		gpio_free(platform_data->irq_gpio);
-err_query_device:
+err_irq_gpio_req:
 	synaptics_rmi4_power_on(rmi4_data, false);
 err_power_device:
 	synaptics_rmi4_regulator_configure(rmi4_data, false);
@@ -2306,10 +2395,20 @@
 };
 MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
 
+#ifdef CONFIG_OF
+static struct of_device_id rmi4_match_table[] = {
+	{ .compatible = "synaptics,rmi4",},
+	{ },
+};
+#else
+#define rmi4_match_table NULL
+#endif
+
 static struct i2c_driver synaptics_rmi4_driver = {
 	.driver = {
 		.name = DRIVER_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = rmi4_match_table,
 #ifdef CONFIG_PM
 		.pm = &synaptics_rmi4_dev_pm_ops,
 #endif
diff --git a/include/linux/input/synaptics_dsx.h b/include/linux/input/synaptics_dsx.h
index 9d03787..56616d7 100644
--- a/include/linux/input/synaptics_dsx.h
+++ b/include/linux/input/synaptics_dsx.h
@@ -50,7 +50,8 @@
 	bool regulator_en;
 	bool i2c_pull_up;
 	unsigned irq_gpio;
-	unsigned long irq_flags;
+	u32 irq_flags;
+	u32 reset_flags;
 	unsigned reset_gpio;
 	unsigned panel_x;
 	unsigned panel_y;