diff options
| author | Mohan Pallaka <mpallaka@codeaurora.org> | 2014-02-12 15:17:28 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:57:51 -0700 |
| commit | 358da51dda67c6747d8ff119d1311636ceacb7a5 (patch) | |
| tree | fe35ac58186842f3bd6e385bb173696e7940adcc | |
| parent | 7ef5f9cf4e6464f7128dccd58481977a91d69400 (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.txt | 103 | ||||
| -rw-r--r-- | drivers/input/touchscreen/Kconfig | 13 | ||||
| -rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/touchscreen/synaptics_dsx/Kconfig | 42 | ||||
| -rw-r--r-- | drivers/input/touchscreen/synaptics_dsx/Makefile | 12 | ||||
| -rw-r--r--[-rwxr-xr-x] | drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c | 1741 | ||||
| -rw-r--r--[-rwxr-xr-x] | drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.h | 82 | ||||
| -rw-r--r--[-rwxr-xr-x] | drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c | 267 | ||||
| -rwxr-xr-x | drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c | 254 | ||||
| -rwxr-xr-x | drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c | 6 | ||||
| -rw-r--r--[-rwxr-xr-x] | drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c | 18 | ||||
| -rwxr-xr-x | include/linux/input/synaptics_dsx_v2.h | 26 |
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 |
