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;