summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohan Pallaka <mpallaka@codeaurora.org>2014-02-12 15:17:28 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:57:51 -0700
commit358da51dda67c6747d8ff119d1311636ceacb7a5 (patch)
treefe35ac58186842f3bd6e385bb173696e7940adcc
parent7ef5f9cf4e6464f7128dccd58481977a91d69400 (diff)
input: synaptics_dsx: squash commit from 3.14 kernel
Squash and apply the following touchscreen changes taken from the msm-3.14 kernel branch as of msm-3.14 commit 3bc54cf86b (Merge "msm: camera: Add dummy sub module in sensor pipeline") b20792c2 input: synaptics_dsx: Fix security issues 4f3ec831 input: synaptics_dsx: Remove use of deprecated INIT_COMPLETION 8c5bd97f input: synaptics_dsx: change permission for sysfs secure_touch_enable b22c0b56 input: synaptics_dsx: reconfigure resolution in suspend 0ea26697 touchscreen: synaptics_dsx: set absolute axes for touchscreen 6a021e0a input: synaptics_dsx: handle all controller interrupts d3de3ed6 input: synaptics_dsx: remove query operation from reinit 2285a8dd input: synaptics_dsx: remove vkey kobject in remove 6817aed5 input: synaptics: Fix to secure touch clock unbalance 44a84a1e input: synaptics_dsx: support for pm ops 41439903 input: synaptics: add support for unprogrammed panels b029351d input: synaptics: remove outdated header d065c5e0 input: synaptics: add ability to distinguish touch part 72ca30da input: synaptics_dsx: release pinctrl resources on probe failure 0ab5f1e5 input: synaptics: add NULL pointer check ad4102c8 input: synaptics: Secure touch clocks 6a77bbed input: synaptics_dsx: fix compilation warning when !CONFIG_PM_* f3488933 input: synaptics_dsx: reorder device resume sequence 71b65447 input: synaptics_dsx: add support for 2D sensor for soft-keys 610ecdc2 input: synaptics_dsx: fix data sysfs read-write permission 06195779 input: synaptics_dsx: fix up world writable sysfs file 995ed76d input: synaptics_dsx: add ability to identify controller 69a416fe input: synaptic_dsx: configure touch panel boundary coordinates 609eb34b input: synaptics_dsx: correct sysfs permissions 59af5ffb input: synaptics_dsx: remove firmware update at boot 13b71e2f input: synaptic_dsx: stay awake the device during firmware update dccee682 input: synaptic_dsx: add sysfs entry for force firmware update a4d13992 input: synaptics: secure touch support 11c70731 input: synaptic_dsx: add debugfs support for suspend/resume 2642f2cb input: synaptics_dsx: add standard features for touch support 72f05e70 input: synaptics_dsx: add dual regulator support ab390caa input: synaptics_dsx: add device tree support 51898424 input: synaptics_dsx: fix conflicts with other drivers Signed-off-by: Alex Sarraf <asarraf@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/synaptics_dsx_i2c.txt103
-rw-r--r--drivers/input/touchscreen/Kconfig13
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/Kconfig42
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/Makefile12
-rw-r--r--[-rwxr-xr-x]drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c1741
-rw-r--r--[-rwxr-xr-x]drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h82
-rw-r--r--[-rwxr-xr-x]drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c267
-rwxr-xr-xdrivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c254
-rwxr-xr-xdrivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c6
-rw-r--r--[-rwxr-xr-x]drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c18
-rwxr-xr-xinclude/linux/input/synaptics_dsx_v2.h26
12 files changed, 2188 insertions, 377 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsx_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsx_i2c.txt
new file mode 100644
index 000000000000..2a77a029eee7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsx_i2c.txt
@@ -0,0 +1,103 @@
+Synaptics DSX touch controller
+
+Required properties:
+
+ - compatible : should be "synaptics,dsx"
+ - 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 : digital voltage power supply needed to power device
+ - avdd-supply : analog voltage power supply needed to power device
+ - 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,reset-delay-ms : reset delay for controller (ms), default 100
+ - synaptics,panel-coords : touch panel min x, min y, max x and
+ max y resolution
+ - synaptics,display-coords : display min x, min y, max x and
+ max y resolution
+ - synaptics,fw-name : name of firmware .img file in /etc/firmware
+ - synaptics,disable-gpios : specify this to disable gpios in suspend
+ - pinctrl-names : This should be defined if a target uses pinctrl framework.
+ See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+ It should specify the names of the configs that pinctrl can install in driver.
+ Following are the pinctrl configs that can be installed:
+ "pmx_ts_active" : Active configuration of pins, this should specify active
+ config defined in pin groups of interrupt and reset gpio.
+ "pmx_ts_suspend" : Disabled configuration of pins, this should specify sleep
+ config defined in pin groups of interrupt and reset gpio.
+ "pmx_ts_release" : Release configuration of pins, this should specify
+ release config defined in pin groups of interrupt and reset gpio.
+ - synaptics,detect-device : Define this property when two Synaptics Touchscreen controllers
+ need to be supported without changing the DT. In this case, all
+ such devices are placed as child nodes of Synaptics touchscreen
+ node. Following are the properties that can be defined inside
+ these child nodes:
+ - synaptics-package-id
+ - synaptics,panel-coords
+ - synaptics-display-coords
+ - synaptics,button-map
+ - synaptics,key-codes
+ - clocks : Optional property that represents the clocks associated
+ with the underlying bus when secure touch is enabled. This property
+ is required only if secure touch is enabled and used with this driver.
+ - clock-names: : Clock names used for secure touch. The names are:
+ "iface_clk", "core_clk".
+
+Optional properties inside child node:
+These properties are defined only when synaptics,detect-device property is defined in DT.
+ - synaptics,package-id : Specifies the Package Id of touch controller.
+ - synaptics,panel-coords : Specifies the Touch panel min x, min y, max x and max y
+ resolution.
+ - synaptics,display-coords : Specifies the display min x, min y, max x and max y
+ resolution.
+ - synaptics,button-map : Key code mappings to be used when device
+ supports 0D buttons and directly sends key codes.
+ - synaptics,key-codes : Virtual key code mappings to be used when device
+ supports 2D buttons and sends coordinates instead of
+ key codes.
+ - synaptics,bypass-sensor-coords-check : Bypass the comparison of sensor coordinates
+ range read from DT and touch controller. Used when some
+ touch panels in the field are unprogrammed and misprogrammed.
+
+Example:
+ i2c@f9927000 {
+ synaptics@20 {
+ compatible = "synaptics,dsx"
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2>;
+ vdd-supply = <&pm8226_l19>;
+ avdd-supply = <&pm8226_lvs1>;
+ synaptics,reset-gpio = <&msmgpio 16 0x00>;
+ synaptics,irq-gpio = <&msmgpio 17 0x00>;
+ synaptics,reset-delay-ms = <100>;
+ synaptics,x-flip;
+ synaptics,y-flip;
+ synaptics,disable-gpios;
+ synaptics,fw-name = "PR1610974.img";
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend", "pmx_ts_release";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ pinctrl-2 = <&ts_release>;
+ synaptics,detect-device;
+ synaptics,device1 {
+ synaptics,package-id = <3202>;
+ synaptics,button-map = <139 172 158>;
+ };
+ synaptics,device2 {
+ synaptics,package-id = <3408>;
+ synaptics,display-coords = <0 0 1079 1919>;
+ synaptics,panel-coords = <0 0 1079 2084>;
+ synaptics,key-codes = <139 172 158 217>;
+ };
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup5_i2c_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ };
+ };
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3af127f9ccbb..3b956417e9fb 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -11,7 +11,9 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN
-config TOUCHSCREEN_PROPERTIES
+source "drivers/input/touchscreen/synaptics_dsx/Kconfig"
+
+config OF_TOUCHSCREEN
def_tristate INPUT
depends on INPUT
@@ -1118,4 +1120,13 @@ config TOUCHSCREEN_MAXIM_STI
To compile this driver as a module, choose M here: the
module will be called maxim_sti.
+config SECURE_TOUCH
+ bool "Secure Touch"
+ depends on (TOUCHSCREEN_SYNAPTICS_I2C_RMI4 || \
+ TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21)
+ help
+ Say Y here to enable Secure Touch in supported drivers.
+
+ If unsure, say N.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 1ad6525ee400..aba207e9180a 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21) += synaptics_dsx/
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/synaptics_dsx/Kconfig b/drivers/input/touchscreen/synaptics_dsx/Kconfig
index 18591719f162..86263fddacea 100644
--- a/drivers/input/touchscreen/synaptics_dsx/Kconfig
+++ b/drivers/input/touchscreen/synaptics_dsx/Kconfig
@@ -1,7 +1,7 @@
#
# Synaptics DSX touchscreen driver configuration
#
-menuconfig TOUCHSCREEN_SYNAPTICS_DSX
+menuconfig TOUCHSCREEN_SYNAPTICS_DSX_v21
bool "Synaptics DSX touchscreen"
default y
help
@@ -10,22 +10,38 @@ menuconfig TOUCHSCREEN_SYNAPTICS_DSX
If unsure, say N.
-if TOUCHSCREEN_SYNAPTICS_DSX
+if TOUCHSCREEN_SYNAPTICS_DSX_v21
choice
- default TOUCHSCREEN_SYNAPTICS_DSX_I2C
+ default TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21
prompt "Synaptics DSX touchscreen bus interface"
-config TOUCHSCREEN_SYNAPTICS_DSX_I2C
+
+config TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21
bool "I2C"
depends on I2C
-config TOUCHSCREEN_SYNAPTICS_DSX_SPI
+ help
+ Say Y here if you have a Synaptics DSX touchscreen interfaced
+ to the host processor over I2C
+
+ If unsure, say N.
+
+ This module uses the services of DSX CORE
+
+config TOUCHSCREEN_SYNAPTICS_DSX_SPI_v21
bool "SPI"
depends on SPI_MASTER
+ help
+ Say Y here if you have a Synaptics DSX touchscreen interfaced
+ to the host processor over SPI
+
+ If unsure, say N.
+
+ This module uses the services of DSX CORE
endchoice
-config TOUCHSCREEN_SYNAPTICS_DSX_CORE
+config TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
tristate "Synaptics DSX core driver module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C || TOUCHSCREEN_SYNAPTICS_DSX_SPI
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21 || TOUCHSCREEN_SYNAPTICS_DSX_SPI_v21
help
Say Y here to enable basic touch reporting functionalities.
@@ -34,9 +50,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_CORE
To compile this driver as a module, choose M here: the
module will be called synaptics_dsx_core.
-config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV
+config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21
tristate "Synaptics DSX touchscreen RMI device module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
help
Say Y here to enable support for direct RMI register access.
@@ -45,9 +61,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV
To compile this driver as a module, choose M here: the
module will be called synaptics_dsx_rmi_dev.
-config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE
+config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21
tristate "Synaptics DSX touchscreen firmware update module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
help
Say Y here to enable support for carrying out firmware update.
@@ -56,9 +72,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE
To compile this driver as a module, choose M here: the
module will be called synaptics_dsx_fw_update.
-config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY
+config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v21
tristate "Synaptics DSX touchscreen proximity module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
help
Say Y here to enable support for proximity functionalities.
diff --git a/drivers/input/touchscreen/synaptics_dsx/Makefile b/drivers/input/touchscreen/synaptics_dsx/Makefile
index 7e7f218c07f9..b35b222d5ae2 100644
--- a/drivers/input/touchscreen/synaptics_dsx/Makefile
+++ b/drivers/input/touchscreen/synaptics_dsx/Makefile
@@ -4,9 +4,9 @@
# Each configuration option enables a list of files.
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C) += synaptics_dsx_i2c.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI) += synaptics_dsx_spi.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE) += synaptics_dsx_core.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV) += synaptics_dsx_rmi_dev.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_dsx_fw_update.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY) += synaptics_dsx_proximity.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21) += synaptics_dsx_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v21) += synaptics_dsx_spi.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21) += synaptics_dsx_core.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21) += synaptics_dsx_rmi_dev.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21) += synaptics_dsx_fw_update.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v21) += synaptics_dsx_proximity.o
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
index dbdaa3e6f612..8130ff9227bd 100755..100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (c) 2014-2015, 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
@@ -16,6 +17,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -25,13 +27,17 @@
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/input/synaptics_dsx.h>
+#include <linux/input/synaptics_dsx_v2.h>
#include "synaptics_dsx_core.h"
#ifdef KERNEL_ABOVE_2_6_38
#include <linux/input/mt.h>
#endif
+#if defined(CONFIG_SECURE_TOUCH)
+#include <linux/errno.h>
+#endif
#define INPUT_PHYS_NAME "synaptics_dsx/input0"
+#define DEBUGFS_DIR_NAME "ts_debug"
#ifdef KERNEL_ABOVE_2_6_38
#define TYPE_B_PROTOCOL
@@ -82,6 +88,9 @@
#define NO_SLEEP_ON (1 << 2)
#define CONFIGURED (1 << 7)
+#define SYNA_F11_MAX 4096
+#define SYNA_F12_MAX 65536
+
static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
unsigned short ctrl28);
@@ -89,13 +98,16 @@ static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data);
static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data);
static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
-#ifdef CONFIG_HAS_EARLYSUSPEND
static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void synaptics_rmi4_early_suspend(struct early_suspend *h);
static void synaptics_rmi4_late_resume(struct early_suspend *h);
@@ -108,6 +120,12 @@ static int synaptics_rmi4_resume(struct device *dev);
static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t synaptics_rmi4_set_abs_x_axis(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_set_abs_y_axis(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
struct device_attribute *attr, char *buf);
@@ -123,9 +141,19 @@ static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
-static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data);
+
+#if defined(CONFIG_SECURE_TOUCH)
+static ssize_t synaptics_secure_touch_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_secure_touch_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t synaptics_secure_touch_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+#endif
+
struct synaptics_rmi4_f01_device_status {
union {
struct {
@@ -333,14 +361,18 @@ struct synaptics_rmi4_exp_fn_data {
static struct synaptics_rmi4_exp_fn_data exp_data;
static struct device_attribute attrs[] = {
-#ifdef CONFIG_HAS_EARLYSUSPEND
- __ATTR(full_pm_cycle, (S_IRUGO | S_IWUGO),
+ __ATTR(full_pm_cycle, (S_IRUGO | S_IWUSR | S_IWGRP),
synaptics_rmi4_full_pm_cycle_show,
synaptics_rmi4_full_pm_cycle_store),
-#endif
- __ATTR(reset, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(reset, (S_IWUSR | S_IWGRP),
+ NULL,
synaptics_rmi4_f01_reset_store),
+ __ATTR(set_abs_x_axis, (S_IWUSR | S_IWGRP),
+ NULL,
+ synaptics_rmi4_set_abs_x_axis),
+ __ATTR(set_abs_y_axis, (S_IWUSR | S_IWGRP),
+ NULL,
+ synaptics_rmi4_set_abs_y_axis),
__ATTR(productinfo, S_IRUGO,
synaptics_rmi4_f01_productinfo_show,
synaptics_rmi4_store_error),
@@ -350,17 +382,275 @@ static struct device_attribute attrs[] = {
__ATTR(flashprog, S_IRUGO,
synaptics_rmi4_f01_flashprog_show,
synaptics_rmi4_store_error),
- __ATTR(0dbutton, (S_IRUGO | S_IWUGO),
+ __ATTR(0dbutton, (S_IRUGO | S_IWUSR | S_IWGRP),
synaptics_rmi4_0dbutton_show,
synaptics_rmi4_0dbutton_store),
- __ATTR(suspend, S_IWUGO,
- synaptics_rmi4_show_error,
- synaptics_rmi4_suspend_store),
+#if defined(CONFIG_SECURE_TOUCH)
+ __ATTR(secure_touch_enable, (S_IRUGO | S_IWUSR | S_IWGRP),
+ synaptics_secure_touch_enable_show,
+ synaptics_secure_touch_enable_store),
+ __ATTR(secure_touch, S_IRUGO ,
+ synaptics_secure_touch_show,
+ NULL),
+#endif
};
+#define MAX_BUF_SIZE 256
+#define VKEY_VER_CODE "0x01"
+
+#define HEIGHT_SCALE_NUM 8
+#define HEIGHT_SCALE_DENOM 10
+
+/* numerator and denomenator for border equations */
+#define BORDER_ADJUST_NUM 3
+#define BORDER_ADJUST_DENOM 4
+
+static struct kobject *vkey_kobj;
+static char *vkey_buf;
+
+static ssize_t vkey_show(struct kobject *obj,
+ struct kobj_attribute *attr, char *buf)
+{
+ strlcpy(buf, vkey_buf, MAX_BUF_SIZE);
+ return strnlen(buf, MAX_BUF_SIZE);
+}
+
+static struct kobj_attribute vkey_obj_attr = {
+ .attr = {
+ .mode = S_IRUGO,
+ .name = "virtualkeys."PLATFORM_DRIVER_NAME,
+ },
+ .show = vkey_show,
+};
+
+static struct attribute *vkey_attr[] = {
+ &vkey_obj_attr.attr,
+ NULL,
+};
+
+static struct attribute_group vkey_grp = {
+ .attrs = vkey_attr,
+};
+
+static int synaptics_rmi4_debug_suspend_set(void *_data, u64 val)
+{
+ struct synaptics_rmi4_data *rmi4_data = _data;
+
+ if (val)
+ synaptics_rmi4_suspend(&rmi4_data->input_dev->dev);
+ else
+ synaptics_rmi4_resume(&rmi4_data->input_dev->dev);
+
+ return 0;
+}
+
+static int synaptics_rmi4_debug_suspend_get(void *_data, u64 *val)
+{
+ struct synaptics_rmi4_data *rmi4_data = _data;
+
+ *val = rmi4_data->suspended;
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, synaptics_rmi4_debug_suspend_get,
+ synaptics_rmi4_debug_suspend_set, "%lld\n");
+
+#if defined(CONFIG_SECURE_TOUCH)
+static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data)
+{
+ int ret = 0;
+ data->st_initialized = 0;
+ init_completion(&data->st_powerdown);
+ init_completion(&data->st_irq_processed);
+ /* Get clocks */
+ data->core_clk = clk_get(data->pdev->dev.parent, "core_clk");
+ if (IS_ERR(data->core_clk)) {
+ ret = PTR_ERR(data->core_clk);
+ dev_err(data->pdev->dev.parent,
+ "%s: error on clk_get(core_clk):%d\n", __func__, ret);
+ return;
+ }
+
+ data->iface_clk = clk_get(data->pdev->dev.parent, "iface_clk");
+ if (IS_ERR(data->iface_clk)) {
+ ret = PTR_ERR(data->iface_clk);
+ dev_err(data->pdev->dev.parent,
+ "%s: error on clk_get(iface_clk):%d\n", __func__, ret);
+ goto err_iface_clk;
+ }
+
+ data->st_initialized = 1;
+ return;
+
+err_iface_clk:
+ clk_put(data->core_clk);
+ data->core_clk = NULL;
+}
+static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data)
+{
+ sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch");
+}
+static irqreturn_t synaptics_filter_interrupt(
+ struct synaptics_rmi4_data *rmi4_data)
+{
+ if (atomic_read(&rmi4_data->st_enabled)) {
+ if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) {
+ synaptics_secure_touch_notify(rmi4_data);
+ wait_for_completion_interruptible(
+ &rmi4_data->st_irq_processed);
+ }
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+static void synaptics_secure_touch_stop(
+ struct synaptics_rmi4_data *rmi4_data,
+ int blocking)
+{
+ if (atomic_read(&rmi4_data->st_enabled)) {
+ atomic_set(&rmi4_data->st_pending_irqs, -1);
+ synaptics_secure_touch_notify(rmi4_data);
+ if (blocking)
+ wait_for_completion_interruptible(
+ &rmi4_data->st_powerdown);
+ }
+}
+#else
+static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data)
+{
+}
+static irqreturn_t synaptics_filter_interrupt(
+ struct synaptics_rmi4_data *rmi4_data)
+{
+ return IRQ_NONE;
+}
+static void synaptics_secure_touch_stop(
+ struct synaptics_rmi4_data *rmi4_data,
+ int blocking)
+{
+}
+#endif
+#if defined(CONFIG_SECURE_TOUCH)
+static ssize_t synaptics_secure_touch_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ return scnprintf(
+ buf,
+ PAGE_SIZE,
+ "%d",
+ atomic_read(&rmi4_data->st_enabled));
+}
+/*
+ * Accept only "0" and "1" valid values.
+ * "0" will reset the st_enabled flag, then wake up the reading process and
+ * the interrupt handler.
+ * The bus driver is notified via pm_runtime that it is not required to stay
+ * awake anymore.
+ * It will also make sure the queue of events is emptied in the controller,
+ * in case a touch happened in between the secure touch being disabled and
+ * the local ISR being ungated.
+ * "1" will set the st_enabled flag and clear the st_pending_irqs flag.
+ * The bus driver is requested via pm_runtime to stay awake.
+ */
+static ssize_t synaptics_secure_touch_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ unsigned long value;
+ int err = 0;
+
+ if (count > 2)
+ return -EINVAL;
+
+ err = kstrtoul(buf, 10, &value);
+ if (err != 0)
+ return err;
+
+ if (!rmi4_data->st_initialized)
+ return -EIO;
+
+ err = count;
+
+ switch (value) {
+ case 0:
+ if (atomic_read(&rmi4_data->st_enabled) == 0)
+ break;
+
+ synaptics_rmi4_bus_put(rmi4_data);
+ atomic_set(&rmi4_data->st_enabled, 0);
+ synaptics_secure_touch_notify(rmi4_data);
+ complete(&rmi4_data->st_irq_processed);
+ synaptics_rmi4_irq(rmi4_data->irq, rmi4_data);
+ complete(&rmi4_data->st_powerdown);
+
+ break;
+ case 1:
+ if (atomic_read(&rmi4_data->st_enabled)) {
+ err = -EBUSY;
+ break;
+ }
+
+ synchronize_irq(rmi4_data->irq);
+
+ if (synaptics_rmi4_bus_get(rmi4_data) < 0) {
+ dev_err(
+ rmi4_data->pdev->dev.parent,
+ "synaptics_rmi4_bus_get failed\n");
+ err = -EIO;
+ break;
+ }
+ reinit_completion(&rmi4_data->st_powerdown);
+ reinit_completion(&rmi4_data->st_irq_processed);
+ atomic_set(&rmi4_data->st_enabled, 1);
+ atomic_set(&rmi4_data->st_pending_irqs, 0);
+ break;
+ default:
+ dev_err(
+ rmi4_data->pdev->dev.parent,
+ "unsupported value: %lu\n", value);
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+/*
+ * This function returns whether there are pending interrupts, or
+ * other error conditions that need to be signaled to the userspace library,
+ * according tot he following logic:
+ * - st_enabled is 0 if secure touch is not enabled, returning -EBADF
+ * - st_pending_irqs is -1 to signal that secure touch is in being stopped,
+ * returning -EINVAL
+ * - st_pending_irqs is 1 to signal that there is a pending irq, returning
+ * the value "1" to the sysfs read operation
+ * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt
+ * has been processed, so the interrupt handler can be allowed to continue.
+ */
+static ssize_t synaptics_secure_touch_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ int val = 0;
+ if (atomic_read(&rmi4_data->st_enabled) == 0)
+ return -EBADF;
+
+ if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1)
+ return -EINVAL;
+
+ if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1)
+ val = 1;
+ else
+ complete(&rmi4_data->st_irq_processed);
+
+ return scnprintf(buf, PAGE_SIZE, "%u", val);
+
+}
+#endif
-#ifdef CONFIG_HAS_EARLYSUSPEND
static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -383,7 +673,42 @@ static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev,
return count;
}
-#endif
+
+static ssize_t synaptics_rmi4_set_abs_x_axis(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ if (input == 0)
+ return -EINVAL;
+
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_X,
+ 0, input, 0, 0);
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_set_abs_y_axis(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ if (input == 0)
+ return -EINVAL;
+
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_Y,
+ 0, input, 0, 0);
+
+ return count;
+}
static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -513,24 +838,6 @@ static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
return count;
}
-static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- synaptics_rmi4_suspend(dev);
- else if (input == 0)
- synaptics_rmi4_resume(dev);
- else
- return -EINVAL;
-
- return count;
-}
-
/**
* synaptics_rmi4_f11_abs_report()
*
@@ -729,21 +1036,25 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
/* Start checking from the highest bit */
temp = extra_data->data15_size - 1; /* Highest byte */
- finger = (fingers_to_process - 1) % 8; /* Highest bit */
- do {
- if (extra_data->data15_data[temp] & (1 << finger))
- break;
-
- if (finger) {
- finger--;
- } else {
- temp--; /* Move to the next lower byte */
- finger = 7;
- }
+ if ((temp >= 0) && (fingers_to_process > 0) &&
+ (temp < ((F12_FINGERS_TO_SUPPORT + 7) / 8))) {
+ finger = (fingers_to_process - 1) % 8; /* Highest bit */
+ do {
+ if (extra_data->data15_data[temp]
+ & (1 << finger))
+ break;
- fingers_to_process--;
- } while (fingers_to_process);
+ if (finger) {
+ finger--;
+ } else {
+ /* Move to the next lower byte */
+ temp--;
+ finger = 7;
+ }
+ fingers_to_process--;
+ } while (fingers_to_process && (temp >= 0));
+ }
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Number of fingers to process = %d\n",
__func__, fingers_to_process);
@@ -1096,8 +1407,10 @@ static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
{
struct synaptics_rmi4_data *rmi4_data = data;
- if (!rmi4_data->touch_stopped)
- synaptics_rmi4_sensor_report(rmi4_data);
+ if (IRQ_HANDLED == synaptics_filter_interrupt(data))
+ return IRQ_HANDLED;
+
+ synaptics_rmi4_sensor_report(rmi4_data);
return IRQ_HANDLED;
}
@@ -1198,16 +1511,88 @@ static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data,
}
/**
- * synaptics_rmi4_f11_init()
- *
- * Called by synaptics_rmi4_query_device().
- *
- * This funtion parses information from the Function 11 registers
- * and determines the number of fingers supported, x and y data ranges,
- * offset to the associated interrupt status register, interrupt bit
- * mask, and gathers finger data acquisition capabilities from the query
- * registers.
- */
+ * synaptics_rmi4_f11_set_coords()
+ *
+ * Set panel resolution for f11 to match display resolution.
+ *
+ */
+static int synaptics_rmi4_f11_set_coords(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char control[F11_STD_CTRL_LEN];
+ const struct synaptics_dsx_board_data *bdata =
+ rmi4_data->hw_if->board_data;
+
+ if (!rmi4_data->update_coords) {
+ dev_dbg(rmi4_data->pdev->dev.parent,
+ "%s: No need to update panel resolution\n", __func__);
+ return 0;
+ }
+
+ retval = synaptics_rmi4_reg_read(rmi4_data,
+ fhandler->full_addr.ctrl_base,
+ control,
+ sizeof(control));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum x and y */
+ rmi4_data->sensor_max_x = ((control[6] & MASK_8BIT) << 0) |
+ ((control[7] & MASK_4BIT) << 8);
+ rmi4_data->sensor_max_y = ((control[8] & MASK_8BIT) << 0) |
+ ((control[9] & MASK_4BIT) << 8);
+
+ if (bdata->panel_maxx && bdata->panel_maxy &&
+ (rmi4_data->sensor_max_x != bdata->panel_maxx ||
+ rmi4_data->sensor_max_y != bdata->panel_maxy)) {
+ if (bdata->panel_maxx > SYNA_F11_MAX ||
+ bdata->panel_maxy > SYNA_F11_MAX) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Invalid panel resolution\n", __func__);
+ return -EINVAL;
+ }
+
+ rmi4_data->sensor_max_x = bdata->panel_maxx;
+ rmi4_data->sensor_max_y = bdata->panel_maxy;
+ control[6] = rmi4_data->sensor_max_x & MASK_8BIT;
+ control[7] = (rmi4_data->sensor_max_x >> 8) & MASK_4BIT;
+ control[8] = rmi4_data->sensor_max_y & MASK_8BIT;
+ control[9] = (rmi4_data->sensor_max_y >> 8) & MASK_4BIT;
+
+ retval = synaptics_rmi4_reg_write(rmi4_data,
+ fhandler->full_addr.ctrl_base,
+ control,
+ sizeof(control));
+ if (retval < 0)
+ return retval;
+ rmi4_data->update_coords = true;
+ } else {
+ rmi4_data->update_coords = false;
+ }
+
+ dev_dbg(rmi4_data->pdev->dev.parent,
+ "%s: Function %02x max x = %d max y = %d\n",
+ __func__, fhandler->fn_number,
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+
+ rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_f11_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This funtion parses information from the Function 11 registers
+ * and determines the number of fingers supported, x and y data ranges,
+ * offset to the associated interrupt status register, interrupt bit
+ * mask, and gathers finger data acquisition capabilities from the query
+ * registers.
+ */
static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
struct synaptics_rmi4_fn *fhandler,
struct synaptics_rmi4_fn_desc *fd,
@@ -1217,7 +1602,6 @@ static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
unsigned char abs_data_size;
unsigned char abs_data_blk_size;
unsigned char query[F11_STD_QUERY_LEN];
- unsigned char control[F11_STD_CTRL_LEN];
fhandler->fn_number = fd->fn_number;
fhandler->num_of_data_sources = fd->intr_src_count;
@@ -1237,26 +1621,10 @@ static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
rmi4_data->num_of_fingers = fhandler->num_of_data_points;
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base,
- control,
- sizeof(control));
+ retval = synaptics_rmi4_f11_set_coords(rmi4_data, fhandler);
if (retval < 0)
return retval;
- /* Maximum x and y */
- rmi4_data->sensor_max_x = ((control[6] & MASK_8BIT) << 0) |
- ((control[7] & MASK_4BIT) << 8);
- rmi4_data->sensor_max_y = ((control[8] & MASK_8BIT) << 0) |
- ((control[9] & MASK_4BIT) << 8);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Function %02x max x = %d max y = %d\n",
- __func__, fhandler->fn_number,
- rmi4_data->sensor_max_x,
- rmi4_data->sensor_max_y);
-
- rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
-
synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
abs_data_size = query[5] & MASK_2BIT;
@@ -1288,16 +1656,116 @@ static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
}
/**
- * synaptics_rmi4_f12_init()
- *
- * Called by synaptics_rmi4_query_device().
- *
- * This funtion parses information from the Function 12 registers and
- * determines the number of fingers supported, offset to the data1
- * register, x and y data ranges, offset to the associated interrupt
- * status register, interrupt bit mask, and allocates memory resources
- * for finger data acquisition.
- */
+ * synaptics_rmi4_f12_set_coords()
+ *
+ * Set panel resolution for f12 to match display resolution.
+ *
+ */
+static int synaptics_rmi4_f12_set_coords(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+
+ const struct synaptics_dsx_board_data *bdata =
+ rmi4_data->hw_if->board_data;
+ struct synaptics_rmi4_f12_query_5 query_5;
+ struct synaptics_rmi4_f12_ctrl_8 ctrl_8;
+ unsigned char ctrl_8_offset;
+ int retval;
+
+ if (!rmi4_data->update_coords) {
+ dev_dbg(rmi4_data->pdev->dev.parent,
+ "%s: No need to update panel resolution\n", __func__);
+ return 0;
+ }
+
+ retval = synaptics_rmi4_reg_read(rmi4_data,
+ fhandler->full_addr.query_base + 5,
+ query_5.data,
+ sizeof(query_5.data));
+ if (retval < 0)
+ return retval;
+
+ ctrl_8_offset = query_5.ctrl0_is_present +
+ query_5.ctrl1_is_present +
+ query_5.ctrl2_is_present +
+ query_5.ctrl3_is_present +
+ query_5.ctrl4_is_present +
+ query_5.ctrl5_is_present +
+ query_5.ctrl6_is_present +
+ query_5.ctrl7_is_present;
+
+ retval = synaptics_rmi4_reg_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_8_offset,
+ ctrl_8.data,
+ sizeof(ctrl_8.data));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum x and y */
+ rmi4_data->sensor_max_x =
+ ((unsigned short)ctrl_8.max_x_coord_lsb << 0) |
+ ((unsigned short)ctrl_8.max_x_coord_msb << 8);
+ rmi4_data->sensor_max_y =
+ ((unsigned short)ctrl_8.max_y_coord_lsb << 0) |
+ ((unsigned short)ctrl_8.max_y_coord_msb << 8);
+
+ if (bdata->panel_maxx && bdata->panel_maxy &&
+ (rmi4_data->sensor_max_x != bdata->panel_maxx ||
+ rmi4_data->sensor_max_y != bdata->panel_maxy)) {
+
+ if (bdata->panel_maxx > SYNA_F12_MAX ||
+ bdata->panel_maxy > SYNA_F12_MAX) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Invalid panel resolution\n", __func__);
+ retval = -EINVAL;
+ return retval;
+ }
+
+ rmi4_data->sensor_max_x = bdata->panel_maxx;
+ rmi4_data->sensor_max_y = bdata->panel_maxy;
+ ctrl_8.max_x_coord_lsb = rmi4_data->sensor_max_x & MASK_8BIT;
+ ctrl_8.max_x_coord_msb = (rmi4_data->sensor_max_x >> 8) &
+ MASK_4BIT;
+ ctrl_8.max_y_coord_lsb = rmi4_data->sensor_max_y & MASK_8BIT;
+ ctrl_8.max_y_coord_msb = (rmi4_data->sensor_max_y >> 8) &
+ MASK_4BIT;
+
+ retval = synaptics_rmi4_reg_write(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_8_offset,
+ ctrl_8.data,
+ sizeof(ctrl_8.data));
+ if (retval < 0)
+ return retval;
+ rmi4_data->update_coords = true;
+ } else {
+ rmi4_data->update_coords = false;
+ }
+
+ dev_dbg(rmi4_data->pdev->dev.parent,
+ "%s: Function %02x max x = %d max y = %d\n",
+ __func__, fhandler->fn_number,
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+
+ rmi4_data->num_of_rx = ctrl_8.num_of_rx;
+ rmi4_data->num_of_tx = ctrl_8.num_of_tx;
+ rmi4_data->max_touch_width = max(rmi4_data->num_of_rx,
+ rmi4_data->num_of_tx);
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_f12_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This funtion parses information from the Function 12 registers and
+ * determines the number of fingers supported, offset to the data1
+ * register, x and y data ranges, offset to the associated interrupt
+ * status register, interrupt bit mask, and allocates memory resources
+ * for finger data acquisition.
+ */
static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
struct synaptics_rmi4_fn *fhandler,
struct synaptics_rmi4_fn_desc *fd,
@@ -1313,21 +1781,27 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
struct synaptics_rmi4_f12_extra_data *extra_data;
struct synaptics_rmi4_f12_query_5 query_5;
struct synaptics_rmi4_f12_query_8 query_8;
- struct synaptics_rmi4_f12_ctrl_8 ctrl_8;
struct synaptics_rmi4_f12_ctrl_23 ctrl_23;
fhandler->fn_number = fd->fn_number;
fhandler->num_of_data_sources = fd->intr_src_count;
+ size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+ if (!fhandler->extra) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to alloc mem for function handler\n",
+ __func__);
+ return -ENOMEM;
+ }
extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
retval = synaptics_rmi4_reg_read(rmi4_data,
fhandler->full_addr.query_base + 5,
query_5.data,
sizeof(query_5.data));
if (retval < 0)
- return retval;
+ goto free_function_handler_mem;
ctrl_8_offset = query_5.ctrl0_is_present +
query_5.ctrl1_is_present +
@@ -1367,7 +1841,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
ctrl_23.data,
sizeof(ctrl_23.data));
if (retval < 0)
- return retval;
+ goto free_function_handler_mem;
/* Maximum number of fingers supported */
fhandler->num_of_data_points = min(ctrl_23.max_reported_objects,
@@ -1381,14 +1855,14 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
&size_of_query8,
sizeof(size_of_query8));
if (retval < 0)
- return retval;
+ goto free_function_handler_mem;
retval = synaptics_rmi4_reg_read(rmi4_data,
fhandler->full_addr.query_base + 8,
query_8.data,
size_of_query8);
if (retval < 0)
- return retval;
+ goto free_function_handler_mem;
/* Determine the presence of the Data0 register */
extra_data->data1_offset = query_8.data0_is_present;
@@ -1425,39 +1899,30 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
retval = synaptics_rmi4_f12_set_enables(rmi4_data,
fhandler->full_addr.ctrl_base + ctrl_28_offset);
if (retval < 0)
- return retval;
+ goto free_function_handler_mem;
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base + ctrl_8_offset,
- ctrl_8.data,
- sizeof(ctrl_8.data));
- if (retval < 0)
- return retval;
-
- /* Maximum x and y */
- rmi4_data->sensor_max_x =
- ((unsigned short)ctrl_8.max_x_coord_lsb << 0) |
- ((unsigned short)ctrl_8.max_x_coord_msb << 8);
- rmi4_data->sensor_max_y =
- ((unsigned short)ctrl_8.max_y_coord_lsb << 0) |
- ((unsigned short)ctrl_8.max_y_coord_msb << 8);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Function %02x max x = %d max y = %d\n",
- __func__, fhandler->fn_number,
- rmi4_data->sensor_max_x,
- rmi4_data->sensor_max_y);
- rmi4_data->num_of_rx = ctrl_8.num_of_rx;
- rmi4_data->num_of_tx = ctrl_8.num_of_tx;
- rmi4_data->max_touch_width = max(rmi4_data->num_of_rx,
- rmi4_data->num_of_tx);
+ retval = synaptics_rmi4_f12_set_coords(rmi4_data, fhandler);
+ if (retval < 0)
+ goto free_function_handler_mem;
synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
/* Allocate memory for finger data storage space */
fhandler->data_size = num_of_fingers * size_of_2d_data;
fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL);
+ if (!fhandler->data) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to alloc mem for function handler data\n",
+ __func__);
+ retval = -ENOMEM;
+ goto free_function_handler_mem;
+ }
+
+ return retval;
+free_function_handler_mem:
+ kfree(fhandler->extra);
return retval;
}
@@ -1552,15 +2017,13 @@ static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data,
}
if (!bdata->cap_button_map) {
- dev_err(rmi4_data->pdev->dev.parent,
+ dev_dbg(rmi4_data->pdev->dev.parent,
"%s: cap_button_map is NULL in board file\n",
__func__);
- return -ENODEV;
} else if (!bdata->cap_button_map->map) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Button map is missing in board file\n",
__func__);
- return -ENODEV;
} else {
if (bdata->cap_button_map->nbuttons != f1a->max_count) {
f1a->valid_button_count = min(f1a->max_count,
@@ -1799,6 +2262,7 @@ static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
struct synaptics_rmi4_fn_desc rmi_fd;
struct synaptics_rmi4_fn *fhandler;
struct synaptics_rmi4_device_info *rmi;
+ unsigned char pkg_id[PACKAGE_ID_SIZE];
rmi = &(rmi4_data->rmi4_mod_info);
@@ -1997,6 +2461,19 @@ flash_prog_mode:
}
retval = synaptics_rmi4_reg_read(rmi4_data,
+ rmi4_data->f01_query_base_addr + F01_PACKAGE_ID_OFFSET,
+ pkg_id, sizeof(pkg_id));
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to read device package id (code %d)\n",
+ __func__, retval);
+ return retval;
+ }
+
+ rmi->package_id = (pkg_id[1] << 8) | pkg_id[0];
+ rmi->package_id_rev = (pkg_id[3] << 8) | pkg_id[2];
+
+ retval = synaptics_rmi4_reg_read(rmi4_data,
rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET,
rmi->build_id,
sizeof(rmi->build_id));
@@ -2049,15 +2526,23 @@ static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data)
struct synaptics_rmi4_f1a_handle *f1a;
struct synaptics_rmi4_fn *fhandler;
struct synaptics_rmi4_device_info *rmi;
+ const struct synaptics_dsx_board_data *bdata =
+ rmi4_data->hw_if->board_data;
rmi = &(rmi4_data->rmi4_mod_info);
- 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);
+ if (bdata->disp_maxx && bdata->disp_maxy) {
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_X,
+ 0, bdata->disp_maxx, 0, 0);
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_Y,
+ 0, bdata->disp_maxy, 0, 0);
+ } else {
+ 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,
@@ -2069,7 +2554,7 @@ static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data)
#ifdef TYPE_B_PROTOCOL
input_mt_init_slots(rmi4_data->input_dev,
- rmi4_data->num_of_fingers);
+ rmi4_data->num_of_fingers, 0);
#endif
f1a = NULL;
@@ -2092,6 +2577,273 @@ static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data)
return;
}
+static int synaptics_dsx_virtual_keys_init(struct device *dev,
+ struct synaptics_dsx_board_data *rmi4_pdata)
+{
+ int width, height, center_x, center_y;
+ int x1 = 0, x2 = 0, i, c = 0, rc = 0, border;
+
+ vkey_buf = devm_kzalloc(dev, MAX_BUF_SIZE, GFP_KERNEL);
+ if (!vkey_buf) {
+ dev_err(dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ border = (rmi4_pdata->panel_maxx - rmi4_pdata->disp_maxx) * 2;
+ width = ((rmi4_pdata->disp_maxx -
+ (border * (rmi4_pdata->virtual_key_map->nkeys - 1)))
+ / rmi4_pdata->virtual_key_map->nkeys);
+ height = (rmi4_pdata->panel_maxy - rmi4_pdata->disp_maxy);
+ center_y = rmi4_pdata->disp_maxy + (height / 2);
+ height = height * HEIGHT_SCALE_NUM / HEIGHT_SCALE_DENOM;
+
+ x2 -= border * BORDER_ADJUST_NUM / BORDER_ADJUST_DENOM;
+
+ for (i = 0; i < rmi4_pdata->virtual_key_map->nkeys; i++) {
+ x1 = x2 + border;
+ x2 = x2 + border + width;
+ center_x = x1 + (x2 - x1) / 2;
+ c += snprintf(vkey_buf + c, MAX_BUF_SIZE - c,
+ "%s:%d:%d:%d:%d:%d\n", VKEY_VER_CODE,
+ rmi4_pdata->virtual_key_map->map[i],
+ center_x, center_y, width, height);
+ }
+
+ vkey_buf[c] = '\0';
+
+ vkey_kobj = kobject_create_and_add("board_properties", NULL);
+ if (!vkey_kobj) {
+ dev_err(dev, "unable to create kobject\n");
+ return -ENOMEM;
+ }
+
+ rc = sysfs_create_group(vkey_kobj, &vkey_grp);
+ if (rc) {
+ dev_err(dev, "failed to create attributes\n");
+ kobject_put(vkey_kobj);
+ }
+
+ return rc;
+}
+
+static int synaptics_dsx_get_virtual_keys(struct device *dev,
+ struct property *prop, char *name,
+ struct synaptics_dsx_board_data *rmi4_pdata,
+ struct device_node *np)
+{
+ u32 num_keys;
+ int rc;
+
+ num_keys = prop->length / sizeof(u32);
+
+ rmi4_pdata->virtual_key_map = devm_kzalloc(dev,
+ sizeof(*rmi4_pdata->virtual_key_map),
+ GFP_KERNEL);
+ if (!rmi4_pdata->virtual_key_map)
+ return -ENOMEM;
+
+ rmi4_pdata->virtual_key_map->map = devm_kzalloc(dev,
+ sizeof(*rmi4_pdata->virtual_key_map->map) *
+ num_keys, GFP_KERNEL);
+ if (!rmi4_pdata->virtual_key_map->map)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(np, name,
+ rmi4_pdata->virtual_key_map->map,
+ num_keys);
+ if (rc) {
+ dev_err(dev, "Failed to read key codes\n");
+ return -EINVAL;
+ }
+ rmi4_pdata->virtual_key_map->nkeys = num_keys;
+
+ return 0;
+}
+
+static int synaptics_dsx_get_button_map(struct device *dev,
+ struct property *prop, char *name,
+ struct synaptics_dsx_board_data *rmi4_pdata,
+ struct device_node *np)
+{
+ int rc, i;
+ u32 num_buttons;
+ u32 button_map[MAX_NUMBER_OF_BUTTONS];
+
+ num_buttons = prop->length / sizeof(u32);
+
+ rmi4_pdata->cap_button_map = devm_kzalloc(dev,
+ sizeof(*rmi4_pdata->cap_button_map),
+ GFP_KERNEL);
+ if (!rmi4_pdata->cap_button_map)
+ return -ENOMEM;
+
+ rmi4_pdata->cap_button_map->map = devm_kzalloc(dev,
+ sizeof(*rmi4_pdata->cap_button_map->map) *
+ num_buttons, GFP_KERNEL);
+ if (!rmi4_pdata->cap_button_map->map)
+ return -ENOMEM;
+
+ if (num_buttons <= MAX_NUMBER_OF_BUTTONS) {
+ rc = of_property_read_u32_array(np,
+ name, 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->cap_button_map->map[i] =
+ button_map[i];
+ rmi4_pdata->cap_button_map->nbuttons = num_buttons;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int synaptics_rmi4_parse_dt_children(struct device *dev,
+ struct synaptics_dsx_board_data *rmi4_pdata,
+ struct synaptics_rmi4_data *rmi4_data)
+{
+ struct synaptics_rmi4_device_info *rmi = &rmi4_data->rmi4_mod_info;
+ struct device_node *node = dev->of_node, *child = NULL;
+ int rc = 0;
+ struct synaptics_rmi4_fn *fhandler = NULL;
+ struct property *prop;
+
+ for_each_child_of_node(node, child) {
+ rc = of_property_read_u32(child, "synaptics,package-id",
+ &rmi4_pdata->package_id);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read package_id\n");
+ return rc;
+ } else if (rc == -EINVAL) {
+ rmi4_pdata->package_id = 0x00;
+ }
+
+ if (rmi4_pdata->package_id) {
+ if (rmi4_pdata->package_id != rmi->package_id) {
+ dev_err(dev,
+ "%s: Synaptics package id don't match %d %d\n",
+ __func__,
+ rmi4_pdata->package_id, rmi->package_id);
+ /*
+ * Iterate over next child if package
+ * id does not match
+ */
+ continue;
+ } else if (of_property_read_bool(child,
+ "synaptics,bypass-sensor-coords-check")) {
+ /*
+ * Some unprogrammed panels from touch vendor
+ * and wrongly programmed panels from factory
+ * may return incorrect sensor coordinate range
+ * when their query registers are read, but
+ * they normally work fine in field. In such
+ * a scenario, driver can bypass the comparison
+ * of coordinate range read from sensor and read
+ * from DT and continue normal operation.
+ */
+ dev_info(dev,
+ "%s Synaptics package id matches %d %d,"
+ "but bypassing the comparison of sensor"
+ "coordinates.\n", __func__,
+ rmi4_pdata->package_id,
+ rmi->package_id);
+ dev_info(dev, "Pmax_x Pmax_y = %d:%d\n",
+ rmi4_pdata->panel_maxx,
+ rmi4_pdata->panel_maxy);
+ dev_info(dev, "Smax_x Smax_y = %d:%d\n",
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+ } else {
+ /*
+ * If package id read from DT matches the
+ * package id value read from touch controller,
+ * also check if sensor dimensions read from DT
+ * match those read from controller, before
+ * moving further. For this first check if touch
+ * panel coordinates are defined in DT or not.
+ */
+ if (of_find_property(child,
+ "synaptics,panel-coords", NULL)) {
+ synaptics_dsx_get_dt_coords(dev,
+ "synaptics,panel-coords",
+ rmi4_pdata, child);
+ dev_info(dev, "Pmax_x Pmax_y = %d:%d\n",
+ rmi4_pdata->panel_maxx,
+ rmi4_pdata->panel_maxy);
+ dev_info(dev, "Smax_x Smax_y = %d:%d\n",
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+ if ((rmi4_pdata->panel_maxx !=
+ rmi4_data->sensor_max_x) ||
+ (rmi4_pdata->panel_maxy !=
+ rmi4_data->sensor_max_y))
+ continue;
+ }
+ }
+ }
+
+ rc = synaptics_dsx_get_dt_coords(dev,
+ "synaptics,display-coords", rmi4_pdata, child);
+ if (rc && (rc != -EINVAL))
+ return rc;
+
+ prop = of_find_property(child, "synaptics,button-map", NULL);
+ if (prop) {
+ rc = synaptics_dsx_get_button_map(dev, prop,
+ "synaptics,button-map", rmi4_pdata, child);
+ if (rc < 0) {
+ dev_err(dev, "Unable to read button map\n");
+ return rc;
+ }
+
+ if (!list_empty(&rmi->support_fn_list)) {
+ list_for_each_entry(fhandler,
+ &rmi->support_fn_list, link) {
+ if (fhandler->fn_number ==
+ SYNAPTICS_RMI4_F1A)
+ break;
+ }
+ }
+
+ if (fhandler && fhandler->fn_number ==
+ SYNAPTICS_RMI4_F1A) {
+ rc = synaptics_rmi4_f1a_button_map(rmi4_data,
+ fhandler);
+ if (rc < 0) {
+ dev_err(dev,
+ "Fail to register F1A %d\n",
+ rc);
+ return rc;
+ }
+ }
+ }
+
+ prop = of_find_property(child, "synaptics,key-codes", NULL);
+ if (prop) {
+ rc = synaptics_dsx_get_virtual_keys(dev, prop,
+ "synaptics,key-codes", rmi4_pdata, child);
+ if (!rc) {
+ rc = synaptics_dsx_virtual_keys_init(dev,
+ rmi4_pdata);
+ if (!rc)
+ rmi4_data->support_vkeys = true;
+
+ } else {
+ dev_err(dev,
+ "Unable to read virtual key codes\n");
+ return rc;
+ }
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
@@ -2114,6 +2866,17 @@ static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data)
goto err_query_device;
}
+ if (rmi4_data->hw_if->board_data->detect_device) {
+ retval = synaptics_rmi4_parse_dt_children(
+ rmi4_data->pdev->dev.parent,
+ rmi4_data->hw_if->board_data,
+ rmi4_data);
+ if (retval < 0)
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to parse device tree property\n",
+ __func__);
+ }
+
rmi4_data->input_dev->name = PLATFORM_DRIVER_NAME;
rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
@@ -2149,6 +2912,10 @@ static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data)
return 0;
err_register_input:
+ if (rmi4_data->support_vkeys) {
+ sysfs_remove_group(vkey_kobj, &vkey_grp);
+ kobject_put(vkey_kobj);
+ }
err_query_device:
synaptics_rmi4_empty_fn_list(rmi4_data);
input_free_device(rmi4_data->input_dev);
@@ -2232,6 +2999,147 @@ err_gpio_irq:
return retval;
}
+static int synaptics_dsx_pinctrl_init(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+
+ /* Get pinctrl if target uses pinctrl */
+ rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent));
+ if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) {
+ retval = PTR_ERR(rmi4_data->ts_pinctrl);
+ dev_dbg(rmi4_data->pdev->dev.parent,
+ "Target does not use pinctrl %d\n", retval);
+ goto err_pinctrl_get;
+ }
+
+ rmi4_data->pinctrl_state_active
+ = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active");
+ if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) {
+ retval = PTR_ERR(rmi4_data->pinctrl_state_active);
+ dev_err(rmi4_data->pdev->dev.parent,
+ "Can not lookup %s pinstate %d\n",
+ PINCTRL_STATE_ACTIVE, retval);
+ goto err_pinctrl_lookup;
+ }
+
+ rmi4_data->pinctrl_state_suspend
+ = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend");
+ if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) {
+ retval = PTR_ERR(rmi4_data->pinctrl_state_suspend);
+ dev_dbg(rmi4_data->pdev->dev.parent,
+ "Can not lookup %s pinstate %d\n",
+ PINCTRL_STATE_SUSPEND, retval);
+ goto err_pinctrl_lookup;
+ }
+
+ rmi4_data->pinctrl_state_release
+ = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_release");
+ if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+ retval = PTR_ERR(rmi4_data->pinctrl_state_release);
+ dev_dbg(rmi4_data->pdev->dev.parent,
+ "Can not lookup %s pinstate %d\n",
+ PINCTRL_STATE_RELEASE, retval);
+ }
+
+ return 0;
+
+err_pinctrl_lookup:
+ devm_pinctrl_put(rmi4_data->ts_pinctrl);
+err_pinctrl_get:
+ rmi4_data->ts_pinctrl = NULL;
+ return retval;
+}
+
+static int synaptics_dsx_gpio_configure(struct synaptics_rmi4_data *rmi4_data,
+ bool on)
+{
+ int retval = 0;
+ const struct synaptics_dsx_board_data *bdata =
+ rmi4_data->hw_if->board_data;
+
+ if (on) {
+ if (gpio_is_valid(bdata->irq_gpio)) {
+ /* configure touchscreen irq gpio */
+ retval = gpio_request(bdata->irq_gpio,
+ "rmi4_irq_gpio");
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "unable to request gpio [%d]\n",
+ bdata->irq_gpio);
+ goto err_irq_gpio_req;
+ }
+ retval = gpio_direction_input(bdata->irq_gpio);
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "unable to set dir for gpio[%d]\n",
+ bdata->irq_gpio);
+ goto err_irq_gpio_dir;
+ }
+ } else {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "irq gpio not provided\n");
+ goto err_irq_gpio_req;
+ }
+
+ if (gpio_is_valid(bdata->reset_gpio)) {
+ /* configure touchscreen reset out gpio */
+ retval = gpio_request(bdata->reset_gpio,
+ "rmi4_reset_gpio");
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "unable to request gpio [%d]\n",
+ bdata->reset_gpio);
+ goto err_irq_gpio_dir;
+ }
+
+ retval = gpio_direction_output(bdata->reset_gpio, 1);
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "unable to set dir for gpio [%d]\n",
+ bdata->reset_gpio);
+ goto err_reset_gpio_dir;
+ }
+
+ gpio_set_value(bdata->reset_gpio, 1);
+ msleep(bdata->reset_delay_ms);
+ }
+
+ return 0;
+ } else {
+ if (bdata->disable_gpios) {
+ if (gpio_is_valid(bdata->irq_gpio))
+ gpio_free(bdata->irq_gpio);
+ if (gpio_is_valid(bdata->reset_gpio)) {
+ /*
+ * This is intended to save leakage current
+ * only. Even if the call(gpio_direction_input)
+ * fails, only leakage current will be more but
+ * functionality will not be affected.
+ */
+ retval = gpio_direction_input(
+ bdata->reset_gpio);
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "unable to set direction for gpio "
+ "[%d]\n", bdata->irq_gpio);
+ }
+ gpio_free(bdata->reset_gpio);
+ }
+ }
+
+ return 0;
+ }
+
+err_reset_gpio_dir:
+ if (gpio_is_valid(bdata->reset_gpio))
+ gpio_free(bdata->reset_gpio);
+err_irq_gpio_dir:
+ if (gpio_is_valid(bdata->irq_gpio))
+ gpio_free(bdata->irq_gpio);
+err_irq_gpio_req:
+ return retval;
+}
+
static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data)
{
unsigned char ii;
@@ -2275,9 +3183,16 @@ static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data)
if (!list_empty(&rmi->support_fn_list)) {
list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F12) {
+ synaptics_rmi4_f12_set_coords(rmi4_data,
+ fhandler);
synaptics_rmi4_f12_set_enables(rmi4_data, 0);
break;
+ } else if (fhandler->fn_number == SYNAPTICS_RMI4_F11) {
+ synaptics_rmi4_f11_set_coords(rmi4_data,
+ fhandler);
+ break;
}
+
}
}
@@ -2419,7 +3334,7 @@ static void synaptics_rmi4_exp_fn_work(struct work_struct *work)
}
/**
-* synaptics_rmi4_new_function()
+* synaptics_rmi4_dsx_new_function()
*
* Called by other expansion Function modules in their module init and
* module exit functions.
@@ -2430,7 +3345,7 @@ static void synaptics_rmi4_exp_fn_work(struct work_struct *work)
* can be inserted or removed dynamically at module init and exit times,
* respectively.
*/
-void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn,
+void synaptics_rmi4_dsx_new_function(struct synaptics_rmi4_exp_fn *exp_fn,
bool insert)
{
struct synaptics_rmi4_exp_fhandler *exp_fhandler;
@@ -2474,7 +3389,64 @@ exit:
return;
}
-EXPORT_SYMBOL(synaptics_rmi4_new_function);
+EXPORT_SYMBOL(synaptics_rmi4_dsx_new_function);
+
+static int synaptics_dsx_regulator_configure(struct synaptics_rmi4_data
+ *rmi4_data)
+{
+ int retval;
+ rmi4_data->regulator_vdd = regulator_get(rmi4_data->pdev->dev.parent,
+ "vdd");
+ if (IS_ERR(rmi4_data->regulator_vdd)) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to get regulator vdd\n",
+ __func__);
+ retval = PTR_ERR(rmi4_data->regulator_vdd);
+ return retval;
+ }
+ rmi4_data->regulator_avdd = regulator_get(rmi4_data->pdev->dev.parent,
+ "avdd");
+ if (IS_ERR(rmi4_data->regulator_avdd)) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to get regulator avdd\n",
+ __func__);
+ retval = PTR_ERR(rmi4_data->regulator_avdd);
+ regulator_put(rmi4_data->regulator_vdd);
+ return retval;
+ }
+
+ return 0;
+};
+
+static int synaptics_dsx_regulator_enable(struct synaptics_rmi4_data
+ *rmi4_data, bool on)
+{
+ int retval;
+
+ if (on) {
+ retval = regulator_enable(rmi4_data->regulator_vdd);
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to enable regulator vdd\n",
+ __func__);
+ return retval;
+ }
+ retval = regulator_enable(rmi4_data->regulator_avdd);
+ if (retval) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to enable regulator avdd\n",
+ __func__);
+ regulator_disable(rmi4_data->regulator_vdd);
+ return retval;
+ }
+ msleep(rmi4_data->hw_if->board_data->power_delay_ms);
+ } else {
+ regulator_disable(rmi4_data->regulator_vdd);
+ regulator_disable(rmi4_data->regulator_avdd);
+ }
+
+ return 0;
+}
/**
* synaptics_rmi4_probe()
@@ -2490,13 +3462,14 @@ EXPORT_SYMBOL(synaptics_rmi4_new_function);
* and creates a work queue for detection of other expansion Function
* modules.
*/
-static int __devinit synaptics_rmi4_probe(struct platform_device *pdev)
+static int synaptics_rmi4_probe(struct platform_device *pdev)
{
- int retval;
+ int retval, len;
unsigned char attr_count;
struct synaptics_rmi4_data *rmi4_data;
const struct synaptics_dsx_hw_interface *hw_if;
const struct synaptics_dsx_board_data *bdata;
+ struct dentry *temp;
hw_if = pdev->dev.platform_data;
if (!hw_if) {
@@ -2522,27 +3495,15 @@ static int __devinit synaptics_rmi4_probe(struct platform_device *pdev)
return -ENOMEM;
}
- if (*bdata->regulator_name != 0x00) {
- rmi4_data->regulator = regulator_get(&pdev->dev,
- bdata->regulator_name);
- if (IS_ERR(rmi4_data->regulator)) {
- dev_err(&pdev->dev,
- "%s: Failed to get regulator\n",
- __func__);
- retval = PTR_ERR(rmi4_data->regulator);
- goto err_regulator;
- }
- regulator_enable(rmi4_data->regulator);
- msleep(bdata->power_delay_ms);
- }
-
rmi4_data->pdev = pdev;
rmi4_data->current_page = MASK_8BIT;
rmi4_data->hw_if = hw_if;
rmi4_data->touch_stopped = false;
rmi4_data->sensor_sleep = false;
rmi4_data->irq_enabled = false;
+ rmi4_data->fw_updating = false;
rmi4_data->fingers_on_2d = false;
+ rmi4_data->update_coords = true;
rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
rmi4_data->reset_device = synaptics_rmi4_reset_device;
@@ -2550,18 +3511,65 @@ static int __devinit synaptics_rmi4_probe(struct platform_device *pdev)
mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
mutex_init(&(rmi4_data->rmi4_reset_mutex));
+ retval = synaptics_dsx_regulator_configure(rmi4_data);
+ if (retval) {
+ dev_err(&pdev->dev,
+ "%s: regulator configuration failed\n", __func__);
+ goto err_regulator_configure;
+ }
+ retval = synaptics_dsx_regulator_enable(rmi4_data, true);
+ if (retval) {
+ dev_err(&pdev->dev,
+ "%s: regulator enable failed\n", __func__);
+ goto err_regulator_enable;
+ }
+
platform_set_drvdata(pdev, rmi4_data);
if (bdata->gpio_config) {
retval = synaptics_rmi4_set_gpio(rmi4_data);
if (retval < 0) {
dev_err(&pdev->dev,
+ "%s: Failed to set up GPIO's\n",
+ __func__);
+ goto err_set_gpio;
+ }
+ } else {
+ retval = synaptics_dsx_pinctrl_init(rmi4_data);
+ if (!retval && rmi4_data->ts_pinctrl) {
+ /*
+ * Pinctrl handle is optional. If pinctrl handle is found
+ * let pins to be configured in active state. If not
+ * found continue further without error.
+ */
+ retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+ rmi4_data->pinctrl_state_active);
+ if (retval < 0) {
+ dev_err(&pdev->dev,
+ "%s: Failed to select %s pinstate %d\n",
+ __func__, PINCTRL_STATE_ACTIVE, retval);
+ }
+ }
+
+ retval = synaptics_dsx_gpio_configure(rmi4_data, true);
+ if (retval < 0) {
+ dev_err(&pdev->dev,
"%s: Failed to set up GPIO's\n",
__func__);
- goto err_set_gpio;
+ goto err_config_gpio;
}
}
+ if (bdata->fw_name) {
+ len = strlen(bdata->fw_name);
+ if (len > SYNA_FW_NAME_MAX_LEN - 1) {
+ dev_err(&pdev->dev, "Invalid firmware name\n");
+ goto err_set_input_dev;
+ }
+
+ strlcpy(rmi4_data->fw_name, bdata->fw_name, len + 1);
+ }
+
retval = synaptics_rmi4_set_input_dev(rmi4_data);
if (retval < 0) {
dev_err(&pdev->dev,
@@ -2570,7 +3578,14 @@ static int __devinit synaptics_rmi4_probe(struct platform_device *pdev)
goto err_set_input_dev;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_FB
+ rmi4_data->fb_notif.notifier_call = fb_notifier_callback;
+
+ retval = fb_register_client(&rmi4_data->fb_notif);
+ if (retval)
+ dev_err(rmi4_data->pdev->dev.parent,
+ "Unable to register fb_notifier: %d\n", retval);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
@@ -2601,6 +3616,25 @@ static int __devinit synaptics_rmi4_probe(struct platform_device *pdev)
&exp_data.work,
msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
+ rmi4_data->dir = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
+ if (rmi4_data->dir == NULL || IS_ERR(rmi4_data->dir)) {
+ retval = rmi4_data->dir ? PTR_ERR(rmi4_data->dir) : -EIO;
+ dev_err(&pdev->dev,
+ "%s: Failed to create debugfs directory, rc = %d\n",
+ __func__, retval);
+ goto err_create_debugfs_dir;
+ }
+
+ temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, rmi4_data->dir,
+ rmi4_data, &debug_suspend_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ retval = temp ? PTR_ERR(temp) : -EIO;
+ dev_err(&pdev->dev,
+ "%s: Failed to create suspend debugfs file, rc = %d\n",
+ __func__, retval);
+ goto err_create_debugfs_file;
+ }
+
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
@@ -2612,6 +3646,9 @@ static int __devinit synaptics_rmi4_probe(struct platform_device *pdev)
}
}
+ synaptics_secure_touch_init(rmi4_data);
+ synaptics_secure_touch_stop(rmi4_data, 1);
+
return retval;
err_sysfs:
@@ -2619,15 +3656,21 @@ err_sysfs:
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
}
-
+err_create_debugfs_file:
+ debugfs_remove_recursive(rmi4_data->dir);
+err_create_debugfs_dir:
cancel_delayed_work_sync(&exp_data.work);
- flush_workqueue(exp_data.workqueue);
- destroy_workqueue(exp_data.workqueue);
-
+ if (exp_data.workqueue != NULL) {
+ flush_workqueue(exp_data.workqueue);
+ destroy_workqueue(exp_data.workqueue);
+ }
synaptics_rmi4_irq_enable(rmi4_data, false);
+ free_irq(rmi4_data->irq, rmi4_data);
err_enable_irq:
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+ fb_unregister_client(&rmi4_data->fb_notif);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&rmi4_data->early_suspend);
#endif
@@ -2652,15 +3695,32 @@ err_set_input_dev:
bdata->power_gpio,
false, 0, 0);
}
+ } else {
+ synaptics_dsx_gpio_configure(rmi4_data, false);
}
-
-err_set_gpio:
- if (rmi4_data->regulator) {
- regulator_disable(rmi4_data->regulator);
- regulator_put(rmi4_data->regulator);
+err_config_gpio:
+ if (rmi4_data->ts_pinctrl) {
+ if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+ devm_pinctrl_put(rmi4_data->ts_pinctrl);
+ rmi4_data->ts_pinctrl = NULL;
+ } else {
+ retval = pinctrl_select_state(
+ rmi4_data->ts_pinctrl,
+ rmi4_data->pinctrl_state_release);
+ if (retval)
+ dev_err(&pdev->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ }
}
-err_regulator:
+err_set_gpio:
+ regulator_disable(rmi4_data->regulator_vdd);
+ regulator_disable(rmi4_data->regulator_avdd);
+err_regulator_enable:
+ regulator_put(rmi4_data->regulator_vdd);
+ regulator_put(rmi4_data->regulator_avdd);
+err_regulator_configure:
kfree(rmi4_data);
return retval;
@@ -2676,25 +3736,34 @@ err_regulator:
* frees the interrupt, unregisters the driver from the input subsystem,
* turns off the power to the sensor, and frees other allocated resources.
*/
-static int __devexit synaptics_rmi4_remove(struct platform_device *pdev)
+static int synaptics_rmi4_remove(struct platform_device *pdev)
{
unsigned char attr_count;
struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev);
const struct synaptics_dsx_board_data *bdata =
rmi4_data->hw_if->board_data;
+ int err;
+
+ if (rmi4_data->support_vkeys) {
+ sysfs_remove_group(vkey_kobj, &vkey_grp);
+ kobject_put(vkey_kobj);
+ }
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
}
+ debugfs_remove_recursive(rmi4_data->dir);
cancel_delayed_work_sync(&exp_data.work);
flush_workqueue(exp_data.workqueue);
destroy_workqueue(exp_data.workqueue);
synaptics_rmi4_irq_enable(rmi4_data, false);
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+ fb_unregister_client(&rmi4_data->fb_notif);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&rmi4_data->early_suspend);
#endif
@@ -2718,11 +3787,32 @@ static int __devexit synaptics_rmi4_remove(struct platform_device *pdev)
bdata->power_gpio,
false, 0, 0);
}
+ } else {
+ synaptics_dsx_gpio_configure(rmi4_data, false);
+ if (rmi4_data->ts_pinctrl) {
+ if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
+ devm_pinctrl_put(rmi4_data->ts_pinctrl);
+ rmi4_data->ts_pinctrl = NULL;
+ } else {
+ err = pinctrl_select_state(
+ rmi4_data->ts_pinctrl,
+ rmi4_data->pinctrl_state_release);
+ if (err)
+ dev_err(&pdev->dev,
+ "Failed to select release pinctrl state %d\n",
+ err);
+ }
+ }
}
- if (rmi4_data->regulator) {
- regulator_disable(rmi4_data->regulator);
- regulator_put(rmi4_data->regulator);
+ if (rmi4_data->regulator_vdd) {
+ regulator_disable(rmi4_data->regulator_vdd);
+ regulator_put(rmi4_data->regulator_vdd);
+ }
+
+ if (rmi4_data->regulator_avdd) {
+ regulator_disable(rmi4_data->regulator_avdd);
+ regulator_put(rmi4_data->regulator_avdd);
}
kfree(rmi4_data);
@@ -2730,6 +3820,126 @@ static int __devexit synaptics_rmi4_remove(struct platform_device *pdev)
return 0;
}
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(self, struct synaptics_rmi4_data, fb_notif);
+
+ if (evdata && evdata->data && rmi4_data) {
+ if (event == FB_EARLY_EVENT_BLANK)
+ synaptics_secure_touch_stop(rmi4_data, 0);
+ else if (event == FB_EVENT_BLANK) {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK)
+ synaptics_rmi4_resume(
+ &(rmi4_data->input_dev->dev));
+ else if (*blank == FB_BLANK_POWERDOWN)
+ synaptics_rmi4_suspend(
+ &(rmi4_data->input_dev->dev));
+ }
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ /**
+ * synaptics_rmi4_early_suspend()
+ *
+ * Called by the kernel during the early suspend phase when the system
+ * enters suspend.
+ *
+ * This function calls synaptics_rmi4_sensor_sleep() to stop finger
+ * data acquisition and put the sensor to sleep.
+ */
+static void synaptics_rmi4_early_suspend(struct early_suspend *h)
+{
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(h, struct synaptics_rmi4_data,
+ early_suspend);
+
+ if (rmi4_data->stay_awake) {
+ rmi4_data->staying_awake = true;
+ return;
+ } else {
+ rmi4_data->staying_awake = false;
+ }
+
+ synaptics_secure_touch_stop(rmi4_data, 0);
+
+ rmi4_data->touch_stopped = true;
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+ synaptics_rmi4_sensor_sleep(rmi4_data);
+ synaptics_rmi4_free_fingers(rmi4_data);
+
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link)
+ if (exp_fhandler->exp_fn->early_suspend != NULL)
+ exp_fhandler->exp_fn->early_suspend(rmi4_data);
+ }
+ mutex_unlock(&exp_data.mutex);
+
+ if (rmi4_data->full_pm_cycle)
+ synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_late_resume()
+ *
+ * Called by the kernel during the late resume phase when the system
+ * wakes up from suspend.
+ *
+ * This function goes through the sensor wake process if the system wakes
+ * up from early suspend (without going into suspend).
+ */
+static void synaptics_rmi4_late_resume(struct early_suspend *h)
+{
+ int retval;
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+ struct synaptics_rmi4_data *rmi4_data =
+ container_of(h, struct synaptics_rmi4_data,
+ early_suspend);
+
+ if (rmi4_data->staying_awake)
+ return;
+
+ synaptics_secure_touch_stop(rmi4_data, 0);
+
+ if (rmi4_data->full_pm_cycle)
+ synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+
+ if (rmi4_data->sensor_sleep == true) {
+ synaptics_rmi4_sensor_wake(rmi4_data);
+ synaptics_rmi4_irq_enable(rmi4_data, true);
+ retval = synaptics_rmi4_reinit_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to reinit device\n",
+ __func__);
+ }
+ }
+
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link)
+ if (exp_fhandler->exp_fn->late_resume != NULL)
+ exp_fhandler->exp_fn->late_resume(rmi4_data);
+ }
+ mutex_unlock(&exp_data.mutex);
+
+ rmi4_data->touch_stopped = false;
+
+ return;
+}
+#endif
+
#ifdef CONFIG_PM
/**
* synaptics_rmi4_sensor_sleep()
@@ -2820,134 +4030,103 @@ static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data)
return;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
/**
- * synaptics_rmi4_early_suspend()
+ * synaptics_rmi4_suspend()
*
- * Called by the kernel during the early suspend phase when the system
+ * Called by the kernel during the suspend phase when the system
* enters suspend.
*
- * This function calls synaptics_rmi4_sensor_sleep() to stop finger
- * data acquisition and put the sensor to sleep.
+ * This function stops finger data acquisition and puts the sensor to
+ * sleep (if not already done so during the early suspend phase),
+ * disables the interrupt, and turns off the power to the sensor.
*/
-static void synaptics_rmi4_early_suspend(struct early_suspend *h)
+static int synaptics_rmi4_suspend(struct device *dev)
{
struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_data *rmi4_data =
- container_of(h, struct synaptics_rmi4_data,
- early_suspend);
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_dsx_board_data *bdata =
+ rmi4_data->hw_if->board_data;
+ int retval;
if (rmi4_data->stay_awake) {
rmi4_data->staying_awake = true;
- return;
+ return 0;
} else {
rmi4_data->staying_awake = false;
}
- rmi4_data->touch_stopped = true;
- synaptics_rmi4_irq_enable(rmi4_data, false);
- synaptics_rmi4_sensor_sleep(rmi4_data);
- synaptics_rmi4_free_fingers(rmi4_data);
-
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->early_suspend != NULL)
- exp_fhandler->exp_fn->early_suspend(rmi4_data);
+ if (rmi4_data->suspended) {
+ dev_info(dev, "Already in suspend state\n");
+ return 0;
}
- mutex_unlock(&exp_data.mutex);
-
- if (rmi4_data->full_pm_cycle)
- synaptics_rmi4_suspend(&(rmi4_data->input_dev->dev));
- return;
-}
+ synaptics_secure_touch_stop(rmi4_data, 1);
- /**
- * synaptics_rmi4_late_resume()
- *
- * Called by the kernel during the late resume phase when the system
- * wakes up from suspend.
- *
- * This function goes through the sensor wake process if the system wakes
- * up from early suspend (without going into suspend).
- */
-static void synaptics_rmi4_late_resume(struct early_suspend *h)
-{
- int retval;
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_data *rmi4_data =
- container_of(h, struct synaptics_rmi4_data,
- early_suspend);
-
- if (rmi4_data->staying_awake)
- return;
+ if (!rmi4_data->fw_updating) {
+ if (!rmi4_data->sensor_sleep) {
+ rmi4_data->touch_stopped = true;
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+ synaptics_rmi4_sensor_sleep(rmi4_data);
+ synaptics_rmi4_free_fingers(rmi4_data);
+ }
- if (rmi4_data->full_pm_cycle)
- synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link)
+ if (exp_fhandler->exp_fn->suspend != NULL)
+ exp_fhandler->exp_fn->suspend(rmi4_data);
+ }
+ mutex_unlock(&exp_data.mutex);
- if (rmi4_data->sensor_sleep == true) {
- synaptics_rmi4_sensor_wake(rmi4_data);
- synaptics_rmi4_irq_enable(rmi4_data, true);
- retval = synaptics_rmi4_reinit_device(rmi4_data);
+ retval = synaptics_dsx_regulator_enable(rmi4_data, false);
if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to reinit device\n",
- __func__);
+ dev_err(dev, "failed to enter low power mode\n");
+ goto err_lpm_regulator;
}
+ } else {
+ dev_err(dev,
+ "Firmware updating, cannot go into suspend mode\n");
+ return 0;
}
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->late_resume != NULL)
- exp_fhandler->exp_fn->late_resume(rmi4_data);
- }
- mutex_unlock(&exp_data.mutex);
+ if (bdata->disable_gpios) {
+ if (rmi4_data->ts_pinctrl) {
+ retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+ rmi4_data->pinctrl_state_suspend);
+ if (retval < 0) {
+ dev_err(dev, "Cannot get idle pinctrl state\n");
+ goto err_pinctrl_select_suspend;
+ }
+ }
- rmi4_data->touch_stopped = false;
+ retval = synaptics_dsx_gpio_configure(rmi4_data, false);
+ if (retval < 0) {
+ dev_err(dev, "failed to put gpios in suspend state\n");
+ goto err_gpio_configure;
+ }
+ }
- return;
-}
-#endif
+ rmi4_data->suspended = true;
- /**
- * synaptics_rmi4_suspend()
- *
- * Called by the kernel during the suspend phase when the system
- * enters suspend.
- *
- * This function stops finger data acquisition and puts the sensor to
- * sleep (if not already done so during the early suspend phase),
- * disables the interrupt, and turns off the power to the sensor.
- */
-static int synaptics_rmi4_suspend(struct device *dev)
-{
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- if (rmi4_data->staying_awake)
- return 0;
+ return 0;
- if (!rmi4_data->sensor_sleep) {
- rmi4_data->touch_stopped = true;
- synaptics_rmi4_irq_enable(rmi4_data, false);
- synaptics_rmi4_sensor_sleep(rmi4_data);
- synaptics_rmi4_free_fingers(rmi4_data);
+err_gpio_configure:
+ if (rmi4_data->ts_pinctrl) {
+ retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+ rmi4_data->pinctrl_state_active);
+ if (retval < 0)
+ dev_err(dev, "Cannot get default pinctrl state\n");
}
-
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->suspend != NULL)
- exp_fhandler->exp_fn->suspend(rmi4_data);
+err_pinctrl_select_suspend:
+ synaptics_dsx_regulator_enable(rmi4_data, true);
+err_lpm_regulator:
+ if (rmi4_data->sensor_sleep) {
+ synaptics_rmi4_sensor_wake(rmi4_data);
+ synaptics_rmi4_irq_enable(rmi4_data, true);
+ rmi4_data->touch_stopped = false;
}
- mutex_unlock(&exp_data.mutex);
-
- if (rmi4_data->regulator)
- regulator_disable(rmi4_data->regulator);
- return 0;
+ return retval;
}
/**
@@ -2971,14 +4150,27 @@ static int synaptics_rmi4_resume(struct device *dev)
if (rmi4_data->staying_awake)
return 0;
- if (rmi4_data->regulator) {
- regulator_enable(rmi4_data->regulator);
- msleep(bdata->reset_delay_ms);
- rmi4_data->current_page = MASK_8BIT;
+ if (!rmi4_data->suspended)
+ return 0;
+
+ synaptics_secure_touch_stop(rmi4_data, 1);
+
+ synaptics_dsx_regulator_enable(rmi4_data, true);
+
+ if (bdata->disable_gpios) {
+ if (rmi4_data->ts_pinctrl) {
+ retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
+ rmi4_data->pinctrl_state_active);
+ if (retval < 0)
+ dev_err(dev, "Cannot get default pinctrl state\n");
+ }
+
+ retval = synaptics_dsx_gpio_configure(rmi4_data, true);
+ if (retval < 0)
+ dev_err(dev, "Failed to put gpios in active state\n");
}
synaptics_rmi4_sensor_wake(rmi4_data);
- synaptics_rmi4_irq_enable(rmi4_data, true);
retval = synaptics_rmi4_reinit_device(rmi4_data);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
@@ -2996,14 +4188,31 @@ static int synaptics_rmi4_resume(struct device *dev)
mutex_unlock(&exp_data.mutex);
rmi4_data->touch_stopped = false;
+ rmi4_data->suspended = false;
+
+ synaptics_rmi4_irq_enable(rmi4_data, true);
return 0;
}
static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
.suspend = synaptics_rmi4_suspend,
.resume = synaptics_rmi4_resume,
+#endif
};
+#else
+static int synaptics_rmi4_suspend(struct device *dev)
+{
+ dev_err(dev, "PM not supported\n");
+ return -EINVAL;
+}
+
+static int synaptics_rmi4_resume(struct device *dev)
+{
+ dev_err(dev, "PM not supported\n");
+ return -EINVAL;
+}
#endif
static struct platform_driver synaptics_rmi4_driver = {
@@ -3015,7 +4224,7 @@ static struct platform_driver synaptics_rmi4_driver = {
#endif
},
.probe = synaptics_rmi4_probe,
- .remove = __devexit_p(synaptics_rmi4_remove),
+ .remove = synaptics_rmi4_remove,
};
/**
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h
index 1692c3191ba6..0483fa4f6dd1 100755..100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h
@@ -5,6 +5,7 @@
*
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright (c) 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
@@ -25,9 +26,19 @@
#define SYNAPTICS_DSX_DRIVER_VERSION 0x2001
#include <linux/version.h>
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/debugfs.h>
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif
+#if defined(CONFIG_SECURE_TOUCH)
+#include <linux/completion.h>
+#include <linux/atomic.h>
+#include <linux/clk.h>
+#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
#define KERNEL_ABOVE_2_6_38
@@ -61,6 +72,9 @@
#define SYNAPTICS_RMI4_PRODUCT_ID_SIZE 10
#define SYNAPTICS_RMI4_BUILD_ID_SIZE 3
+#define F01_PACKAGE_ID_OFFSET 17
+#define PACKAGE_ID_SIZE 4
+
#define F12_FINGERS_TO_SUPPORT 10
#define F12_NO_OBJECT_STATUS 0x00
#define F12_FINGER_STATUS 0x01
@@ -82,6 +96,12 @@
#define MASK_2BIT 0x03
#define MASK_1BIT 0x01
+#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
+#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
+#define PINCTRL_STATE_RELEASE "pmx_ts_release"
+
+#define SYNA_FW_NAME_MAX_LEN 50
+
enum exp_fn {
RMI_DEV = 0,
RMI_F54,
@@ -92,7 +112,7 @@ enum exp_fn {
};
struct synaptics_dsx_hw_interface {
- const struct synaptics_dsx_board_data *board_data;
+ struct synaptics_dsx_board_data *board_data;
const struct synaptics_dsx_bus_access *bus_access;
};
@@ -187,6 +207,8 @@ struct synaptics_rmi4_device_info {
unsigned char product_id_string[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned char build_id[SYNAPTICS_RMI4_BUILD_ID_SIZE];
struct list_head support_fn_list;
+ unsigned int package_id;
+ unsigned int package_id_rev;
};
/*
@@ -195,7 +217,8 @@ struct synaptics_rmi4_device_info {
* @input_dev: pointer to associated input device
* @hw_if: pointer to hardware interface data
* @rmi4_mod_info: device information
- * @regulator: pointer to associated regulator
+ * @regulator_vdd: pointer to associated vdd regulator
+ * @regulator_add: pointer to associated avdd regulator
* @rmi4_io_ctrl_mutex: mutex for i2c i/o control
* @early_suspend: instance to support early suspend power management
* @current_page: current page in sensor to acess
@@ -220,12 +243,16 @@ struct synaptics_rmi4_data {
struct input_dev *input_dev;
const struct synaptics_dsx_hw_interface *hw_if;
struct synaptics_rmi4_device_info rmi4_mod_info;
- struct regulator *regulator;
+ struct regulator *regulator_vdd;
+ struct regulator *regulator_avdd;
struct mutex rmi4_reset_mutex;
struct mutex rmi4_io_ctrl_mutex;
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+ struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
+ struct dentry *dir;
unsigned char current_page;
unsigned char button_0d_enabled;
unsigned char full_pm_cycle;
@@ -253,8 +280,27 @@ struct synaptics_rmi4_data {
bool sensor_sleep;
bool stay_awake;
bool staying_awake;
+ bool fw_updating;
+ bool support_vkeys;
+ bool update_coords;
int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
int (*reset_device)(struct synaptics_rmi4_data *rmi4_data);
+
+ struct pinctrl *ts_pinctrl;
+ struct pinctrl_state *pinctrl_state_active;
+ struct pinctrl_state *pinctrl_state_suspend;
+ struct pinctrl_state *pinctrl_state_release;
+ char fw_name[SYNA_FW_NAME_MAX_LEN];
+ bool suspended;
+#if defined(CONFIG_SECURE_TOUCH)
+ atomic_t st_enabled;
+ atomic_t st_pending_irqs;
+ bool st_initialized;
+ struct completion st_powerdown;
+ struct completion st_irq_processed;
+ struct clk *core_clk;
+ struct clk *iface_clk;
+#endif
};
struct synaptics_dsx_bus_access {
@@ -263,6 +309,10 @@ struct synaptics_dsx_bus_access {
unsigned char *data, unsigned short length);
int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
unsigned char *data, unsigned short length);
+#if defined(CONFIG_SECURE_TOUCH)
+ int (*get)(struct synaptics_rmi4_data *rmi4_data);
+ void (*put)(struct synaptics_rmi4_data *rmi4_data);
+#endif
};
struct synaptics_rmi4_exp_fn {
@@ -283,10 +333,14 @@ int synaptics_rmi4_bus_init(void);
void synaptics_rmi4_bus_exit(void);
-void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module,
+void synaptics_rmi4_dsx_new_function(struct synaptics_rmi4_exp_fn *exp_fn_mod,
bool insert);
-int synaptics_fw_updater(unsigned char *fw_data);
+int synaptics_dsx_fw_updater(unsigned char *fw_data);
+
+int synaptics_dsx_get_dt_coords(struct device *dev, char *name,
+ struct synaptics_dsx_board_data *pdata,
+ struct device_node *node);
static inline int synaptics_rmi4_reg_read(
struct synaptics_rmi4_data *rmi4_data,
@@ -306,13 +360,16 @@ static inline int synaptics_rmi4_reg_write(
return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
}
-static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
- struct device_attribute *attr, char *buf)
+#if defined(CONFIG_SECURE_TOUCH)
+static inline int synaptics_rmi4_bus_get(struct synaptics_rmi4_data *rmi4_data)
{
- dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
- __func__, attr->attr.name);
- return -EPERM;
+ return rmi4_data->hw_if->bus_access->get(rmi4_data);
}
+static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data)
+{
+ rmi4_data->hw_if->bus_access->put(rmi4_data);
+}
+#endif
static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -332,5 +389,4 @@ static inline void hstoba(unsigned char *dest, unsigned short src)
dest[0] = src % 0x100;
dest[1] = src / 0x100;
}
-
#endif
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 268ca250c7ca..a32222932ee1 100755..100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -24,11 +24,9 @@
#include <linux/input.h>
#include <linux/firmware.h>
#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx.h>
+#include <linux/input/synaptics_dsx_v2.h>
#include "synaptics_dsx_core.h"
-#define FW_IMAGE_NAME "synaptics/startup_fw_update.img"
-#define DO_STARTUP_FW_UPDATE
#define STARTUP_FW_UPDATE_DELAY_MS 1000 /* ms */
#define FORCE_UPDATE false
#define DO_LOCKDOWN false
@@ -99,6 +97,9 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count);
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
@@ -111,6 +112,9 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev,
static ssize_t fwu_sysfs_config_area_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t fwu_sysfs_image_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
static ssize_t fwu_sysfs_image_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
@@ -135,6 +139,12 @@ static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
struct device_attribute *attr, char *buf);
+static ssize_t fwu_sysfs_config_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t fwu_sysfs_package_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
enum bl_version {
V5 = 5,
V6 = 6,
@@ -268,7 +278,6 @@ struct synaptics_rmi4_fwu_handle {
const unsigned char *firmware_data;
const unsigned char *config_data;
const unsigned char *lockdown_data;
- struct workqueue_struct *fwu_workqueue;
struct delayed_work fwu_work;
struct synaptics_rmi4_fn_desc f34_fd;
struct synaptics_rmi4_data *rmi4_data;
@@ -277,31 +286,35 @@ struct synaptics_rmi4_fwu_handle {
static struct bin_attribute dev_attr_data = {
.attr = {
.name = "data",
- .mode = (S_IRUGO | S_IWUGO),
+ .mode = (S_IRUGO | S_IWUSR),
},
.size = 0,
.read = fwu_sysfs_show_image,
.write = fwu_sysfs_store_image,
};
+
static struct device_attribute attrs[] = {
- __ATTR(doreflash, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(force_update_fw, S_IWUSR | S_IWGRP,
+ NULL,
+ fwu_sysfs_force_reflash_store),
+ __ATTR(update_fw, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_do_reflash_store),
- __ATTR(writeconfig, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(writeconfig, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_write_config_store),
- __ATTR(readconfig, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(readconfig, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_read_config_store),
- __ATTR(configarea, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(configarea, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_config_area_store),
- __ATTR(imagename, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(fw_name, S_IRUGO | S_IWUSR | S_IWGRP,
+ fwu_sysfs_image_name_show,
fwu_sysfs_image_name_store),
- __ATTR(imagesize, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(imagesize, S_IWUSR | S_IWGRP,
+ NULL,
fwu_sysfs_image_size_store),
__ATTR(blocksize, S_IRUGO,
fwu_sysfs_block_size_show,
@@ -321,11 +334,17 @@ static struct device_attribute attrs[] = {
__ATTR(dispconfigblockcount, S_IRUGO,
fwu_sysfs_disp_config_block_count_show,
synaptics_rmi4_store_error),
+ __ATTR(config_id, S_IRUGO,
+ fwu_sysfs_config_id_show,
+ synaptics_rmi4_store_error),
+ __ATTR(package_id, S_IRUGO,
+ fwu_sysfs_package_id_show,
+ synaptics_rmi4_store_error),
};
static struct synaptics_rmi4_fwu_handle *fwu;
-DECLARE_COMPLETION(fwu_remove_complete);
+DECLARE_COMPLETION(fwu_dsx_remove_complete);
static unsigned int extract_uint_le(const unsigned char *ptr)
{
@@ -644,6 +663,14 @@ static enum flash_area fwu_go_nogo(struct image_header_data *header)
strptr += 2;
firmware_id = kzalloc(MAX_FIRMWARE_ID_LEN, GFP_KERNEL);
+ if (!firmware_id) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to alloc mem for firmware id\n",
+ __func__);
+ flash_area = NONE;
+ goto exit;
+ }
+
while (strptr[index] >= '0' && strptr[index] <= '9') {
firmware_id[index] = strptr[index];
index++;
@@ -811,6 +838,27 @@ static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt,
unsigned char block_offset[] = {0, 0};
unsigned short block_num;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ unsigned int progress;
+ unsigned char command_str[10];
+
+ switch (command) {
+ case CMD_WRITE_CONFIG_BLOCK:
+ progress = 10;
+ strlcpy(command_str, "config", 10);
+ break;
+ case CMD_WRITE_FW_BLOCK:
+ progress = 100;
+ strlcpy(command_str, "firmware", 10);
+ break;
+ case CMD_WRITE_LOCKDOWN_BLOCK:
+ progress = 1;
+ strlcpy(command_str, "lockdown", 10);
+ break;
+ default:
+ progress = 1;
+ strlcpy(command_str, "unknown", 10);
+ break;
+ }
block_offset[1] |= (fwu->config_area << 5);
@@ -826,6 +874,11 @@ static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt,
}
for (block_num = 0; block_num < block_cnt; block_num++) {
+ if (block_num % progress == 0)
+ dev_info(rmi4_data->pdev->dev.parent,
+ "%s: update %s %3d / %3d\n",
+ __func__, command_str, block_num, block_cnt);
+
retval = synaptics_rmi4_reg_write(rmi4_data,
fwu->f34_fd.data_base_addr + fwu->blk_data_off,
block_ptr,
@@ -856,6 +909,9 @@ static int fwu_write_blocks(unsigned char *block_ptr, unsigned short block_cnt,
block_ptr += fwu->block_size;
}
+ dev_info(rmi4_data->pdev->dev.parent,
+ "updated %d/%d blocks\n", block_num, block_cnt);
+
return 0;
}
@@ -1205,6 +1261,13 @@ static int fwu_do_read_config(void)
kfree(fwu->read_config_buf);
fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL);
+ if (!fwu->read_config_buf) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to alloc memory for config buffer\n",
+ __func__);
+ retval = -ENOMEM;
+ goto exit;
+ }
block_offset[1] |= (fwu->config_area << 5);
@@ -1316,7 +1379,6 @@ static int fwu_start_reflash(void)
if (fwu->ext_data_source) {
fw_image = fwu->ext_data_source;
} else {
- strncpy(fwu->image_name, FW_IMAGE_NAME, MAX_IMAGE_NAME_LEN);
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Requesting firmware image %s\n",
__func__, fwu->image_name);
@@ -1327,12 +1389,12 @@ static int fwu_start_reflash(void)
dev_err(rmi4_data->pdev->dev.parent,
"%s: Firmware image %s not available\n",
__func__, fwu->image_name);
- retval = -EINVAL;
- goto exit;
+ rmi4_data->stay_awake = false;
+ return retval;
}
dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Firmware image size = %d\n",
+ "%s: Firmware image size = %zu\n",
__func__, fw_entry->size);
fw_image = fw_entry->data;
@@ -1417,7 +1479,7 @@ exit:
return retval;
}
-int synaptics_fw_updater(unsigned char *fw_data)
+int synaptics_dsx_fw_updater(unsigned char *fw_data)
{
int retval;
@@ -1427,21 +1489,24 @@ int synaptics_fw_updater(unsigned char *fw_data)
if (!fwu->initialized)
return -ENODEV;
+ fwu->rmi4_data->fw_updating = true;
+ if (fwu->rmi4_data->suspended == true) {
+ fwu->rmi4_data->fw_updating = false;
+ dev_err(fwu->rmi4_data->pdev->dev.parent,
+ "Cannot start fw upgrade: Device is in suspend\n");
+ return -EBUSY;
+ }
+
fwu->ext_data_source = fw_data;
fwu->config_area = UI_CONFIG_AREA;
retval = fwu_start_reflash();
- return retval;
-}
-EXPORT_SYMBOL(synaptics_fw_updater);
-
-static void fwu_startup_fw_update_work(struct work_struct *work)
-{
- synaptics_fw_updater(NULL);
+ fwu->rmi4_data->fw_updating = false;
- return;
+ return retval;
}
+EXPORT_SYMBOL(synaptics_dsx_fw_updater);
static ssize_t fwu_sysfs_show_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
@@ -1451,7 +1516,7 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file,
if (count < fwu->config_size) {
dev_err(rmi4_data->pdev->dev.parent,
- "%s: Not enough space (%d bytes) in buffer\n",
+ "%s: Not enough space (%zu bytes) in buffer\n",
__func__, count);
return -EINVAL;
}
@@ -1474,6 +1539,44 @@ static ssize_t fwu_sysfs_store_image(struct file *data_file,
return count;
}
+static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+ if (sscanf(buf, "%u", &input) != 1) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (input != 1) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (LOCKDOWN)
+ fwu->do_lockdown = true;
+
+ fwu->force_update = true;
+ retval = synaptics_dsx_fw_updater(fwu->ext_data_source);
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to do reflash\n",
+ __func__);
+ goto exit;
+ }
+
+ retval = count;
+exit:
+ kfree(fwu->ext_data_source);
+ fwu->ext_data_source = NULL;
+ fwu->force_update = FORCE_UPDATE;
+ fwu->do_lockdown = DO_LOCKDOWN;
+ return retval;
+}
+
static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
@@ -1499,7 +1602,7 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
if (input == FORCE)
fwu->force_update = true;
- retval = synaptics_fw_updater(fwu->ext_data_source);
+ retval = synaptics_dsx_fw_updater(fwu->ext_data_source);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to do reflash\n",
@@ -1589,10 +1692,21 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
return count;
}
+static ssize_t fwu_sysfs_image_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (strnlen(fwu->rmi4_data->fw_name, SYNA_FW_NAME_MAX_LEN) > 0)
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ fwu->rmi4_data->fw_name);
+ else
+ return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+}
+
static ssize_t fwu_sysfs_image_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- memcpy(fwu->image_name, buf, count);
+ if (sscanf(buf, "%s", fwu->image_name) != 1)
+ return -EINVAL;
return count;
}
@@ -1659,6 +1773,54 @@ static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", fwu->disp_config_block_count);
}
+static ssize_t fwu_sysfs_config_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ unsigned char config_id[4];
+ int retval;
+
+ /* device config id */
+ retval = synaptics_rmi4_reg_read(rmi4_data,
+ fwu->f34_fd.ctrl_base_addr,
+ config_id,
+ sizeof(config_id));
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to read device config ID\n",
+ __func__);
+ return retval;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
+ config_id[0], config_id[1], config_id[2], config_id[3]);
+}
+
+static ssize_t fwu_sysfs_package_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ unsigned char package_id[PACKAGE_ID_SIZE];
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+ /* read device package id */
+ retval = synaptics_rmi4_reg_read(rmi4_data,
+ rmi4_data->f01_query_base_addr + F01_PACKAGE_ID_OFFSET,
+ package_id,
+ sizeof(package_id));
+
+ if (retval < 0) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "%s: Failed to read device package ID\n",
+ __func__);
+ return retval;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%d rev %d\n",
+ (package_id[1] << 8) | package_id[0],
+ (package_id[3] << 8) | package_id[2]);
+}
+
static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
unsigned char intr_mask)
{
@@ -1686,14 +1848,7 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
goto exit;
}
- fwu->image_name = kzalloc(MAX_IMAGE_NAME_LEN, GFP_KERNEL);
- if (!fwu->image_name) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for image name\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_fwu;
- }
+ fwu->image_name = rmi4_data->fw_name;
fwu->rmi4_data = rmi4_data;
@@ -1710,12 +1865,12 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
"%s: Reflash for LTS not currently supported\n",
__func__);
retval = -ENODEV;
- goto exit_free_mem;
+ goto exit_free_fwu;
}
retval = fwu_scan_pdt();
if (retval < 0)
- goto exit_free_mem;
+ goto exit_free_fwu;
fwu->productinfo1 = rmi4_data->rmi4_mod_info.product_info[0];
fwu->productinfo2 = rmi4_data->rmi4_mod_info.product_info[1];
@@ -1732,7 +1887,7 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
retval = fwu_read_f34_queries();
if (retval < 0)
- goto exit_free_mem;
+ goto exit_free_fwu;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = DO_LOCKDOWN;
@@ -1744,7 +1899,7 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to create sysfs bin file\n",
__func__);
- goto exit_free_mem;
+ goto exit_free_fwu;
}
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
@@ -1759,14 +1914,6 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
}
}
-#ifdef DO_STARTUP_FW_UPDATE
- fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue");
- INIT_DELAYED_WORK(&fwu->fwu_work, fwu_startup_fw_update_work);
- queue_delayed_work(fwu->fwu_workqueue,
- &fwu->fwu_work,
- msecs_to_jiffies(STARTUP_FW_UPDATE_DELAY_MS));
-#endif
-
return 0;
exit_remove_attrs:
@@ -1777,9 +1924,6 @@ exit_remove_attrs:
sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
-exit_free_mem:
- kfree(fwu->image_name);
-
exit_free_fwu:
kfree(fwu);
fwu = NULL;
@@ -1803,12 +1947,11 @@ static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
kfree(fwu->read_config_buf);
- kfree(fwu->image_name);
kfree(fwu);
fwu = NULL;
exit:
- complete(&fwu_remove_complete);
+ complete(&fwu_dsx_remove_complete);
return;
}
@@ -1828,16 +1971,16 @@ static struct synaptics_rmi4_exp_fn fwu_module = {
static int __init rmi4_fw_update_module_init(void)
{
- synaptics_rmi4_new_function(&fwu_module, true);
+ synaptics_rmi4_dsx_new_function(&fwu_module, true);
return 0;
}
static void __exit rmi4_fw_update_module_exit(void)
{
- synaptics_rmi4_new_function(&fwu_module, false);
+ synaptics_rmi4_dsx_new_function(&fwu_module, false);
- wait_for_completion(&fwu_remove_complete);
+ wait_for_completion(&fwu_dsx_remove_complete);
return;
}
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
index 8e7abec6318e..f08737945b56 100755
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
@@ -1,6 +1,11 @@
/*
* Synaptics DSX touchscreen driver
*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Linux foundation chooses to take subject only to the GPLv2 license terms,
+ * and distributes only under these terms.
+ *
* Copyright (C) 2012 Synaptics Incorporated
*
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
@@ -24,10 +29,17 @@
#include <linux/input.h>
#include <linux/types.h>
#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx.h>
+#include <linux/input/synaptics_dsx_v2.h>
#include "synaptics_dsx_core.h"
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#if defined(CONFIG_SECURE_TOUCH)
+#include <linux/pm_runtime.h>
+#endif
#define SYN_I2C_RETRY_TIMES 10
+#define RESET_DELAY 100
+#define DSX_COORDS_ARR_SIZE 4
static int synaptics_rmi4_i2c_set_page(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr)
@@ -168,10 +180,70 @@ exit:
return retval;
}
+#if defined(CONFIG_SECURE_TOUCH)
+static int synaptics_rmi4_clk_prepare_enable(
+ struct synaptics_rmi4_data *rmi4_data)
+{
+ int ret;
+ ret = clk_prepare_enable(rmi4_data->iface_clk);
+ if (ret) {
+ dev_err(rmi4_data->pdev->dev.parent,
+ "error on clk_prepare_enable(iface_clk):%d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(rmi4_data->core_clk);
+ if (ret) {
+ clk_disable_unprepare(rmi4_data->iface_clk);
+ dev_err(rmi4_data->pdev->dev.parent,
+ "error clk_prepare_enable(core_clk):%d\n", ret);
+ }
+ return ret;
+}
+
+static void synaptics_rmi4_clk_disable_unprepare(
+ struct synaptics_rmi4_data *rmi4_data)
+{
+ clk_disable_unprepare(rmi4_data->core_clk);
+ clk_disable_unprepare(rmi4_data->iface_clk);
+}
+
+static int synaptics_rmi4_i2c_get(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
+
+ mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+ retval = pm_runtime_get_sync(i2c->adapter->dev.parent);
+ if (retval >= 0) {
+ retval = synaptics_rmi4_clk_prepare_enable(rmi4_data);
+ if (retval)
+ pm_runtime_put_sync(i2c->adapter->dev.parent);
+ }
+ mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
+
+ return retval;
+}
+
+static void synaptics_rmi4_i2c_put(struct synaptics_rmi4_data *rmi4_data)
+{
+ struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
+
+ mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
+ synaptics_rmi4_clk_disable_unprepare(rmi4_data);
+ pm_runtime_put_sync(i2c->adapter->dev.parent);
+ mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
+}
+#endif
+
static struct synaptics_dsx_bus_access bus_access = {
.type = BUS_I2C,
.read = synaptics_rmi4_i2c_read,
.write = synaptics_rmi4_i2c_write,
+#if defined(CONFIG_SECURE_TOUCH)
+ .get = synaptics_rmi4_i2c_get,
+ .put = synaptics_rmi4_i2c_put,
+#endif
};
static struct synaptics_dsx_hw_interface hw_if;
@@ -184,11 +256,154 @@ static void synaptics_rmi4_i2c_dev_release(struct device *dev)
return;
}
+#ifdef CONFIG_OF
+int synaptics_dsx_get_dt_coords(struct device *dev, char *name,
+ struct synaptics_dsx_board_data *pdata,
+ struct device_node *node)
+{
+ u32 coords[DSX_COORDS_ARR_SIZE];
+ struct property *prop;
+ struct device_node *np = (node == NULL) ? (dev->of_node) : (node);
+ int coords_size, rc;
+
+ prop = of_find_property(np, name, NULL);
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+
+ coords_size = prop->length / sizeof(u32);
+ if (coords_size != DSX_COORDS_ARR_SIZE) {
+ dev_err(dev, "invalid %s\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(np, name, coords, coords_size);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read %s\n", name);
+ return rc;
+ }
+
+ if (strcmp(name, "synaptics,panel-coords") == 0) {
+ pdata->panel_minx = coords[0];
+ pdata->panel_miny = coords[1];
+ pdata->panel_maxx = coords[2];
+ pdata->panel_maxy = coords[3];
+ } else if (strcmp(name, "synaptics,display-coords") == 0) {
+ pdata->disp_minx = coords[0];
+ pdata->disp_miny = coords[1];
+ pdata->disp_maxx = coords[2];
+ pdata->disp_maxy = coords[3];
+ } else {
+ dev_err(dev, "unsupported property %s\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int synaptics_dsx_parse_dt(struct device *dev,
+ struct synaptics_dsx_board_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->x_flip = of_property_read_bool(np, "synaptics,x-flip");
+ rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
+
+ rmi4_pdata->disable_gpios = of_property_read_bool(np,
+ "synaptics,disable-gpios");
+
+ rmi4_pdata->reset_delay_ms = RESET_DELAY;
+ rc = of_property_read_u32(np, "synaptics,reset-delay-ms", &temp_val);
+ if (!rc)
+ rmi4_pdata->reset_delay_ms = temp_val;
+ else if (rc != -EINVAL) {
+ dev_err(dev, "Unable to read reset delay\n");
+ return rc;
+ }
+
+ rmi4_pdata->fw_name = "PRXXX_fw.img";
+ rc = of_property_read_string(np, "synaptics,fw-name",
+ &rmi4_pdata->fw_name);
+ if (rc && (rc != -EINVAL)) {
+ dev_err(dev, "Unable to read fw name\n");
+ return rc;
+ }
+
+ /* 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);
+
+ rc = synaptics_dsx_get_dt_coords(dev, "synaptics,display-coords",
+ rmi4_pdata, NULL);
+ if (rc && (rc != -EINVAL))
+ return rc;
+
+ rc = synaptics_dsx_get_dt_coords(dev, "synaptics,panel-coords",
+ rmi4_pdata, NULL);
+ if (rc && (rc != -EINVAL))
+ return rc;
+
+ rmi4_pdata->detect_device = of_property_read_bool(np,
+ "synaptics,detect-device");
+
+ if (rmi4_pdata->detect_device)
+ return 0;
+
+ prop = of_find_property(np, "synaptics,button-map", NULL);
+ if (prop) {
+ num_buttons = prop->length / sizeof(temp_val);
+
+ rmi4_pdata->cap_button_map = devm_kzalloc(dev,
+ sizeof(*rmi4_pdata->cap_button_map),
+ GFP_KERNEL);
+ if (!rmi4_pdata->cap_button_map)
+ return -ENOMEM;
+
+ rmi4_pdata->cap_button_map->map = devm_kzalloc(dev,
+ sizeof(*rmi4_pdata->cap_button_map->map) *
+ MAX_NUMBER_OF_BUTTONS, GFP_KERNEL);
+ if (!rmi4_pdata->cap_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->cap_button_map->map[i] =
+ button_map[i];
+ rmi4_pdata->cap_button_map->nbuttons =
+ num_buttons;
+ } else {
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+#else
+static inline int synaptics_dsx_parse_dt(struct device *dev,
+ struct synaptics_dsx_board_data *rmi4_pdata)
+{
+ return 0;
+}
+#endif
static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int retval;
+ struct synaptics_dsx_board_data *platform_data;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -198,6 +413,29 @@ static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
return -EIO;
}
+ if (client->dev.of_node) {
+ platform_data = devm_kzalloc(&client->dev,
+ sizeof(struct synaptics_dsx_board_data),
+ GFP_KERNEL);
+ if (!platform_data) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ retval = synaptics_dsx_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",
+ __func__);
+ return -EINVAL;
+ }
+
synaptics_dsx_i2c_device = kzalloc(
sizeof(struct platform_device),
GFP_KERNEL);
@@ -208,7 +446,7 @@ static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
return -ENOMEM;
}
- hw_if.board_data = client->dev.platform_data;
+ hw_if.board_data = platform_data;
hw_if.bus_access = &bus_access;
synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME;
@@ -242,13 +480,23 @@ static const struct i2c_device_id synaptics_rmi4_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+#ifdef CONFIG_OF
+static struct of_device_id dsx_match_table[] = {
+ { .compatible = "synaptics,dsx",},
+ { },
+};
+#else
+#define dsx_match_table NULL
+#endif
+
static struct i2c_driver synaptics_rmi4_i2c_driver = {
.driver = {
.name = I2C_DRIVER_NAME,
.owner = THIS_MODULE,
+ .of_match_table = dsx_match_table,
},
.probe = synaptics_rmi4_i2c_probe,
- .remove = __devexit_p(synaptics_rmi4_i2c_remove),
+ .remove = synaptics_rmi4_i2c_remove,
.id_table = synaptics_rmi4_id_table,
};
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c
index 44d3a9ee603b..99c05e6845c0 100755
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c
@@ -23,7 +23,7 @@
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx.h>
+#include <linux/input/synaptics_dsx_v2.h>
#include "synaptics_dsx_core.h"
#define PROX_PHYS_NAME "synaptics_dsx/input1"
@@ -649,14 +649,14 @@ static struct synaptics_rmi4_exp_fn proximity_module = {
static int __init rmi4_proximity_module_init(void)
{
- synaptics_rmi4_new_function(&proximity_module, true);
+ synaptics_rmi4_dsx_new_function(&proximity_module, true);
return 0;
}
static void __exit rmi4_proximity_module_exit(void)
{
- synaptics_rmi4_new_function(&proximity_module, false);
+ synaptics_rmi4_dsx_new_function(&proximity_module, false);
wait_for_completion(&prox_remove_complete);
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
index 016ffe9d91df..4c341ffb6094 100755..100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
@@ -26,7 +26,7 @@
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx.h>
+#include <linux/input/synaptics_dsx_v2.h>
#include "synaptics_dsx_core.h"
#define CHAR_DEVICE_NAME "rmi"
@@ -72,7 +72,7 @@ struct rmidev_data {
static struct bin_attribute attr_data = {
.attr = {
.name = "data",
- .mode = (S_IRUGO | S_IWUGO),
+ .mode = (S_IRUGO | S_IWUSR),
},
.size = 0,
.read = rmidev_sysfs_data_show,
@@ -80,11 +80,11 @@ static struct bin_attribute attr_data = {
};
static struct device_attribute attrs[] = {
- __ATTR(open, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(open, S_IWUSR | S_IWGRP,
+ NULL,
rmidev_sysfs_open_store),
- __ATTR(release, S_IWUGO,
- synaptics_rmi4_show_error,
+ __ATTR(release, S_IWUSR | S_IWGRP,
+ NULL,
rmidev_sysfs_release_store),
__ATTR(attn_state, S_IRUGO,
rmidev_sysfs_attn_state_show,
@@ -522,7 +522,7 @@ static void rmidev_device_cleanup(struct rmidev_data *dev_data)
return;
}
-static char *rmi_char_devnode(struct device *dev, mode_t *mode)
+static char *rmi_char_devnode(struct device *dev, umode_t *mode)
{
if (!mode)
return NULL;
@@ -759,14 +759,14 @@ static struct synaptics_rmi4_exp_fn rmidev_module = {
static int __init rmidev_module_init(void)
{
- synaptics_rmi4_new_function(&rmidev_module, true);
+ synaptics_rmi4_dsx_new_function(&rmidev_module, true);
return 0;
}
static void __exit rmidev_module_exit(void)
{
- synaptics_rmi4_new_function(&rmidev_module, false);
+ synaptics_rmi4_dsx_new_function(&rmidev_module, false);
wait_for_completion(&rmidev_remove_complete);
diff --git a/include/linux/input/synaptics_dsx_v2.h b/include/linux/input/synaptics_dsx_v2.h
index dc6e6be28ceb..fe293f5b99c7 100755
--- a/include/linux/input/synaptics_dsx_v2.h
+++ b/include/linux/input/synaptics_dsx_v2.h
@@ -35,6 +35,16 @@ struct synaptics_dsx_cap_button_map {
};
/*
+ * struct synaptics_virtual_key_map - 2d button map
+ * @nkeys: number of virtual keys
+ * @map: pointer to array of virtual keys
+ */
+struct synaptics_rmi4_virtual_key_map {
+ unsigned char nkeys;
+ unsigned int *map;
+};
+
+/*
* struct synaptics_dsx_board_data - dsx board data
* @x_flip: x flip flag
* @y_flip: y flip flag
@@ -60,11 +70,12 @@ struct synaptics_dsx_board_data {
bool y_flip;
bool swap_axes;
int irq_gpio;
+ u32 irq_flags;
int power_gpio;
int power_on_state;
int reset_gpio;
+ u32 reset_flags;
int reset_on_state;
- unsigned long irq_flags;
unsigned int panel_x;
unsigned int panel_y;
unsigned int power_delay_ms;
@@ -73,8 +84,21 @@ struct synaptics_dsx_board_data {
unsigned int byte_delay_us;
unsigned int block_delay_us;
unsigned char *regulator_name;
+ unsigned int package_id;
int (*gpio_config)(int gpio, bool configure, int dir, int state);
struct synaptics_dsx_cap_button_map *cap_button_map;
+ struct synaptics_rmi4_virtual_key_map *virtual_key_map;
+ u32 panel_minx;
+ u32 panel_miny;
+ u32 panel_maxx;
+ u32 panel_maxy;
+ u32 disp_minx;
+ u32 disp_miny;
+ u32 disp_maxx;
+ u32 disp_maxy;
+ bool disable_gpios;
+ bool detect_device;
+ const char *fw_name;
};
#endif