MLK-17829 touchscreen: Add synaptics_dsx S3508 i2c touch driver
authorHaibo Chen <haibo.chen@nxp.com>
Mon, 5 Mar 2018 09:46:15 +0000 (17:46 +0800)
committerHaibo Chen <haibo.chen@nxp.com>
Thu, 12 Apr 2018 10:44:05 +0000 (18:44 +0800)
Add S3508 touch driver support.

Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/synaptics_dsx/Kconfig [new file with mode: 0644]
drivers/input/touchscreen/synaptics_dsx/Makefile [new file with mode: 0644]
drivers/input/touchscreen/synaptics_dsx/synaptics_dsx.h [new file with mode: 0644]
drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c [new file with mode: 0644]
drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.h [new file with mode: 0644]

index c6cd111..14931da 100644 (file)
@@ -1239,6 +1239,7 @@ config TOUCHSCREEN_ROHM_BU21023
          To compile this driver as a module, choose M here: the
          module will be called bu21023_ts.
 
+source "drivers/input/touchscreen/synaptics_dsx/Kconfig"
 endif
 
 source "drivers/input/touchscreen/focaltech_touch/Kconfig"
index 7037a08..d9a5331 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN_TS)      += elan_ts.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)       += egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)        += egalax_ts_serial.o
 obj-$(CONFIG_TOUCHSCREEN_FTS)          += focaltech_touch/
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX)        += synaptics_dsx/
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)      += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GOODIX)       += goodix.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)      += ili210x.o
diff --git a/drivers/input/touchscreen/synaptics_dsx/Kconfig b/drivers/input/touchscreen/synaptics_dsx/Kconfig
new file mode 100644 (file)
index 0000000..6410f7e
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Synaptics DSX touchscreen driver configuration
+#
+menuconfig TOUCHSCREEN_SYNAPTICS_DSX
+       bool "Synaptics DSX touchscreen"
+       default y
+       help
+         Say Y here if you have a Synaptics DSX I2C touchscreen
+         connected to your system
+
+         if unsure, say N.
+
+if TOUCHSCREEN_SYNAPTICS_DSX
+
+config TOUCHSCREEN_SYNAPTICS_DSX_I2C
+       tristate "Synaptics DSX core driver module"
+       depends on I2C
+       help
+         Say Y here if you have a Synaptics DSX I2C touchscreen
+         connected to your system
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called synaptics_dsx_i2c.
+
+endif
diff --git a/drivers/input/touchscreen/synaptics_dsx/Makefile b/drivers/input/touchscreen/synaptics_dsx/Makefile
new file mode 100644 (file)
index 0000000..b46f3df
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C) +=  synaptics_dsx_i2c.o
+
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx.h
new file mode 100644 (file)
index 0000000..5adeb65
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Synaptics DSX touchscreen driver
+ *
+ * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
+ * DOLLARS.
+ */
+
+#ifndef _SYNAPTICS_DSX_H_
+#define _SYNAPTICS_DSX_H_
+
+/*
+ * synaptics_dsx_cap_button_map - 0d button map
+ * @nbuttons: number of 0d buttons
+ * @map: pointer to array of button types
+ */
+struct synaptics_dsx_cap_button_map {
+       unsigned int nbuttons;
+       unsigned int *map;
+};
+
+/*
+ * struct synaptics_dsx_platform_data - dsx platform data
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * @irq_gpio: attention interrupt gpio
+ * @power_gpio: power switch gpio
+ * @power_on_state: power switch active state
+ * @reset_gpio: reset gpio
+ * @reset_on_state: reset active state
+ * @irq_flags: irq flags
+ * @panel_x: x-axis resolution of display panel
+ * @panel_y: y-axis resolution of display panel
+ * @power_delay_ms: delay time to wait after power-on
+ * @reset_delay_ms: delay time to wait after reset
+ * @reset_active_ms: reset active time
+ * @regulator_name: pointer to name of regulator
+ * @gpio_config: pointer to gpio configuration function
+ * @cap_button_map: pointer to 0d button map
+ */
+struct synaptics_dsx_platform_data {
+       bool x_flip;
+       bool y_flip;
+       bool swap_axes;
+       int irq_gpio;
+       int power_gpio;
+       int power_on_state;
+       int reset_gpio;
+       int reset_on_state;
+       unsigned long irq_flags;
+       unsigned int panel_x;
+       unsigned int panel_y;
+       unsigned int power_delay_ms;
+       unsigned int reset_delay_ms;
+       unsigned int reset_active_ms;
+       unsigned char *regulator_name;
+       int (*gpio_config)(int gpio, bool configure, int dir, int state);
+       struct synaptics_dsx_cap_button_map *cap_button_map;
+};
+
+#endif
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
new file mode 100644 (file)
index 0000000..b05e561
--- /dev/null
@@ -0,0 +1,3613 @@
+/*
+ * Synaptics DSX touchscreen driver
+ *
+ * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright 2018 NXP
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
+ * DOLLARS.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/stringify.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/dma-mapping.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+
+#include "synaptics_dsx_i2c.h"
+#include "synaptics_dsx.h"
+
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+#include <linux/input/mt.h>
+
+
+#define DRIVER_NAME "synaptics_dsx_i2c"
+#define INPUT_PHYS_NAME "synaptics_dsx_i2c/input0"
+
+#define TYPE_B_PROTOCOL
+
+#define UBL_I2C_ADDR 0x2c
+
+#define SENSOR_MAX_X 1080
+#define SENSOR_MAX_Y 1920
+
+#define WAKEUP_GESTURE false
+
+#define NO_0D_WHILE_2D
+#define REPORT_2D_W
+
+#define F12_DATA_15_WORKAROUND
+
+#define RPT_TYPE (1 << 0)
+#define RPT_X_LSB (1 << 1)
+#define RPT_X_MSB (1 << 2)
+#define RPT_Y_LSB (1 << 3)
+#define RPT_Y_MSB (1 << 4)
+#define RPT_Z (1 << 5)
+#define RPT_WX (1 << 6)
+#define RPT_WY (1 << 7)
+#define RPT_DEFAULT (RPT_TYPE | RPT_X_LSB | RPT_X_MSB | RPT_Y_LSB | RPT_Y_MSB)
+#define attrify(propname) (&dev_attr_##propname.attr)
+
+#define EXP_FN_WORK_DELAY_MS 1000 /* ms */
+#define SYN_I2C_RETRY_TIMES 5
+#define MAX_F11_TOUCH_WIDTH 15
+
+#define CHECK_STATUS_TIMEOUT_MS        100
+#define DELAY_BOOT_READY       200
+#define DELAY_RESET_LOW                20
+#define DELAY_UI_READY         200
+
+#define F01_STD_QUERY_LEN 21
+#define F01_BUID_ID_OFFSET 18
+#define F11_STD_QUERY_LEN 9
+#define F11_STD_CTRL_LEN 10
+#define F11_STD_DATA_LEN 12
+
+#define STATUS_NO_ERROR 0x00
+#define STATUS_RESET_OCCURRED 0x01
+#define STATUS_INVALID_CONFIG 0x02
+#define STATUS_DEVICE_FAILURE 0x03
+#define STATUS_CONFIG_CRC_FAILURE 0x04
+#define STATUS_FIRMWARE_CRC_FAILURE 0x05
+#define STATUS_CRC_IN_PROGRESS 0x06
+
+#define NORMAL_OPERATION (0 << 0)
+#define SENSOR_SLEEP (1 << 0)
+#define NO_SLEEP_OFF (0 << 2)
+#define NO_SLEEP_ON (1 << 2)
+#define CONFIGURED (1 << 7)
+
+
+#define F11_CONTINUOUS_MODE 0x00
+#define F11_WAKEUP_GESTURE_MODE 0x04
+#define F12_CONTINUOUS_MODE 0x00
+#define F12_WAKEUP_GESTURE_MODE 0x02
+
+#define F12_UDG_DETECT 0x0f
+
+#ifdef USE_I2C_DMA
+#include <linux/dma-mapping.h>
+static unsigned char *wDMABuf_va;
+static dma_addr_t wDMABuf_pa;
+#endif
+
+static struct task_struct *thread;
+static DECLARE_WAIT_QUEUE_HEAD(waiter);
+int tpd_halt;
+static int tpd_flag;
+DEFINE_MUTEX(rmi4_report_mutex);
+static struct device *g_dev;
+
+/* for 0D button  */
+static unsigned int cap_button_codes[] = {KEY_APPSELECT, KEY_HOMEPAGE, KEY_BACK};
+static struct synaptics_dsx_cap_button_map cap_button_map = {
+       .nbuttons = ARRAY_SIZE(cap_button_codes),
+       .map = cap_button_codes,
+};
+
+#ifdef CONFIG_OF_TOUCH
+unsigned int touch_irq;
+#endif
+
+#ifdef CONFIG_OF_TOUCH
+static irqreturn_t tpd_eint_handler(unsigned int irq, struct irq_desc *desc);
+#else
+static void tpd_eint_handler(void);
+#endif
+
+static int touch_event_handler(void *data);
+
+static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
+               unsigned short addr, unsigned char *data,
+               unsigned short length);
+
+static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
+               unsigned short addr, unsigned char *data,
+               unsigned short length);
+
+static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
+               unsigned short ctrl28);
+
+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);
+
+
+static int __maybe_unused synaptics_rmi4_suspend(struct device *dev);
+
+static int __maybe_unused 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_f01_productinfo_show(struct device *dev,
+               struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
+               struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
+               struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
+               struct device_attribute *attr, char *buf);
+
+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,
+               struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
+               struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count);
+struct synaptics_rmi4_f01_device_status {
+       union {
+               struct {
+                       unsigned char status_code:4;
+                       unsigned char reserved:2;
+                       unsigned char flash_prog:1;
+                       unsigned char unconfigured:1;
+               } __packed;
+               unsigned char data[1];
+       };
+};
+
+struct synaptics_rmi4_f11_query_0_5 {
+       union {
+               struct {
+                       /* query 0 */
+                       unsigned char f11_query0_b0__2:3;
+                       unsigned char has_query_9:1;
+                       unsigned char has_query_11:1;
+                       unsigned char has_query_12:1;
+                       unsigned char has_query_27:1;
+                       unsigned char has_query_28:1;
+
+                       /* query 1 */
+                       unsigned char num_of_fingers:3;
+                       unsigned char has_rel:1;
+                       unsigned char has_abs:1;
+                       unsigned char has_gestures:1;
+                       unsigned char has_sensitibity_adjust:1;
+                       unsigned char f11_query1_b7:1;
+
+                       /* query 2 */
+                       unsigned char num_of_x_electrodes;
+
+                       /* query 3 */
+                       unsigned char num_of_y_electrodes;
+
+                       /* query 4 */
+                       unsigned char max_electrodes:7;
+                       unsigned char f11_query4_b7:1;
+
+                       /* query 5 */
+                       unsigned char abs_data_size:2;
+                       unsigned char has_anchored_finger:1;
+                       unsigned char has_adj_hyst:1;
+                       unsigned char has_dribble:1;
+                       unsigned char has_bending_correction:1;
+                       unsigned char has_large_object_suppression:1;
+                       unsigned char has_jitter_filter:1;
+               } __packed;
+               unsigned char data[6];
+       };
+};
+
+struct synaptics_rmi4_f11_query_7_8 {
+       union {
+               struct {
+                       /* query 7 */
+                       unsigned char has_single_tap:1;
+                       unsigned char has_tap_and_hold:1;
+                       unsigned char has_double_tap:1;
+                       unsigned char has_early_tap:1;
+                       unsigned char has_flick:1;
+                       unsigned char has_press:1;
+                       unsigned char has_pinch:1;
+                       unsigned char has_chiral_scroll:1;
+
+                       /* query 8 */
+                       unsigned char has_palm_detect:1;
+                       unsigned char has_rotate:1;
+                       unsigned char has_touch_shapes:1;
+                       unsigned char has_scroll_zones:1;
+                       unsigned char individual_scroll_zones:1;
+                       unsigned char has_multi_finger_scroll:1;
+                       unsigned char has_multi_finger_scroll_edge_motion:1;
+                       unsigned char has_multi_finger_scroll_inertia:1;
+               } __packed;
+               unsigned char data[2];
+       };
+};
+
+struct synaptics_rmi4_f11_query_9 {
+       union {
+               struct {
+                       unsigned char has_pen:1;
+                       unsigned char has_proximity:1;
+                       unsigned char has_large_object_sensitivity:1;
+                       unsigned char has_suppress_on_large_object_detect:1;
+                       unsigned char has_two_pen_thresholds:1;
+                       unsigned char has_contact_geometry:1;
+                       unsigned char has_pen_hover_discrimination:1;
+                       unsigned char has_pen_hover_and_edge_filters:1;
+               } __packed;
+               unsigned char data[1];
+       };
+};
+
+struct synaptics_rmi4_f11_query_12 {
+       union {
+               struct {
+                       unsigned char has_small_object_detection:1;
+                       unsigned char has_small_object_detection_tuning:1;
+                       unsigned char has_8bit_w:1;
+                       unsigned char has_2d_adjustable_mapping:1;
+                       unsigned char has_general_information_2:1;
+                       unsigned char has_physical_properties:1;
+                       unsigned char has_finger_limit:1;
+                       unsigned char has_linear_cofficient_2:1;
+               } __packed;
+               unsigned char data[1];
+       };
+};
+
+struct synaptics_rmi4_f11_query_27 {
+       union {
+               struct {
+                       unsigned char f11_query27_b0:1;
+                       unsigned char has_pen_position_correction:1;
+                       unsigned char has_pen_jitter_filter_coefficient:1;
+                       unsigned char has_group_decomposition:1;
+                       unsigned char has_wakeup_gesture:1;
+                       unsigned char has_small_finger_correction:1;
+                       unsigned char has_data_37:1;
+                       unsigned char f11_query27_b7:1;
+               } __packed;
+               unsigned char data[1];
+       };
+};
+
+struct synaptics_rmi4_f11_ctrl_6_9 {
+       union {
+               struct {
+                       unsigned char sensor_max_x_pos_7_0;
+                       unsigned char sensor_max_x_pos_11_8:4;
+                       unsigned char f11_ctrl7_b4__7:4;
+                       unsigned char sensor_max_y_pos_7_0;
+                       unsigned char sensor_max_y_pos_11_8:4;
+                       unsigned char f11_ctrl9_b4__7:4;
+               } __packed;
+               unsigned char data[4];
+       };
+};
+
+struct synaptics_rmi4_f11_data_1_5 {
+       union {
+               struct {
+                       unsigned char x_position_11_4;
+                       unsigned char y_position_11_4;
+                       unsigned char x_position_3_0:4;
+                       unsigned char y_position_3_0:4;
+                       unsigned char wx:4;
+                       unsigned char wy:4;
+                       unsigned char z;
+               } __packed;
+               unsigned char data[5];
+       };
+};
+
+struct synaptics_rmi4_f12_query_5 {
+       union {
+               struct {
+                       unsigned char size_of_query6;
+                       struct {
+                               unsigned char ctrl0_is_present:1;
+                               unsigned char ctrl1_is_present:1;
+                               unsigned char ctrl2_is_present:1;
+                               unsigned char ctrl3_is_present:1;
+                               unsigned char ctrl4_is_present:1;
+                               unsigned char ctrl5_is_present:1;
+                               unsigned char ctrl6_is_present:1;
+                               unsigned char ctrl7_is_present:1;
+                       } __packed;
+                       struct {
+                               unsigned char ctrl8_is_present:1;
+                               unsigned char ctrl9_is_present:1;
+                               unsigned char ctrl10_is_present:1;
+                               unsigned char ctrl11_is_present:1;
+                               unsigned char ctrl12_is_present:1;
+                               unsigned char ctrl13_is_present:1;
+                               unsigned char ctrl14_is_present:1;
+                               unsigned char ctrl15_is_present:1;
+                       } __packed;
+                       struct {
+                               unsigned char ctrl16_is_present:1;
+                               unsigned char ctrl17_is_present:1;
+                               unsigned char ctrl18_is_present:1;
+                               unsigned char ctrl19_is_present:1;
+                               unsigned char ctrl20_is_present:1;
+                               unsigned char ctrl21_is_present:1;
+                               unsigned char ctrl22_is_present:1;
+                               unsigned char ctrl23_is_present:1;
+                       } __packed;
+                       struct {
+                               unsigned char ctrl24_is_present:1;
+                               unsigned char ctrl25_is_present:1;
+                               unsigned char ctrl26_is_present:1;
+                               unsigned char ctrl27_is_present:1;
+                               unsigned char ctrl28_is_present:1;
+                               unsigned char ctrl29_is_present:1;
+                               unsigned char ctrl30_is_present:1;
+                               unsigned char ctrl31_is_present:1;
+                       } __packed;
+               };
+               unsigned char data[5];
+       };
+};
+
+struct synaptics_rmi4_f12_query_8 {
+       union {
+               struct {
+                       unsigned char size_of_query9;
+                       struct {
+                               unsigned char data0_is_present:1;
+                               unsigned char data1_is_present:1;
+                               unsigned char data2_is_present:1;
+                               unsigned char data3_is_present:1;
+                               unsigned char data4_is_present:1;
+                               unsigned char data5_is_present:1;
+                               unsigned char data6_is_present:1;
+                               unsigned char data7_is_present:1;
+                       } __packed;
+                       struct {
+                               unsigned char data8_is_present:1;
+                               unsigned char data9_is_present:1;
+                               unsigned char data10_is_present:1;
+                               unsigned char data11_is_present:1;
+                               unsigned char data12_is_present:1;
+                               unsigned char data13_is_present:1;
+                               unsigned char data14_is_present:1;
+                               unsigned char data15_is_present:1;
+                       } __packed;
+               };
+               unsigned char data[3];
+       };
+};
+
+struct synaptics_rmi4_f12_ctrl_8 {
+       union {
+               struct {
+                       unsigned char max_x_coord_lsb;
+                       unsigned char max_x_coord_msb;
+                       unsigned char max_y_coord_lsb;
+                       unsigned char max_y_coord_msb;
+                       unsigned char rx_pitch_lsb;
+                       unsigned char rx_pitch_msb;
+                       unsigned char tx_pitch_lsb;
+                       unsigned char tx_pitch_msb;
+                       unsigned char low_rx_clip;
+                       unsigned char high_rx_clip;
+                       unsigned char low_tx_clip;
+                       unsigned char high_tx_clip;
+                       unsigned char num_of_rx;
+                       unsigned char num_of_tx;
+               };
+               unsigned char data[14];
+       };
+};
+
+struct synaptics_rmi4_f12_ctrl_23 {
+       union {
+               struct {
+                       unsigned char obj_type_enable;
+                       unsigned char max_reported_objects;
+               };
+               unsigned char data[2];
+       };
+};
+
+struct synaptics_rmi4_f12_finger_data {
+       unsigned char object_type_and_status;
+       unsigned char x_lsb;
+       unsigned char x_msb;
+       unsigned char y_lsb;
+       unsigned char y_msb;
+#ifdef REPORT_2D_Z
+       unsigned char z;
+#endif
+#ifdef REPORT_2D_W
+       unsigned char wx;
+       unsigned char wy;
+#endif
+};
+
+struct synaptics_rmi4_f1a_query {
+       union {
+               struct {
+                       unsigned char max_button_count:3;
+                       unsigned char reserved:5;
+                       unsigned char has_general_control:1;
+                       unsigned char has_interrupt_enable:1;
+                       unsigned char has_multibutton_select:1;
+                       unsigned char has_tx_rx_map:1;
+                       unsigned char has_perbutton_threshold:1;
+                       unsigned char has_release_threshold:1;
+                       unsigned char has_strongestbtn_hysteresis:1;
+                       unsigned char has_filter_strength:1;
+               } __packed;
+               unsigned char data[2];
+       };
+};
+
+struct synaptics_rmi4_f1a_control_0 {
+       union {
+               struct {
+                       unsigned char multibutton_report:2;
+                       unsigned char filter_mode:2;
+                       unsigned char reserved:4;
+               } __packed;
+               unsigned char data[1];
+       };
+};
+
+struct synaptics_rmi4_f1a_control {
+       struct synaptics_rmi4_f1a_control_0 general_control;
+       unsigned char button_int_enable;
+       unsigned char multi_button;
+       unsigned char *txrx_map;
+       unsigned char *button_threshold;
+       unsigned char button_release_threshold;
+       unsigned char strongest_button_hysteresis;
+       unsigned char filter_strength;
+};
+
+struct synaptics_rmi4_f1a_handle {
+       int button_bitmask_size;
+       unsigned int max_count;
+       unsigned char valid_button_count;
+       unsigned char *button_data_buffer;
+       unsigned int *button_map;
+       struct synaptics_rmi4_f1a_query button_query;
+       struct synaptics_rmi4_f1a_control button_control;
+};
+
+struct synaptics_rmi4_exp_fhandler {
+       struct synaptics_rmi4_exp_fn *exp_fn;
+       bool insert;
+       bool remove;
+       struct list_head link;
+};
+
+struct synaptics_rmi4_exp_fn_data {
+       bool initialized;
+       bool queue_work;
+       struct mutex mutex;
+       struct list_head list;
+       struct delayed_work work;
+       struct workqueue_struct *workqueue;
+       struct synaptics_rmi4_data *rmi4_data;
+};
+
+static struct synaptics_rmi4_exp_fn_data exp_data;
+
+static struct device_attribute attrs[] = {
+       __ATTR(reset, 0660,
+                       synaptics_rmi4_show_error,
+                       synaptics_rmi4_f01_reset_store),
+       __ATTR(productinfo, 0444,
+                       synaptics_rmi4_f01_productinfo_show,
+                       synaptics_rmi4_store_error),
+       __ATTR(buildid, 0444,
+                       synaptics_rmi4_f01_buildid_show,
+                       synaptics_rmi4_store_error),
+       __ATTR(flashprog, 0444,
+                       synaptics_rmi4_f01_flashprog_show,
+                       synaptics_rmi4_store_error),
+       __ATTR(0dbutton, 0660,
+                       synaptics_rmi4_0dbutton_show,
+                       synaptics_rmi4_0dbutton_store),
+       __ATTR(suspend, 0660,
+                       synaptics_rmi4_show_error,
+                       synaptics_rmi4_suspend_store),
+       __ATTR(wake_gesture, 0660,
+                       synaptics_rmi4_wake_gesture_show,
+                       synaptics_rmi4_wake_gesture_store),
+};
+
+static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int retval;
+       unsigned int reset;
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       if (sscanf(buf, "%u", &reset) != 1)
+               return -EINVAL;
+
+       if (reset != 1)
+               return -EINVAL;
+
+       retval = synaptics_rmi4_reset_device(rmi4_data);
+       if (retval < 0) {
+               dev_err(dev,
+                               "%s: Failed to issue reset command, error = %d\n",
+                               __func__, retval);
+               return retval;
+       }
+
+       return count;
+}
+
+static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n",
+                       (rmi4_data->rmi4_mod_info.product_info[0]),
+                       (rmi4_data->rmi4_mod_info.product_info[1]));
+}
+
+static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       rmi4_data->firmware_id);
+}
+
+static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       int retval;
+       struct synaptics_rmi4_f01_device_status device_status;
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_data_base_addr,
+                       device_status.data,
+                       sizeof(device_status.data));
+       if (retval < 0) {
+               dev_err(dev,
+                               "%s: Failed to read device status, error = %d\n",
+                               __func__, retval);
+               return retval;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       device_status.flash_prog);
+}
+
+static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       rmi4_data->button_0d_enabled);
+}
+
+static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int retval;
+       unsigned int input;
+       unsigned char ii;
+       unsigned char intr_enable;
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+       struct synaptics_rmi4_device_info *rmi;
+
+       rmi = &(rmi4_data->rmi4_mod_info);
+
+       if (sscanf(buf, "%u", &input) != 1)
+               return -EINVAL;
+
+       input = input > 0 ? 1 : 0;
+
+       if (rmi4_data->button_0d_enabled == input)
+               return count;
+
+       if (list_empty(&rmi->support_fn_list))
+               return -ENODEV;
+
+       list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+               if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
+                       ii = fhandler->intr_reg_num;
+
+                       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                                       rmi4_data->f01_ctrl_base_addr + 1 + ii,
+                                       &intr_enable,
+                                       sizeof(intr_enable));
+                       if (retval < 0)
+                               return retval;
+
+                       if (input == 1)
+                               intr_enable |= fhandler->intr_mask;
+                       else
+                               intr_enable &= ~fhandler->intr_mask;
+
+                       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                                       rmi4_data->f01_ctrl_base_addr + 1 + ii,
+                                       &intr_enable,
+                                       sizeof(intr_enable));
+                       if (retval < 0)
+                               return retval;
+               }
+       }
+
+       rmi4_data->button_0d_enabled = input;
+
+       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;
+}
+
+
+static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n",
+                       rmi4_data->enable_wakeup_gesture);
+}
+
+static ssize_t synaptics_rmi4_wake_gesture_store(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;
+
+       input = input > 0 ? 1 : 0;
+
+       if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
+               rmi4_data->enable_wakeup_gesture = input;
+
+       return count;
+}
+
+static int tpd_set_page(struct synaptics_rmi4_data *rmi4_data,
+                       unsigned short addr)
+{
+       int retval = 0;
+       unsigned char retry;
+       unsigned char buf[PAGE_SELECT_LEN];
+       unsigned char page;
+       struct i2c_client *i2c = rmi4_data->i2c_client;
+
+       page = ((addr >> 8) & MASK_8BIT);
+       if (page != rmi4_data->current_page) {
+               buf[0] = MASK_8BIT;
+               buf[1] = page;
+               for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+                       retval = i2c_master_send(i2c, buf, PAGE_SELECT_LEN);
+                       if (retval != PAGE_SELECT_LEN) {
+                               dev_err(&rmi4_data->i2c_client->dev,
+                                       "%s: I2C retry %d\n", __func__, retry + 1);
+                               msleep(20);
+                               if (retry == (SYN_I2C_RETRY_TIMES / 2)) {
+                                       if (i2c->addr == rmi4_data->i2c_addr)
+                                               i2c->addr = UBL_I2C_ADDR;
+                                       else
+                                               i2c->addr = rmi4_data->i2c_addr;
+                               }
+                       } else {
+                               rmi4_data->current_page = page;
+                               break;
+                       }
+               }
+       } else {
+               retval = PAGE_SELECT_LEN;
+       }
+
+       return retval;
+}
+
+
+int tpd_i2c_read_data(struct synaptics_rmi4_data *rmi4_data, struct i2c_client *client,
+                          unsigned short addr, unsigned char *data, unsigned short length)
+{
+
+       unsigned char retry = 0;
+       unsigned char *pData = data;
+       unsigned char tmp_addr = (unsigned char)addr;
+       int retval = 0;
+       int left_len = length;
+
+       /* u16 old_flag; */
+       mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+       retval = tpd_set_page(rmi4_data, addr);
+       if (retval != PAGE_SELECT_LEN) {
+               retval = -EIO;
+               goto exit;
+       }
+
+       retval = i2c_master_send(client, &tmp_addr, 1);
+       while (left_len > 0) {
+               for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+                       if (left_len > 8)
+                               retval = i2c_master_recv(client, pData, 8);
+                       else
+                               retval = i2c_master_recv(client, pData, left_len);
+                       if (retval <= 0) {
+                               dev_err(&client->dev, "%s: I2C retry %d\n", __func__, retry + 1);
+                               msleep(20);
+                               if (retry == (SYN_I2C_RETRY_TIMES / 2)) {
+                                       if (client->addr == rmi4_data->i2c_addr)
+                                               client->addr = UBL_I2C_ADDR;
+                                       else
+                                               client->addr = rmi4_data->i2c_addr;
+                               }
+                               left_len = length;
+                               pData = data;
+                               retval = i2c_master_send(client, &tmp_addr, 1);
+                               continue;
+                       } else {
+                               break;
+                       }
+               }
+               if (retry == SYN_I2C_RETRY_TIMES) {
+                       retval = -EIO;
+                       goto exit;
+               }
+               left_len -= 8;
+               pData += 8;
+       }
+exit:
+        mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+       return retval;
+}
+EXPORT_SYMBOL(tpd_i2c_read_data);
+
+#ifdef USE_I2C_DMA
+int tpd_i2c_write_data_dma(struct synaptics_rmi4_data *rmi4_data, struct i2c_client *client,
+                               unsigned short addr, unsigned char *data, unsigned short length)
+{
+       int retval = 0;
+       unsigned char retry;
+       unsigned char *buf_va = NULL;
+       struct i2c_msg msg[1];
+
+       mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+       msg[0].addr = rmi4_data->i2c_client->addr;
+       msg[0].flags = 0;
+       msg[0].len = length + 1;
+       msg[0].ext_flag = (rmi4_data->i2c_client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
+       msg[0].buf = (unsigned char *)(uintptr_t)wDMABuf_pa;
+       msg[0].timing = 400;
+
+       retval = tpd_set_page(rmi4_data, addr);
+       if (retval != PAGE_SELECT_LEN) {
+               retval = -EIO;
+               goto exit;
+       }
+
+       buf_va = wDMABuf_va;
+       buf_va[0] = addr & MASK_8BIT;
+       memcpy(&buf_va[1], &data[0], length);
+
+       for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+               if (i2c_transfer(rmi4_data->i2c_client->adapter, msg, 1) == 1) {
+                       retval = length;
+                       break;
+               }
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: I2C retry %d\n",
+                               __func__, retry + 1);
+               msleep(20);
+
+               if (retry == (SYN_I2C_RETRY_TIMES / 2)) {
+                       if (rmi4_data->i2c_client->addr == rmi4_data->i2c_addr)
+                               rmi4_data->i2c_client->addr = UBL_I2C_ADDR;
+                       else
+                               rmi4_data->i2c_client->addr = rmi4_data->i2c_addr;
+                       msg[0].addr = rmi4_data->i2c_client->addr;
+               }
+       }
+
+       if (retry == SYN_I2C_RETRY_TIMES) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: I2C write over retry limit\n",
+                               __func__);
+               retval = -EIO;
+       }
+
+exit:
+       mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+       return retval;
+}
+EXPORT_SYMBOL(tpd_i2c_write_data_dma);
+
+#else
+int tpd_i2c_write_data(struct synaptics_rmi4_data *rmi4_data, struct i2c_client *client,
+                               unsigned short addr, unsigned char *data, unsigned short length)
+{
+       int retval = 0;
+       u8 retry = 0;
+       u8 *buf;
+       int tmp_addr = addr;
+
+
+       mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+       retval = tpd_set_page(rmi4_data, addr);
+       if (retval != PAGE_SELECT_LEN) {
+               pr_err("tpd_set_page fail, retval = %d\n", retval);
+               retval = -EIO;
+               goto exit;
+       }
+
+       buf = kzalloc(sizeof(unsigned char) * (length + 1), GFP_KERNEL);
+       *buf = tmp_addr;
+       memcpy(buf + 1, data, length);
+       for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+               retval = i2c_master_send(client, buf, (length + 1));
+               if (retval <= 0) {
+                       dev_err(&client->dev, "%s: I2C retry %d\n", __func__, retry + 1);
+                       msleep(20);
+                       continue;
+               } else {
+                       break;
+               }
+       }
+       kfree(buf);
+
+exit:
+       mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+       return retval;
+}
+EXPORT_SYMBOL(tpd_i2c_write_data);
+
+#endif
+
+ /**
+  * synaptics_rmi4_i2c_read()
+  *
+  * Called by various functions in this driver, and also exported to
+  * other expansion Function modules such as rmi_dev.
+  *
+  * This function reads data of an arbitrary length from the sensor,
+  * starting from an assigned register address of the sensor, via I2C
+  * with a retry mechanism.
+  */
+static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
+               unsigned short addr, unsigned char *data, unsigned short length)
+{
+       return tpd_i2c_read_data(rmi4_data, rmi4_data->i2c_client, addr, data, length);
+}
+
+ /**
+  * synaptics_rmi4_i2c_write()
+  *
+  * Called by various functions in this driver, and also exported to
+  * other expansion Function modules such as rmi_dev.
+  *
+  * This function writes data of an arbitrary length to the sensor,
+  * starting from an assigned register address of the sensor, via I2C with
+  * a retry mechanism.
+  */
+static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
+               unsigned short addr, unsigned char *data, unsigned short length)
+{
+#ifdef USE_I2C_DMA
+       return tpd_i2c_write_data_dma(rmi4_data, rmi4_data->i2c_client, addr, data, length);
+#else
+       return tpd_i2c_write_data(rmi4_data, rmi4_data->i2c_client, addr, data, length);
+#endif
+}
+
+ /**
+  * synaptics_rmi4_f11_abs_report()
+  *
+  * Called by synaptics_rmi4_report_touch() when valid Function $11
+  * finger data has been detected.
+  *
+  * This function reads the Function $11 data registers, determines the
+  * status of each finger supported by the Function, processes any
+  * necessary coordinate manipulation, reports the finger data to
+  * the input subsystem, and returns the number of fingers detected.
+  */
+static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler)
+{
+       int retval;
+       unsigned char touch_count = 0; /* number of touch points */
+       unsigned char reg_index;
+       unsigned char finger;
+       unsigned char fingers_supported;
+       unsigned char num_of_finger_status_regs;
+       unsigned char finger_shift;
+       unsigned char finger_status;
+       unsigned char finger_status_reg[3];
+       unsigned char detected_gestures;
+       unsigned short data_addr;
+       unsigned short data_offset;
+       int x;
+       int y;
+       int wx;
+       int wy;
+       //int temp;
+       struct synaptics_rmi4_f11_data_1_5 data;
+       struct synaptics_rmi4_f11_extra_data *extra_data;
+
+       /*
+        * The number of finger status registers is determined by the
+        * maximum number of fingers supported - 2 bits per finger. So
+        * the number of finger status registers to read is:
+        * register_count = ceil(max_num_of_fingers / 4)
+        */
+       fingers_supported = fhandler->num_of_data_points;
+       num_of_finger_status_regs = (fingers_supported + 3) / 4;
+       data_addr = fhandler->full_addr.data_base;
+
+       extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
+
+       if (rmi4_data->sensor_sleep && rmi4_data->enable_wakeup_gesture) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               data_addr + extra_data->data38_offset,
+                               &detected_gestures,
+                               sizeof(detected_gestures));
+               if (retval < 0)
+                       return 0;
+
+               if (detected_gestures) {
+                       input_report_key(rmi4_data->input_dev, KEY_POWER, 1);
+                       input_sync(rmi4_data->input_dev);
+                       input_report_key(rmi4_data->input_dev, KEY_POWER, 0);
+                       input_sync(rmi4_data->input_dev);
+                       rmi4_data->sensor_sleep = false;
+               }
+
+               return 0;
+       }
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       data_addr,
+                       finger_status_reg,
+                       num_of_finger_status_regs);
+       if (retval < 0)
+               return 0;
+       mutex_lock(&rmi4_report_mutex);
+       for (finger = 0; finger < fingers_supported; finger++) {
+               reg_index = finger / 4;
+               finger_shift = (finger % 4) * 2;
+               finger_status = (finger_status_reg[reg_index] >> finger_shift)
+                               & MASK_2BIT;
+
+               /*
+                * Each 2-bit finger status field represents the following:
+                * 00 = finger not present
+                * 01 = finger present and data accurate
+                * 10 = finger present but data may be inaccurate
+                * 11 = reserved
+                */
+#ifdef TYPE_B_PROTOCOL
+               input_mt_slot(rmi4_data->input_dev, finger);
+               input_mt_report_slot_state(rmi4_data->input_dev,
+                               MT_TOOL_FINGER, finger_status);
+#endif
+
+               if (finger_status) {
+                       data_offset = data_addr +
+                                       num_of_finger_status_regs +
+                                       (finger * sizeof(data.data));
+                       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                                       data_offset,
+                                       data.data,
+                                       sizeof(data.data));
+                       if (retval < 0) {
+                               touch_count = 0;
+                               goto exit;
+                       }
+
+                       x = (data.x_position_11_4 << 4) | data.x_position_3_0;
+                       y = (data.y_position_11_4 << 4) | data.y_position_3_0;
+                       wx = data.wx;
+                       wy = data.wy;
+
+                       input_report_key(rmi4_data->input_dev,
+                                       BTN_TOUCH, 1);
+                       input_report_key(rmi4_data->input_dev,
+                                       BTN_TOOL_FINGER, 1);
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_POSITION_X, x);
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_TOUCH_MAJOR, max(wx, wy));
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#ifndef TYPE_B_PROTOCOL
+                       input_mt_sync(rmi4_data->input_dev);
+#endif
+
+                       dev_dbg(&rmi4_data->i2c_client->dev,
+                                       "%s: Finger %d:\n"
+                                       "status = 0x%02x\n"
+                                       "x = %d\n"
+                                       "y = %d\n"
+                                       "wx = %d\n"
+                                       "wy = %d\n",
+                                       __func__, finger,
+                                       finger_status,
+                                       x, y, wx, wy);
+
+                       touch_count++;
+               }
+       }
+
+       if (touch_count == 0) {
+               input_report_key(rmi4_data->input_dev,
+                               BTN_TOUCH, 0);
+               input_report_key(rmi4_data->input_dev,
+                               BTN_TOOL_FINGER, 0);
+#ifndef TYPE_B_PROTOCOL
+               input_mt_sync(rmi4_data->input_dev);
+#endif
+       }
+
+       input_sync(rmi4_data->input_dev);
+exit:
+       mutex_unlock(&(rmi4_report_mutex));
+       return touch_count;
+}
+
+ /**
+ * synaptics_rmi4_f12_abs_report()
+ *
+ * Called by synaptics_rmi4_report_touch() when valid Function $12
+ * finger data has been detected.
+ *
+ * This function reads the Function $12 data registers, determines the
+ * status of each finger supported by the Function, processes any
+ * necessary coordinate manipulation, reports the finger data to
+ * the input subsystem, and returns the number of fingers detected.
+ */
+static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler)
+{
+       int retval;
+       unsigned char touch_count = 0; /* number of touch points */
+       unsigned char finger;
+       unsigned char fingers_to_process;
+       unsigned char finger_status;
+       unsigned char size_of_2d_data;
+       unsigned char detected_gestures[F12_GESTURE_DETECTION_LEN]; // byte0 indicate gesture type, byte1~byte4 are gesture parameter
+       unsigned short data_addr;
+       int x;
+       int y;
+       int wx;
+       int wy;
+       int temp;
+       struct synaptics_rmi4_f12_extra_data *extra_data;
+       struct synaptics_rmi4_f12_finger_data *data;
+       struct synaptics_rmi4_f12_finger_data *finger_data;
+#ifdef F12_DATA_15_WORKAROUND
+       static unsigned char fingers_already_present;
+#endif
+
+       fingers_to_process = fhandler->num_of_data_points;
+       data_addr = fhandler->full_addr.data_base;
+       extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+       size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+
+       if (rmi4_data->sensor_sleep && rmi4_data->enable_wakeup_gesture) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               data_addr + extra_data->data4_offset,
+                               detected_gestures,
+                               sizeof(detected_gestures));
+               if (retval < 0)
+                       return 0;
+
+               if (detected_gestures[0] && (detected_gestures[0] != F12_UDG_DETECT)) { // here is demo only, customer could decode gesture data and do whatever they want
+                       input_report_key(rmi4_data->input_dev, KEY_POWER, 1);
+                       input_sync(rmi4_data->input_dev);
+                       input_report_key(rmi4_data->input_dev, KEY_POWER, 0);
+                       input_sync(rmi4_data->input_dev);
+                       rmi4_data->sensor_sleep = false;
+               }
+
+               return 0;
+       }
+
+
+       /* Determine the total number of fingers to process */
+       if (extra_data->data15_size) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               data_addr + extra_data->data15_offset,
+                               extra_data->data15_data,
+                               extra_data->data15_size);
+               if (retval < 0)
+                       return 0;
+
+               /* 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;
+                       }
+
+                       fingers_to_process--;
+               } while (fingers_to_process);
+
+               dev_dbg(&rmi4_data->i2c_client->dev,
+                       "%s: Number of fingers to process = %d\n",
+                       __func__, fingers_to_process);
+       }
+
+#ifdef F12_DATA_15_WORKAROUND
+       fingers_to_process = max(fingers_to_process, fingers_already_present);
+#endif
+
+       if (!fingers_to_process) {
+               synaptics_rmi4_free_fingers(rmi4_data);
+               return 0;
+       }
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       data_addr + extra_data->data1_offset,
+                       (unsigned char *)fhandler->data,
+                       fingers_to_process * size_of_2d_data);
+       if (retval < 0)
+               return 0;
+
+       data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data;
+       mutex_lock(&rmi4_report_mutex);
+       for (finger = 0; finger < fingers_to_process; finger++) {
+               finger_data = data + finger;
+               finger_status = finger_data->object_type_and_status & MASK_1BIT;
+
+#ifdef TYPE_B_PROTOCOL
+               input_mt_slot(rmi4_data->input_dev, finger);
+               input_mt_report_slot_state(rmi4_data->input_dev,
+                               MT_TOOL_FINGER, finger_status);
+#endif
+
+               if (finger_status) {
+#ifdef F12_DATA_15_WORKAROUND
+                       fingers_already_present = finger + 1;
+#endif
+
+                       x = (finger_data->x_msb << 8) | (finger_data->x_lsb);
+                       y = (finger_data->y_msb << 8) | (finger_data->y_lsb);
+#ifdef REPORT_2D_W
+                       wx = finger_data->wx;
+                       wy = finger_data->wy;
+#endif
+
+                       input_report_key(rmi4_data->input_dev,
+                                       BTN_TOUCH, 1);
+                       input_report_key(rmi4_data->input_dev,
+                                       BTN_TOOL_FINGER, 1);
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_POSITION_X, x);
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_TOUCH_MAJOR, max(wx, wy));
+                       input_report_abs(rmi4_data->input_dev,
+                                       ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#ifndef TYPE_B_PROTOCOL
+                       input_mt_sync(rmi4_data->input_dev);
+#endif
+
+                       dev_dbg(&rmi4_data->i2c_client->dev,
+                                       "%s: Finger %d:\n"
+                                       "status = 0x%02x\n"
+                                       "x = %d\n"
+                                       "y = %d\n"
+                                       "wx = %d\n"
+                                       "wy = %d\n",
+                                       __func__, finger,
+                                       finger_status,
+                                       x, y, wx, wy);
+
+                       touch_count++;
+               }
+       }
+
+       if (touch_count == 0) {
+               input_report_key(rmi4_data->input_dev,
+                               BTN_TOUCH, 0);
+               input_report_key(rmi4_data->input_dev,
+                               BTN_TOOL_FINGER, 0);
+#ifndef TYPE_B_PROTOCOL
+               input_mt_sync(rmi4_data->input_dev);
+#endif
+       }
+
+       input_sync(rmi4_data->input_dev);
+       mutex_unlock(&rmi4_report_mutex);
+       return touch_count;
+}
+
+static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler)
+{
+       int retval;
+       unsigned char touch_count = 0;
+       unsigned char button;
+       unsigned char index;
+       unsigned char shift;
+       unsigned char status;
+       unsigned char *data;
+       unsigned short data_addr = fhandler->full_addr.data_base;
+       struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+       static unsigned char do_once = 1;
+       static bool current_status[MAX_NUMBER_OF_BUTTONS];
+#ifdef NO_0D_WHILE_2D
+       static bool before_2d_status[MAX_NUMBER_OF_BUTTONS];
+       static bool while_2d_status[MAX_NUMBER_OF_BUTTONS];
+#endif
+
+       if (do_once) {
+               memset(current_status, 0, sizeof(current_status));
+#ifdef NO_0D_WHILE_2D
+               memset(before_2d_status, 0, sizeof(before_2d_status));
+               memset(while_2d_status, 0, sizeof(while_2d_status));
+#endif
+               do_once = 0;
+       }
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       data_addr,
+                       f1a->button_data_buffer,
+                       f1a->button_bitmask_size);
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to read button data registers\n",
+                               __func__);
+               return;
+       }
+
+       data = f1a->button_data_buffer;
+       mutex_lock(&rmi4_report_mutex);
+       for (button = 0; button < f1a->valid_button_count; button++) {
+               index = button / 8;
+               shift = button % 8;
+               status = ((data[index] >> shift) & MASK_1BIT);
+
+               if (current_status[button] == status)
+                       continue;
+               else
+                       current_status[button] = status;
+
+               dev_dbg(&rmi4_data->i2c_client->dev,
+                               "%s: Button %d (code %d) ->%d\n",
+                               __func__, button,
+                               f1a->button_map[button],
+                               status);
+#ifdef NO_0D_WHILE_2D
+               if (rmi4_data->fingers_on_2d == false) {
+                       if (status == 1) {
+                               before_2d_status[button] = 1;
+                       } else {
+                               if (while_2d_status[button] == 1) {
+                                       while_2d_status[button] = 0;
+                                       continue;
+                               } else {
+                                       before_2d_status[button] = 0;
+                               }
+                       }
+                       touch_count++;
+                       input_report_key(rmi4_data->input_dev,
+                                       f1a->button_map[button],
+                                       status);
+               } else {
+                       if (before_2d_status[button] == 1) {
+                               before_2d_status[button] = 0;
+                               touch_count++;
+                               input_report_key(rmi4_data->input_dev,
+                                               f1a->button_map[button],
+                                               status);
+                       } else {
+                               if (status == 1)
+                                       while_2d_status[button] = 1;
+                               else
+                                       while_2d_status[button] = 0;
+                       }
+               }
+#else
+               touch_count++;
+               input_report_key(rmi4_data->input_dev,
+                               f1a->button_map[button],
+                               status);
+#endif
+       }
+
+       if (touch_count)
+               input_sync(rmi4_data->input_dev);
+       mutex_unlock(&rmi4_report_mutex);
+       return;
+}
+
+ /**
+  * synaptics_rmi4_report_touch()
+  *
+  * Called by synaptics_rmi4_sensor_report().
+  *
+  * This function calls the appropriate finger data reporting function
+  * based on the function handler it receives and returns the number of
+  * fingers detected.
+  */
+static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler)
+{
+       unsigned char touch_count_2d;
+
+       dev_dbg(&rmi4_data->i2c_client->dev,
+                       "%s: Function %02x reporting\n",
+                       __func__, fhandler->fn_number);
+
+       switch (fhandler->fn_number) {
+       case SYNAPTICS_RMI4_F11:
+               touch_count_2d = synaptics_rmi4_f11_abs_report(rmi4_data,
+                               fhandler);
+
+               if (touch_count_2d)
+                       rmi4_data->fingers_on_2d = true;
+               else
+                       rmi4_data->fingers_on_2d = false;
+               break;
+       case SYNAPTICS_RMI4_F12:
+               touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data,
+                               fhandler);
+               if (touch_count_2d)
+                       rmi4_data->fingers_on_2d = true;
+               else
+                       rmi4_data->fingers_on_2d = false;
+               break;
+       case SYNAPTICS_RMI4_F1A:
+               synaptics_rmi4_f1a_report(rmi4_data, fhandler);
+               break;
+       default:
+               break;
+       }
+
+       return;
+}
+
+ /**
+  * synaptics_rmi4_sensor_report()
+  *
+  * Called by synaptics_rmi4_irq().
+  *
+  * This function determines the interrupt source(s) from the sensor
+  * and calls synaptics_rmi4_report_touch() with the appropriate
+  * function handler for each function with valid data inputs.
+  */
+static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data)
+{
+       int retval;
+       unsigned char data[MAX_INTR_REGISTERS + 1];
+       unsigned char *intr = &data[1];
+       struct synaptics_rmi4_f01_device_status status;
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+       struct synaptics_rmi4_device_info *rmi;
+
+       rmi = &(rmi4_data->rmi4_mod_info);
+
+       /*
+        * Get interrupt status information from F01 Data1 register to
+        * determine the source(s) that are flagging the interrupt.
+        */
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_data_base_addr,
+                       data,
+                       rmi4_data->num_of_intr_regs + 1);
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to read interrupt status\n",
+                               __func__);
+               return;
+       }
+
+       status.data[0] = data[0];
+       if (status.unconfigured && !status.flash_prog) {
+               pr_notice("%s: spontaneous reset detected\n", __func__);
+               retval = synaptics_rmi4_reinit_device(rmi4_data);
+               if (retval < 0) {
+                       dev_err(&rmi4_data->i2c_client->dev,
+                                       "%s: Failed to reinit device\n",
+                                       __func__);
+               }
+               return;
+       }
+
+       /*
+        * Traverse the function handler list and service the source(s)
+        * of the interrupt accordingly.
+        */
+       if (!list_empty(&rmi->support_fn_list)) {
+               list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+                       if (fhandler->num_of_data_sources) {
+                               if (fhandler->intr_mask &
+                                               intr[fhandler->intr_reg_num]) {
+                                       synaptics_rmi4_report_touch(rmi4_data,
+                                                       fhandler);
+                               }
+                       }
+               }
+       }
+
+       mutex_lock(&exp_data.mutex);
+       if (!list_empty(&exp_data.list)) {
+               list_for_each_entry(exp_fhandler, &exp_data.list, link) {
+                       if (!exp_fhandler->insert &&
+                                       !exp_fhandler->remove &&
+                                       (exp_fhandler->exp_fn->attn != NULL))
+                               exp_fhandler->exp_fn->attn(rmi4_data, intr[0]);
+               }
+       }
+       mutex_unlock(&exp_data.mutex);
+
+       return;
+}
+
+ /**
+  * synaptics_rmi4_irq()
+  *
+  * Called by the kernel when an interrupt occurs (when the sensor
+  * asserts the attention irq).
+  *
+  * This function is the ISR thread and handles the acquisition
+  * and the reporting of finger data when the presence of fingers
+  * is detected.
+  */
+#ifdef CONFIG_OF_TOUCH
+static irqreturn_t tpd_eint_handler(unsigned int irq, struct irq_desc *desc)
+{
+       disable_irq_nosync(touch_irq);
+
+       tpd_flag = 1;
+       wake_up_interruptible(&waiter);
+       return IRQ_HANDLED;
+}
+#else
+static void tpd_eint_handler(void)
+{
+       tpd_flag = 1;
+       wake_up_interruptible(&waiter);
+}
+#endif
+
+static int touch_event_handler(void *data)
+{
+       struct synaptics_rmi4_data *rmi4_data = data;
+
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               while (tpd_halt) {
+                       tpd_flag = 0;
+                       msleep(20);
+               }
+
+               wait_event_interruptible(waiter, tpd_flag != 0);
+
+               tpd_flag = 0;
+               set_current_state(TASK_RUNNING);
+
+               if (!rmi4_data->touch_stopped)
+                       synaptics_rmi4_sensor_report(rmi4_data);
+#ifdef CONFIG_OF_TOUCH
+               enable_irq(touch_irq);
+#else
+               mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
+#endif
+
+       } while (1);
+
+       return 0;
+}
+
+ /**
+  * synaptics_rmi4_irq_enable()
+  *
+  * Called by synaptics_rmi4_probe() and the power management functions
+  * in this driver and also exported to other expansion Function modules
+  * such as rmi_dev.
+  *
+  * This function handles the enabling and disabling of the attention
+  * irq including the setting up of the ISR thread.
+  */
+static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data,
+               bool enable)
+{
+       int retval = 0;
+       unsigned char intr_status[MAX_INTR_REGISTERS];
+
+       if (enable) {
+
+               /* Clear interrupts first */
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               rmi4_data->f01_data_base_addr + 1,
+                               intr_status,
+                               rmi4_data->num_of_intr_regs);
+               if (retval < 0)
+                       return retval;
+
+               /* set up irq */
+               if (!rmi4_data->irq_enabled) {
+#ifdef CONFIG_OF_TOUCH
+                       enable_irq(touch_irq);
+#else
+                       mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
+#endif
+                       rmi4_data->irq_enabled = true;
+
+               }
+
+       } else {
+               if (rmi4_data->irq_enabled) {
+#ifdef CONFIG_OF_TOUCH
+                       disable_irq_nosync(touch_irq);
+#else
+                       mt_eint_mask(CUST_EINT_TOUCH_PANEL_NUM);
+#endif
+                       rmi4_data->irq_enabled = false;
+               }
+       }
+
+       return retval;
+}
+
+static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
+               struct synaptics_rmi4_fn_desc *fd,
+               unsigned int intr_count)
+{
+       unsigned char ii;
+       unsigned char intr_offset;
+
+       fhandler->intr_reg_num = (intr_count + 7) / 8;
+       if (fhandler->intr_reg_num != 0)
+               fhandler->intr_reg_num -= 1;
+
+       /* Set an enable bit for each data source */
+       intr_offset = intr_count % 8;
+       fhandler->intr_mask = 0;
+       for (ii = intr_offset;
+                       ii < ((fd->intr_src_count & MASK_3BIT) +
+                       intr_offset);
+                       ii++)
+               fhandler->intr_mask |= 1 << ii;
+
+       return;
+}
+
+static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler,
+               struct synaptics_rmi4_fn_desc *fd,
+               unsigned int intr_count)
+{
+       fhandler->fn_number = fd->fn_number;
+       fhandler->num_of_data_sources = fd->intr_src_count;
+       fhandler->data = NULL;
+       fhandler->extra = NULL;
+
+       synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+
+       rmi4_data->f01_query_base_addr = fd->query_base_addr;
+       rmi4_data->f01_ctrl_base_addr = fd->ctrl_base_addr;
+       rmi4_data->f01_data_base_addr = fd->data_base_addr;
+       rmi4_data->f01_cmd_base_addr = fd->cmd_base_addr;
+
+       return 0;
+}
+
+ /**
+  * synaptics_rmi4_f11_init()
+  *
+  * Called by synaptics_rmi4_query_device().
+  *
+  * This function 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,
+               unsigned int intr_count)
+{
+       int retval;
+       unsigned char offset;
+       unsigned char fingers_supported;
+       struct synaptics_rmi4_f11_extra_data *extra_data;
+       struct synaptics_rmi4_f11_query_0_5 query_0_5;
+       struct synaptics_rmi4_f11_query_7_8 query_7_8;
+       struct synaptics_rmi4_f11_query_9 query_9;
+       struct synaptics_rmi4_f11_query_12 query_12;
+       struct synaptics_rmi4_f11_query_27 query_27;
+       struct synaptics_rmi4_f11_ctrl_6_9 control_6_9;
+
+       fhandler->fn_number = fd->fn_number;
+       fhandler->num_of_data_sources = fd->intr_src_count;
+       fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+       if (!fhandler->extra) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to alloc mem for fhandle->extra\n",
+                               __func__);
+               return -ENOMEM;
+       }
+       extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.query_base,
+                       query_0_5.data,
+                       sizeof(query_0_5.data));
+       if (retval < 0)
+               return retval;
+
+       /* Maximum number of fingers supported */
+       if (query_0_5.num_of_fingers <= 4)
+               fhandler->num_of_data_points = query_0_5.num_of_fingers + 1;
+       else if (query_0_5.num_of_fingers == 5)
+               fhandler->num_of_data_points = 10;
+
+       rmi4_data->num_of_fingers = fhandler->num_of_data_points;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.ctrl_base + 6,
+                       control_6_9.data,
+                       sizeof(control_6_9.data));
+       if (retval < 0)
+               return retval;
+
+       /* Maximum x and y */
+       rmi4_data->sensor_max_x = SENSOR_MAX_X;
+       rmi4_data->sensor_max_y = SENSOR_MAX_Y; //control_6_9.sensor_max_y_pos_7_0 |
+                       //(control_6_9.sensor_max_y_pos_11_8 << 8);
+
+       /* It's recommended to parse max_x and max_y from contrel register, but this does not match MTK's mtk-tpd.c */
+
+       dev_dbg(&rmi4_data->i2c_client->dev,
+                       "%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);
+
+       fhandler->data = NULL;
+
+       offset = sizeof(query_0_5.data);
+
+       /* query 6 */
+       if (query_0_5.has_rel)
+               offset += 1;
+
+       /* queries 7 8 */
+       if (query_0_5.has_gestures) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               fhandler->full_addr.query_base + offset,
+                               query_7_8.data,
+                               sizeof(query_7_8.data));
+               if (retval < 0)
+                       return retval;
+
+               offset += sizeof(query_7_8.data);
+       }
+
+       /* query 9 */
+       if (query_0_5.has_query_9) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               fhandler->full_addr.query_base + offset,
+                               query_9.data,
+                               sizeof(query_9.data));
+               if (retval < 0)
+                       return retval;
+
+               offset += sizeof(query_9.data);
+       }
+
+       /* query 10 */
+       if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
+               offset += 1;
+
+       /* query 11 */
+       if (query_0_5.has_query_11)
+               offset += 1;
+
+       /* query 12 */
+       if (query_0_5.has_query_12) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               fhandler->full_addr.query_base + offset,
+                               query_12.data,
+                               sizeof(query_12.data));
+               if (retval < 0)
+                       return retval;
+
+               offset += sizeof(query_12.data);
+       }
+
+       /* query 13 */
+       if (query_0_5.has_jitter_filter)
+               offset += 1;
+
+       /* query 14 */
+       if (query_0_5.has_query_12 && query_12.has_general_information_2)
+               offset += 1;
+
+       /* queries 15 16 17 18 19 20 21 22 23 24 25 26*/
+       if (query_0_5.has_query_12 && query_12.has_physical_properties)
+               offset += 12;
+
+       /* query 27 */
+       if (query_0_5.has_query_27) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               fhandler->full_addr.query_base + offset,
+                               query_27.data,
+                               sizeof(query_27.data));
+               if (retval < 0)
+                       return retval;
+
+               rmi4_data->f11_wakeup_gesture = query_27.has_wakeup_gesture;
+       }
+
+       if (!rmi4_data->f11_wakeup_gesture)
+               return retval;
+
+       /* data 0 */
+       fingers_supported = fhandler->num_of_data_points;
+       offset = (fingers_supported + 3) / 4;
+
+       /* data 1 2 3 4 5 */
+       offset += 5 * fingers_supported;
+
+       /* data 6 7 */
+       if (query_0_5.has_rel)
+               offset += 2 * fingers_supported;
+
+       /* data 8 */
+       if (query_0_5.has_gestures && query_7_8.data[0])
+               offset += 1;
+
+       /* data 9 */
+       if (query_0_5.has_gestures && (query_7_8.data[0] || query_7_8.data[1]))
+               offset += 1;
+
+       /* data 10 */
+       if (query_0_5.has_gestures &&
+                       (query_7_8.has_pinch || query_7_8.has_flick))
+               offset += 1;
+
+       /* data 11 12 */
+       if (query_0_5.has_gestures &&
+                       (query_7_8.has_flick || query_7_8.has_rotate))
+               offset += 2;
+
+       /* data 13 */
+       if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
+               offset += (fingers_supported + 3) / 4;
+
+       /* data 14 15 */
+       if (query_0_5.has_gestures &&
+                       (query_7_8.has_scroll_zones ||
+                       query_7_8.has_multi_finger_scroll ||
+                       query_7_8.has_chiral_scroll))
+               offset += 2;
+
+       /* data 16 17 */
+       if (query_0_5.has_gestures &&
+                       (query_7_8.has_scroll_zones &&
+                       query_7_8.individual_scroll_zones))
+               offset += 2;
+
+       /* data 18 19 20 21 22 23 24 25 26 27 */
+       if (query_0_5.has_query_9 && query_9.has_contact_geometry)
+               offset += 10 * fingers_supported;
+
+       /* data 28 */
+       if (query_0_5.has_bending_correction ||
+                       query_0_5.has_large_object_suppression)
+               offset += 1;
+
+       /* data 29 30 31 */
+       if (query_0_5.has_query_9 && query_9.has_pen_hover_discrimination)
+               offset += 3;
+
+       /* data 32 */
+       if (query_0_5.has_query_12 &&
+                       query_12.has_small_object_detection_tuning)
+               offset += 1;
+
+       /* data 33 34 */
+       if (query_0_5.has_query_27 && query_27.f11_query27_b0)
+               offset += 2;
+
+       /* data 35 */
+       if (query_0_5.has_query_12 && query_12.has_8bit_w)
+               offset += fingers_supported;
+
+       /* data 36 */
+       if (query_0_5.has_bending_correction)
+               offset += 1;
+
+       /* data 37 */
+       if (query_0_5.has_query_27 && query_27.has_data_37)
+               offset += 1;
+
+       /* data 38 */
+       if (query_0_5.has_query_27 && query_27.has_wakeup_gesture)
+               extra_data->data38_offset = offset;
+
+       return retval;
+}
+
+static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
+               unsigned short ctrl28)
+{
+       int retval;
+       static unsigned short ctrl_28_address;
+
+       if (ctrl28)
+               ctrl_28_address = ctrl28;
+
+       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                       ctrl_28_address,
+                       &rmi4_data->report_enable,
+                       sizeof(rmi4_data->report_enable));
+       if (retval < 0)
+               return retval;
+
+       return retval;
+}
+
+ /**
+  * synaptics_rmi4_f12_init()
+  *
+  * Called by synaptics_rmi4_query_device().
+  *
+  * This function 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,
+               unsigned int intr_count)
+{
+       int retval;
+       unsigned char size_of_2d_data;
+       unsigned char size_of_query8;
+       unsigned char ctrl_8_offset;
+       unsigned char ctrl_20_offset;
+       unsigned char ctrl_23_offset;
+       unsigned char ctrl_27_offset;
+       unsigned char ctrl_28_offset;
+       unsigned char num_of_fingers;
+       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;
+       fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+       if (!fhandler->extra) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to alloc mem for fhandler->extra\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_i2c_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;
+
+       ctrl_20_offset = ctrl_8_offset +
+                       query_5.ctrl8_is_present +
+                       query_5.ctrl9_is_present +
+                       query_5.ctrl10_is_present +
+                       query_5.ctrl11_is_present +
+                       query_5.ctrl12_is_present +
+                       query_5.ctrl13_is_present +
+                       query_5.ctrl14_is_present +
+                       query_5.ctrl15_is_present +
+                       query_5.ctrl16_is_present +
+                       query_5.ctrl17_is_present +
+                       query_5.ctrl18_is_present +
+                       query_5.ctrl19_is_present;
+
+       ctrl_23_offset = ctrl_20_offset +
+                       query_5.ctrl20_is_present +
+                       query_5.ctrl21_is_present +
+                       query_5.ctrl22_is_present;
+       ctrl_27_offset = ctrl_23_offset +
+                       query_5.ctrl23_is_present +
+                       query_5.ctrl24_is_present +
+                       query_5.ctrl25_is_present +
+                       query_5.ctrl26_is_present;
+       ctrl_28_offset = ctrl_27_offset +
+                       query_5.ctrl27_is_present;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.ctrl_base + ctrl_23_offset,
+                       ctrl_23.data,
+                       sizeof(ctrl_23.data));
+       if (retval < 0)
+               return retval;
+
+       /* Maximum number of fingers supported */
+       fhandler->num_of_data_points = min(ctrl_23.max_reported_objects,
+                       (unsigned char)F12_FINGERS_TO_SUPPORT);
+
+       num_of_fingers = fhandler->num_of_data_points;
+       rmi4_data->num_of_fingers = num_of_fingers;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.query_base + 7,
+                       &size_of_query8,
+                       sizeof(size_of_query8));
+       if (retval < 0)
+               return retval;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.query_base + 8,
+                       query_8.data,
+                       size_of_query8);
+       if (retval < 0)
+               return retval;
+
+       /* Determine the presence of the Data0 register */
+       extra_data->data1_offset = query_8.data0_is_present;
+
+       if ((size_of_query8 >= 3) && (query_8.data15_is_present)) {
+               extra_data->data15_offset = query_8.data0_is_present +
+                               query_8.data1_is_present +
+                               query_8.data2_is_present +
+                               query_8.data3_is_present +
+                               query_8.data4_is_present +
+                               query_8.data5_is_present +
+                               query_8.data6_is_present +
+                               query_8.data7_is_present +
+                               query_8.data8_is_present +
+                               query_8.data9_is_present +
+                               query_8.data10_is_present +
+                               query_8.data11_is_present +
+                               query_8.data12_is_present +
+                               query_8.data13_is_present +
+                               query_8.data14_is_present;
+               extra_data->data15_size = (num_of_fingers + 7) / 8;
+       } else {
+               extra_data->data15_size = 0;
+       }
+
+       rmi4_data->report_enable = RPT_DEFAULT;
+#ifdef REPORT_2D_Z
+       rmi4_data->report_enable |= RPT_Z;
+#endif
+#ifdef REPORT_2D_W
+       rmi4_data->report_enable |= (RPT_WX | RPT_WY);
+#endif
+
+       retval = synaptics_rmi4_f12_set_enables(rmi4_data,
+                       fhandler->full_addr.ctrl_base + ctrl_28_offset);
+       if (retval < 0)
+               return retval;
+
+       retval = synaptics_rmi4_i2c_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 = SENSOR_MAX_X;
+       rmi4_data->sensor_max_y = SENSOR_MAX_Y;
+
+               /* It's recommended to parse max_x and max_y from contrel register, but this does not match MTK's mtk-tpd.c */
+
+       dev_dbg(&rmi4_data->i2c_client->dev,
+                       "%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);
+       rmi4_data->f12_wakeup_gesture = query_5.ctrl27_is_present;
+       if (rmi4_data->f12_wakeup_gesture) {
+               extra_data->ctrl20_offset = ctrl_20_offset;
+               extra_data->data4_offset = query_8.data0_is_present +
+                               query_8.data1_is_present +
+                               query_8.data2_is_present +
+                               query_8.data3_is_present;
+               extra_data->ctrl27_offset = ctrl_27_offset;
+       }
+
+       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->i2c_client->dev,
+                               "%s: Failed to alloc mem for fhandler->data\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       return retval;
+}
+
+static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler)
+{
+       int retval;
+       struct synaptics_rmi4_f1a_handle *f1a;
+
+       f1a = kzalloc(sizeof(*f1a), GFP_KERNEL);
+       if (!f1a) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to alloc mem for function handle\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       fhandler->data = (void *)f1a;
+       fhandler->extra = NULL;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.query_base,
+                       f1a->button_query.data,
+                       sizeof(f1a->button_query.data));
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to read query registers\n",
+                               __func__);
+               return retval;
+       }
+
+       f1a->max_count = f1a->button_query.max_button_count + 1;
+
+       f1a->button_control.txrx_map = kzalloc(f1a->max_count * 2, GFP_KERNEL);
+       if (!f1a->button_control.txrx_map) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to alloc mem for tx rx mapping\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       f1a->button_bitmask_size = (f1a->max_count + 7) / 8;
+
+       f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size,
+                       sizeof(*(f1a->button_data_buffer)), GFP_KERNEL);
+       if (!f1a->button_data_buffer) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to alloc mem for data buffer\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       f1a->button_map = kcalloc(f1a->max_count,
+                       sizeof(*(f1a->button_map)), GFP_KERNEL);
+       if (!f1a->button_map) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to alloc mem for button map\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler)
+{
+       int retval;
+       unsigned char ii;
+       unsigned char mapping_offset = 0;
+       struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+
+       mapping_offset = f1a->button_query.has_general_control +
+                       f1a->button_query.has_interrupt_enable +
+                       f1a->button_query.has_multibutton_select;
+
+       if (f1a->button_query.has_tx_rx_map) {
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               fhandler->full_addr.ctrl_base + mapping_offset,
+                               f1a->button_control.txrx_map,
+                               sizeof(f1a->button_control.txrx_map));
+               if (retval < 0) {
+                       dev_err(&rmi4_data->i2c_client->dev,
+                                       "%s: Failed to read tx rx mapping\n",
+                                       __func__);
+                       return retval;
+               }
+
+               rmi4_data->button_txrx_mapping = f1a->button_control.txrx_map;
+       }
+
+       if (cap_button_map.map) {
+               if (cap_button_map.nbuttons != f1a->max_count) {
+                       f1a->valid_button_count = min(f1a->max_count,
+                                       cap_button_map.nbuttons);
+               } else {
+                       f1a->valid_button_count = f1a->max_count;
+               }
+
+               for (ii = 0; ii < f1a->valid_button_count; ii++)
+                       f1a->button_map[ii] = cap_button_map.map[ii];
+       }
+       return 0;
+}
+
+static void synaptics_rmi4_f1a_kfree(struct synaptics_rmi4_fn *fhandler)
+{
+       struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+
+       if (f1a) {
+               kfree(f1a->button_control.txrx_map);
+               kfree(f1a->button_data_buffer);
+               kfree(f1a->button_map);
+               kfree(f1a);
+               fhandler->data = NULL;
+       }
+
+       return;
+}
+
+static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data,
+               struct synaptics_rmi4_fn *fhandler,
+               struct synaptics_rmi4_fn_desc *fd,
+               unsigned int intr_count)
+{
+       int retval;
+
+       fhandler->fn_number = fd->fn_number;
+       fhandler->num_of_data_sources = fd->intr_src_count;
+
+       synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+
+       retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler);
+       if (retval < 0)
+               goto error_exit;
+
+       retval = synaptics_rmi4_f1a_button_map(rmi4_data, fhandler);
+       if (retval < 0)
+               goto error_exit;
+
+       rmi4_data->button_0d_enabled = 1;
+
+       return 0;
+
+error_exit:
+       synaptics_rmi4_f1a_kfree(fhandler);
+
+       return retval;
+}
+
+static void synaptics_rmi4_empty_fn_list(struct synaptics_rmi4_data *rmi4_data)
+{
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_fn *fhandler_temp;
+       struct synaptics_rmi4_device_info *rmi;
+
+       rmi = &(rmi4_data->rmi4_mod_info);
+
+       if (!list_empty(&rmi->support_fn_list)) {
+               list_for_each_entry_safe(fhandler,
+                               fhandler_temp,
+                               &rmi->support_fn_list,
+                               link) {
+                       if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
+                               synaptics_rmi4_f1a_kfree(fhandler);
+                       } else {
+                               kfree(fhandler->extra);
+                               kfree(fhandler->data);
+                       }
+                       list_del(&fhandler->link);
+                       kfree(fhandler);
+               }
+       }
+       INIT_LIST_HEAD(&rmi->support_fn_list);
+
+       return;
+}
+
+static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
+               bool *was_in_bl_mode)
+{
+       int retval;
+       int timeout = CHECK_STATUS_TIMEOUT_MS;
+       unsigned char command = 0x01;
+       unsigned char intr_status;
+       struct synaptics_rmi4_f01_device_status status;
+
+       /* Do a device reset first */
+       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                       rmi4_data->f01_cmd_base_addr,
+                       &command,
+                       sizeof(command));
+       if (retval < 0)
+               return retval;
+
+       msleep(DELAY_UI_READY);
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_data_base_addr,
+                       status.data,
+                       sizeof(status.data));
+       if (retval < 0)
+               return retval;
+
+       while (status.status_code == STATUS_CRC_IN_PROGRESS) {
+               if (timeout > 0)
+                       msleep(20);
+               else
+                       return -1;
+
+               retval = synaptics_rmi4_i2c_read(rmi4_data,
+                               rmi4_data->f01_data_base_addr,
+                               status.data,
+                               sizeof(status.data));
+               if (retval < 0)
+                       return retval;
+
+               timeout -= 20;
+       }
+
+       if (timeout != CHECK_STATUS_TIMEOUT_MS)
+               *was_in_bl_mode = true;
+
+       if (status.flash_prog == 1) {
+               rmi4_data->flash_prog_mode = true;
+               pr_notice("%s: In flash prog mode, status = 0x%02x\n",
+                               __func__,
+                               status.status_code);
+       } else {
+               rmi4_data->flash_prog_mode = false;
+       }
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_data_base_addr + 1,
+                       &intr_status,
+                       sizeof(intr_status));
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to read interrupt status\n",
+                               __func__);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void synaptics_rmi4_set_configured(struct synaptics_rmi4_data *rmi4_data)
+{
+       int retval;
+       unsigned char device_ctrl;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_ctrl_base_addr,
+                       &device_ctrl,
+                       sizeof(device_ctrl));
+       if (retval < 0) {
+               dev_err(&(rmi4_data->input_dev->dev),
+                               "%s: Failed to set configured\n",
+                               __func__);
+               return;
+       }
+
+       rmi4_data->no_sleep_setting = device_ctrl & NO_SLEEP_ON;
+       device_ctrl |= CONFIGURED;
+
+       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                       rmi4_data->f01_ctrl_base_addr,
+                       &device_ctrl,
+                       sizeof(device_ctrl));
+       if (retval < 0) {
+               dev_err(&(rmi4_data->input_dev->dev),
+                               "%s: Failed to set configured\n",
+                               __func__);
+       }
+
+       return;
+}
+
+static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler,
+               struct synaptics_rmi4_fn_desc *rmi_fd, int page_number)
+{
+       *fhandler = kmalloc(sizeof(**fhandler), GFP_KERNEL);
+       if (!(*fhandler))
+               return -ENOMEM;
+
+       (*fhandler)->full_addr.data_base =
+                       (rmi_fd->data_base_addr |
+                       (page_number << 8));
+       (*fhandler)->full_addr.ctrl_base =
+                       (rmi_fd->ctrl_base_addr |
+                       (page_number << 8));
+       (*fhandler)->full_addr.cmd_base =
+                       (rmi_fd->cmd_base_addr |
+                       (page_number << 8));
+       (*fhandler)->full_addr.query_base =
+                       (rmi_fd->query_base_addr |
+                       (page_number << 8));
+
+       return 0;
+}
+
+ /**
+  * synaptics_rmi4_query_device()
+  *
+  * Called by synaptics_rmi4_probe().
+  *
+  * This function scans the page description table, records the offsets
+  * to the register types of Function $01, sets up the function handlers
+  * for Function $11 and Function $12, determines the number of interrupt
+  * sources from the sensor, adds valid Functions with data inputs to the
+  * Function linked list, parses information from the query registers of
+  * Function $01, and enables the interrupt sources from the valid Functions
+  * with data inputs.
+  */
+static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
+{
+       int retval;
+       unsigned char ii;
+       unsigned char page_number;
+       unsigned char intr_count;
+       unsigned char f01_query[F01_STD_QUERY_LEN];
+       unsigned short pdt_entry_addr;
+       unsigned short intr_addr;
+       bool was_in_bl_mode;
+       struct synaptics_rmi4_fn_desc rmi_fd;
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_device_info *rmi;
+
+       rmi = &(rmi4_data->rmi4_mod_info);
+
+rescan_pdt:
+       was_in_bl_mode = false;
+       intr_count = 0;
+       INIT_LIST_HEAD(&rmi->support_fn_list);
+
+       /* Scan the page description tables of the pages to service */
+       for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
+               for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
+                               pdt_entry_addr -= PDT_ENTRY_SIZE) {
+                       pdt_entry_addr |= (page_number << 8);
+
+                       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                                       pdt_entry_addr,
+                                       (unsigned char *)&rmi_fd,
+                                       sizeof(rmi_fd));
+                       if (retval < 0)
+                               return retval;
+
+                       fhandler = NULL;
+
+                       if (rmi_fd.fn_number == 0) {
+                               dev_dbg(&rmi4_data->i2c_client->dev,
+                                               "%s: Reached end of PDT\n",
+                                               __func__);
+                               break;
+                       }
+
+                       dev_dbg(&rmi4_data->i2c_client->dev,
+                                       "%s: F%02x found (page %d)\n",
+                                       __func__, rmi_fd.fn_number,
+                                       page_number);
+
+                       switch (rmi_fd.fn_number) {
+                       case SYNAPTICS_RMI4_F01:
+                               if (rmi_fd.intr_src_count == 0)
+                                       break;
+
+                               retval = synaptics_rmi4_alloc_fh(&fhandler,
+                                               &rmi_fd, page_number);
+                               if (retval < 0) {
+                                       dev_err(&rmi4_data->i2c_client->dev,
+                                                       "%s: Failed to alloc for F%d\n",
+                                                       __func__,
+                                                       rmi_fd.fn_number);
+                                       return retval;
+                               }
+
+                               retval = synaptics_rmi4_f01_init(rmi4_data,
+                                               fhandler, &rmi_fd, intr_count);
+                               if (retval < 0)
+                                       return retval;
+
+                               retval = synaptics_rmi4_check_status(rmi4_data,
+                                               &was_in_bl_mode);
+                               if (retval < 0) {
+                                       dev_err(&rmi4_data->i2c_client->dev,
+                                                       "%s: Failed to check status\n",
+                                                       __func__);
+                                       return retval;
+                               }
+
+                               if (was_in_bl_mode) {
+                                       kfree(fhandler);
+                                       fhandler = NULL;
+                                       goto rescan_pdt;
+                               }
+
+                               if (rmi4_data->flash_prog_mode)
+                                       goto flash_prog_mode;
+
+                               break;
+                       case SYNAPTICS_RMI4_F11:
+                               if (rmi_fd.intr_src_count == 0)
+                                       break;
+
+                               retval = synaptics_rmi4_alloc_fh(&fhandler,
+                                               &rmi_fd, page_number);
+                               if (retval < 0) {
+                                       dev_err(&rmi4_data->i2c_client->dev,
+                                                       "%s: Failed to alloc for F%d\n",
+                                                       __func__,
+                                                       rmi_fd.fn_number);
+                                       return retval;
+                               }
+
+                               retval = synaptics_rmi4_f11_init(rmi4_data,
+                                               fhandler, &rmi_fd, intr_count);
+                               if (retval < 0)
+                                       return retval;
+                               break;
+                       case SYNAPTICS_RMI4_F12:
+                               if (rmi_fd.intr_src_count == 0)
+                                       break;
+
+                               retval = synaptics_rmi4_alloc_fh(&fhandler,
+                                               &rmi_fd, page_number);
+                               if (retval < 0) {
+                                       dev_err(&rmi4_data->i2c_client->dev,
+                                                       "%s: Failed to alloc for F%d\n",
+                                                       __func__,
+                                                       rmi_fd.fn_number);
+                                       return retval;
+                               }
+
+                               retval = synaptics_rmi4_f12_init(rmi4_data,
+                                               fhandler, &rmi_fd, intr_count);
+                               if (retval < 0)
+                                       return retval;
+                               break;
+                       case SYNAPTICS_RMI4_F1A:
+                               if (rmi_fd.intr_src_count == 0)
+                                       break;
+
+                               retval = synaptics_rmi4_alloc_fh(&fhandler,
+                                               &rmi_fd, page_number);
+                               if (retval < 0) {
+                                       dev_err(&rmi4_data->i2c_client->dev,
+                                                       "%s: Failed to alloc for F%d\n",
+                                                       __func__,
+                                                       rmi_fd.fn_number);
+                                       return retval;
+                               }
+
+                               retval = synaptics_rmi4_f1a_init(rmi4_data,
+                                               fhandler, &rmi_fd, intr_count);
+                               if (retval < 0) {
+#ifdef IGNORE_FN_INIT_FAILURE
+                                       kfree(fhandler);
+                                       fhandler = NULL;
+#else
+                                       return retval;
+#endif
+                               }
+                               break;
+                       }
+
+                       /* Accumulate the interrupt count */
+                       intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+
+                       if (fhandler && rmi_fd.intr_src_count) {
+                               list_add_tail(&fhandler->link,
+                                               &rmi->support_fn_list);
+                       }
+               }
+       }
+
+flash_prog_mode:
+       rmi4_data->num_of_intr_regs = (intr_count + 7) / 8;
+       dev_dbg(&rmi4_data->i2c_client->dev,
+                       "%s: Number of interrupt registers = %d\n",
+                       __func__, rmi4_data->num_of_intr_regs);
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_query_base_addr,
+                       f01_query,
+                       sizeof(f01_query));
+       if (retval < 0)
+               return retval;
+
+       /* RMI Version 4.0 currently supported */
+       rmi->version_major = 4;
+       rmi->version_minor = 0;
+
+       rmi->manufacturer_id = f01_query[0];
+       rmi->product_props = f01_query[1];
+       rmi->product_info[0] = f01_query[2] & MASK_7BIT;
+       rmi->product_info[1] = f01_query[3] & MASK_7BIT;
+       rmi->date_code[0] = f01_query[4] & MASK_5BIT;
+       rmi->date_code[1] = f01_query[5] & MASK_4BIT;
+       rmi->date_code[2] = f01_query[6] & MASK_5BIT;
+       rmi->tester_id = ((f01_query[7] & MASK_7BIT) << 8) |
+                       (f01_query[8] & MASK_7BIT);
+       rmi->serial_number = ((f01_query[9] & MASK_7BIT) << 8) |
+                       (f01_query[10] & MASK_7BIT);
+       memcpy(rmi->product_id_string, &f01_query[11], 10);
+
+       if (rmi->manufacturer_id != 1) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Non-Synaptics device found, manufacturer ID = %d\n",
+                               __func__, rmi->manufacturer_id);
+       }
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET,
+                       rmi->build_id,
+                       sizeof(rmi->build_id));
+       if (retval < 0)
+               return retval;
+
+       rmi4_data->firmware_id = (unsigned int)rmi->build_id[0] +
+                       (unsigned int)rmi->build_id[1] * 0x100 +
+                       (unsigned int)rmi->build_id[2] * 0x10000;
+
+       memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask));
+
+       /*
+        * Map out the interrupt bit masks for the interrupt sources
+        * from the registered function handlers.
+        */
+       if (!list_empty(&rmi->support_fn_list)) {
+               list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+                       if (fhandler->num_of_data_sources) {
+                               rmi4_data->intr_mask[fhandler->intr_reg_num] |=
+                                               fhandler->intr_mask;
+                       }
+               }
+       }
+
+       if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
+               rmi4_data->enable_wakeup_gesture = WAKEUP_GESTURE;
+       else
+               rmi4_data->enable_wakeup_gesture = false;
+
+       /* Enable the interrupt sources */
+       for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
+               if (rmi4_data->intr_mask[ii] != 0x00) {
+                       dev_dbg(&rmi4_data->i2c_client->dev,
+                                       "%s: Interrupt enable mask %d = 0x%02x\n",
+                                       __func__, ii, rmi4_data->intr_mask[ii]);
+                       intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii;
+                       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                                       intr_addr,
+                                       &(rmi4_data->intr_mask[ii]),
+                                       sizeof(rmi4_data->intr_mask[ii]));
+                       if (retval < 0)
+                               return retval;
+               }
+       }
+
+       synaptics_rmi4_set_configured(rmi4_data);
+
+       return 0;
+}
+
+static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data)
+{
+       unsigned char ii;
+       struct synaptics_rmi4_f1a_handle *f1a;
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_device_info *rmi;
+
+       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);
+#ifdef REPORT_2D_W
+       input_set_abs_params(rmi4_data->input_dev,
+                       ABS_MT_TOUCH_MAJOR, 0,
+                       rmi4_data->max_touch_width, 0, 0);
+       input_set_abs_params(rmi4_data->input_dev,
+                       ABS_MT_TOUCH_MINOR, 0,
+                       rmi4_data->max_touch_width, 0, 0);
+#endif
+
+#ifdef TYPE_B_PROTOCOL
+       input_mt_init_slots(rmi4_data->input_dev,
+                       rmi4_data->num_of_fingers, 0);
+#endif
+
+       f1a = NULL;
+       if (!list_empty(&rmi->support_fn_list)) {
+               list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+                       if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
+                               f1a = fhandler->data;
+               }
+       }
+
+       if (f1a) {
+               for (ii = 0; ii < f1a->valid_button_count; ii++) {
+                       set_bit(f1a->button_map[ii],
+                                       rmi4_data->input_dev->keybit);
+                       input_set_capability(rmi4_data->input_dev,
+                                       EV_KEY, f1a->button_map[ii]);
+               }
+       }
+
+       if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) {
+               set_bit(KEY_POWER, rmi4_data->input_dev->keybit);
+               input_set_capability(rmi4_data->input_dev, EV_KEY, KEY_POWER);
+       }
+       return;
+}
+
+static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data)
+{
+       int retval;
+
+       rmi4_data->input_dev = input_allocate_device();
+       if (rmi4_data->input_dev == NULL) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to allocate input device\n",
+                               __func__);
+               retval = -ENOMEM;
+               goto err_input_device;
+       }
+
+       retval = synaptics_rmi4_query_device(rmi4_data);
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to query device\n",
+                               __func__);
+               goto err_query_device;
+       }
+
+       rmi4_data->input_dev->name = DRIVER_NAME;
+       rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
+       rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
+       rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
+       rmi4_data->input_dev->id.bustype = BUS_I2C;
+       rmi4_data->input_dev->dev.parent = &rmi4_data->i2c_client->dev;
+       input_set_drvdata(rmi4_data->input_dev, rmi4_data);
+
+       set_bit(EV_SYN, rmi4_data->input_dev->evbit);
+       set_bit(EV_KEY, rmi4_data->input_dev->evbit);
+       set_bit(EV_ABS, rmi4_data->input_dev->evbit);
+       set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit);
+       set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit);
+#ifdef INPUT_PROP_DIRECT
+       set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
+#endif
+
+       synaptics_rmi4_set_params(rmi4_data);
+
+       retval = input_register_device(rmi4_data->input_dev);
+       if (retval) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to register input device\n",
+                               __func__);
+               goto err_register_input;
+       }
+
+       return 0;
+
+err_register_input:
+err_query_device:
+       synaptics_rmi4_empty_fn_list(rmi4_data);
+       input_free_device(rmi4_data->input_dev);
+
+err_input_device:
+       return retval;
+}
+
+static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data)
+{
+       unsigned char ii;
+       mutex_lock(&rmi4_report_mutex);
+
+#ifdef TYPE_B_PROTOCOL
+       for (ii = 0; ii < rmi4_data->num_of_fingers; ii++) {
+               input_mt_slot(rmi4_data->input_dev, ii);
+               input_mt_report_slot_state(rmi4_data->input_dev,
+                               MT_TOOL_FINGER, 0);
+       }
+#endif
+       input_report_key(rmi4_data->input_dev,
+                       BTN_TOUCH, 0);
+       input_report_key(rmi4_data->input_dev,
+                       BTN_TOOL_FINGER, 0);
+#ifndef TYPE_B_PROTOCOL
+       input_mt_sync(rmi4_data->input_dev);
+#endif
+       input_sync(rmi4_data->input_dev);
+       mutex_unlock(&rmi4_report_mutex);
+       rmi4_data->fingers_on_2d = false;
+
+       return 0;
+}
+
+static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data)
+{
+       int retval;
+       unsigned char ii;
+       unsigned short intr_addr;
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+       struct synaptics_rmi4_device_info *rmi;
+
+       rmi = &(rmi4_data->rmi4_mod_info);
+
+       mutex_lock(&(rmi4_data->rmi4_reset_mutex));
+
+       synaptics_rmi4_free_fingers(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_enables(rmi4_data, 0);
+                               break;
+                       }
+               }
+       }
+
+       for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
+               if (rmi4_data->intr_mask[ii] != 0x00) {
+                       dev_dbg(&rmi4_data->i2c_client->dev,
+                                       "%s: Interrupt enable mask %d = 0x%02x\n",
+                                       __func__, ii, rmi4_data->intr_mask[ii]);
+                       intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii;
+                       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                                       intr_addr,
+                                       &(rmi4_data->intr_mask[ii]),
+                                       sizeof(rmi4_data->intr_mask[ii]));
+                       if (retval < 0)
+                               goto exit;
+               }
+       }
+
+       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->reinit != NULL)
+                               exp_fhandler->exp_fn->reinit(rmi4_data);
+       }
+       mutex_unlock(&exp_data.mutex);
+
+       synaptics_rmi4_set_configured(rmi4_data);
+
+       retval = 0;
+
+exit:
+       mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+       return retval;
+}
+
+static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data)
+{
+       int retval;
+       unsigned char command = 0x01;
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+
+       mutex_lock(&(rmi4_data->rmi4_reset_mutex));
+
+       rmi4_data->touch_stopped = true;
+
+       synaptics_rmi4_irq_enable(rmi4_data, false);
+
+       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                       rmi4_data->f01_cmd_base_addr,
+                       &command,
+                       sizeof(command));
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to issue reset command, error = %d\n",
+                               __func__, retval);
+               mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+               return retval;
+       }
+
+       msleep(DELAY_UI_READY);
+
+       synaptics_rmi4_free_fingers(rmi4_data);
+
+       synaptics_rmi4_empty_fn_list(rmi4_data);
+
+       retval = synaptics_rmi4_query_device(rmi4_data);
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to query device\n",
+                               __func__);
+               mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+               return retval;
+       }
+
+       synaptics_rmi4_set_params(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->reset != NULL)
+                               exp_fhandler->exp_fn->reset(rmi4_data);
+       }
+       mutex_unlock(&exp_data.mutex);
+
+       rmi4_data->touch_stopped = false;
+
+       synaptics_rmi4_irq_enable(rmi4_data, true);
+
+       mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+
+       return 0;
+}
+
+
+static void synaptics_rmi4_sleep_enable(struct synaptics_rmi4_data *rmi4_data,
+               bool enable)
+{
+       int retval;
+       unsigned char device_ctrl;
+       unsigned char no_sleep_setting = rmi4_data->no_sleep_setting;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       rmi4_data->f01_ctrl_base_addr,
+                       &device_ctrl,
+                       sizeof(device_ctrl));
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to read device control\n",
+                               __func__);
+               return;
+       }
+
+       device_ctrl = device_ctrl & ~MASK_3BIT;
+       if (enable)
+               device_ctrl = device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP;
+       else
+               device_ctrl = device_ctrl | no_sleep_setting | NORMAL_OPERATION;
+
+       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                       rmi4_data->f01_ctrl_base_addr,
+                       &device_ctrl,
+                       sizeof(device_ctrl));
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to write device control\n",
+                               __func__);
+               return;
+       }
+
+       rmi4_data->sensor_sleep = enable;
+
+       return;
+}
+
+
+
+
+/**
+ * synaptics_rmi4_exp_fn_work()
+ *
+ * Called by the kernel at the scheduled time.
+ *
+ * This function is a work thread that checks for the insertion and
+ * removal of other expansion Function modules such as rmi_dev and calls
+ * their initialization and removal callback functions accordingly.
+ */
+static void synaptics_rmi4_exp_fn_work(struct work_struct *work)
+{
+       int retval;
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler_temp;
+       struct synaptics_rmi4_data *rmi4_data = exp_data.rmi4_data;
+
+       mutex_lock(&exp_data.mutex);
+       if (!list_empty(&exp_data.list)) {
+               list_for_each_entry_safe(exp_fhandler,
+                               exp_fhandler_temp,
+                               &exp_data.list,
+                               link) {
+                       if ((exp_fhandler->exp_fn->init != NULL) &&
+                                       exp_fhandler->insert) {
+                               retval = exp_fhandler->exp_fn->init(rmi4_data);
+                               if (retval < 0) {
+                                       list_del(&exp_fhandler->link);
+                                       kfree(exp_fhandler);
+                               } else {
+                                       exp_fhandler->insert = false;
+                               }
+                       } else if ((exp_fhandler->exp_fn->remove != NULL) &&
+                                       exp_fhandler->remove) {
+                               exp_fhandler->exp_fn->remove(rmi4_data);
+                               list_del(&exp_fhandler->link);
+                               kfree(exp_fhandler);
+                       }
+               }
+       }
+       mutex_unlock(&exp_data.mutex);
+
+       return;
+}
+
+/**
+ * synaptics_rmi4_new_function()
+ *
+ * Called by other expansion Function modules in their module init and
+ * module exit functions.
+ *
+ * This function is used by other expansion Function modules such as
+ * rmi_dev to register themselves with the driver by providing their
+ * initialization and removal callback function pointers so that they
+ * 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,
+               bool insert)
+{
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+
+       if (!exp_data.initialized) {
+               mutex_init(&exp_data.mutex);
+               INIT_LIST_HEAD(&exp_data.list);
+               exp_data.initialized = true;
+       }
+
+       mutex_lock(&exp_data.mutex);
+       if (insert) {
+               exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL);
+               if (!exp_fhandler) {
+                       pr_err("%s: Failed to alloc mem for expansion function\n",
+                                       __func__);
+                       goto exit;
+               }
+               exp_fhandler->exp_fn = exp_fn;
+               exp_fhandler->insert = true;
+               exp_fhandler->remove = false;
+               list_add_tail(&exp_fhandler->link, &exp_data.list);
+       } else if (!list_empty(&exp_data.list)) {
+               list_for_each_entry(exp_fhandler, &exp_data.list, link) {
+                       if (exp_fhandler->exp_fn->fn_type == exp_fn->fn_type) {
+                               exp_fhandler->insert = false;
+                               exp_fhandler->remove = true;
+                               goto exit;
+                       }
+               }
+       }
+
+exit:
+       mutex_unlock(&exp_data.mutex);
+
+       if (exp_data.queue_work) {
+               queue_delayed_work(exp_data.workqueue,
+                               &exp_data.work,
+                               msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
+       }
+
+       return;
+}
+EXPORT_SYMBOL(synaptics_rmi4_new_function);
+
+
+static ssize_t synaptics_rmi4_f34_configid_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "0x%x\n", rmi4_data->config_id);
+}
+
+
+
+static ssize_t synaptics_rmi4_f01_product_id_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       (rmi4_data->rmi4_mod_info.product_id_string));
+}
+
+
+static DEVICE_ATTR(tp_firmware_version, 0664, synaptics_rmi4_f34_configid_show, synaptics_rmi4_store_error);
+static DEVICE_ATTR(product_id, 0664, synaptics_rmi4_f01_product_id_show, synaptics_rmi4_store_error);
+
+static struct attribute *synaptics_rmi4_attrs[] = {
+       attrify(tp_firmware_version),
+       attrify(product_id),
+       NULL,
+};
+
+static struct attribute_group attr_group = {
+       .attrs = synaptics_rmi4_attrs,
+};
+ /**
+  * synaptics_rmi4_probe()
+  *
+  * Called by the kernel when an association with an I2C device of the
+  * same name is made (after doing i2c_add_driver).
+  *
+  * This function allocates and initializes the resources for the driver
+  * as an input driver, turns on the power to the sensor, queries the
+  * sensor for its supported Functions and characteristics, registers
+  * the driver to the input subsystem, sets up the interrupt, handles
+  * the registration of the early_suspend and late_resume functions,
+  * and creates a work queue for detection of other expansion Function
+  * modules.
+  */
+static int synaptics_rmi4_probe(struct i2c_client *client,
+               const struct i2c_device_id *dev_id)
+{
+       int retval, ret;
+       unsigned char attr_count;
+       struct synaptics_rmi4_data *rmi4_data;
+       struct device_node *np = client->dev.of_node;
+#if 0
+       int rst_gpio;
+#endif
+
+       if (!i2c_check_functionality(client->adapter,
+                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev,
+                               "%s: SMBus byte data not supported\n",
+                               __func__);
+               return -EIO;
+       }
+
+#ifdef USE_I2C_DMA
+       wDMABuf_va = (unsigned char *)dma_zalloc_coherent(&client->dev, WRITE_SIZE_LIMIT,
+                                &wDMABuf_pa, GFP_KERNEL);
+       if (!wDMABuf_va) {
+               dev_err(&client->dev, "Allocate DMA I2C Buffer failed, exit\n");
+               return -ENOMEM;
+       }
+#endif
+
+       if (!np)
+               return -ENODEV;
+#if 0
+       rst_gpio = of_get_named_gpio(np, "rest-gpios", 0);
+       if (!gpio_is_valid(rst_gpio))
+               return -ENODEV;
+
+       ret = gpio_request(rst_gpio, "synaptics_rmi4_rest");
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "request rest gpio failed, cannot wake up controller: %d\n",
+                       ret);
+               return ret;
+       }
+
+       gpio_direction_output(rst_gpio, 0);
+       gpio_set_value(rst_gpio, 1);
+       msleep(DELAY_BOOT_READY);
+       gpio_set_value(rst_gpio, 0);
+       msleep(DELAY_RESET_LOW);
+       gpio_set_value(rst_gpio, 1);
+       msleep(DELAY_UI_READY);
+#endif
+
+       rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL);
+       if (!rmi4_data) {
+               dev_err(&client->dev,
+                               "%s: Failed to alloc mem for rmi4_data\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       rmi4_data->i2c_client = client;
+       rmi4_data->current_page = MASK_8BIT;
+       rmi4_data->touch_stopped = false;
+       rmi4_data->sensor_sleep = false;
+       rmi4_data->irq_enabled = false;
+       rmi4_data->fingers_on_2d = false;
+
+       rmi4_data->i2c_read = synaptics_rmi4_i2c_read;
+       rmi4_data->i2c_write = synaptics_rmi4_i2c_write;
+       rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
+       rmi4_data->reset_device = synaptics_rmi4_reset_device;
+       rmi4_data->sleep_enable = synaptics_rmi4_sleep_enable;
+
+       rmi4_data->i2c_addr = client->addr;
+
+       mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
+       mutex_init(&(rmi4_data->rmi4_reset_mutex));
+       mutex_init(&(rmi4_data->rmi4_exp_init_mutex));
+
+       i2c_set_clientdata(client, rmi4_data);
+       retval = synaptics_rmi4_set_input_dev(rmi4_data);
+       if (retval < 0) {
+               dev_err(&client->dev,
+                               "%s: Failed to set up input device\n",
+                               __func__);
+               goto err_set_input_dev;
+       }
+
+       thread = kthread_run(touch_event_handler, rmi4_data, "synaptics_dsx");
+       if (IS_ERR(thread)) {
+               retval = PTR_ERR(thread);
+               pr_err(" %s: failed to create kernel thread: %d\n", __func__, retval);
+       }
+
+       touch_irq = client->irq;
+       ret = devm_request_irq(&client->dev, touch_irq, (irq_handler_t) tpd_eint_handler,
+                               IRQF_TRIGGER_LOW, "synaptics_rmi4_touch", NULL);
+
+       disable_irq_nosync(touch_irq);
+       retval = synaptics_rmi4_irq_enable(rmi4_data, true);
+       if (retval < 0) {
+               dev_err(&client->dev,
+                               "%s: Failed to register attention interrupt\n",
+                               __func__);
+               goto err_enable_irq;
+       }
+
+       if (!exp_data.initialized) {
+               mutex_init(&exp_data.mutex);
+               INIT_LIST_HEAD(&exp_data.list);
+               exp_data.initialized = true;
+       }
+
+
+       exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
+       INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
+       exp_data.rmi4_data = rmi4_data;
+       exp_data.queue_work = true;
+       queue_delayed_work(exp_data.workqueue,
+                       &exp_data.work,
+                       msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
+
+       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);
+               if (retval < 0) {
+                       dev_err(&client->dev,
+                                       "%s: Failed to create sysfs attributes\n",
+                                       __func__);
+                       goto err_sysfs;
+               }
+       }
+
+       retval = sysfs_create_group(&client->dev.kobj, &attr_group);
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to create sysfs attributes\n",
+                               __func__);
+               goto err_sysfs;
+       }
+
+       g_dev = &rmi4_data->input_dev->dev;
+
+       return retval;
+
+err_sysfs:
+       sysfs_remove_group(&client->dev.kobj, &attr_group);
+       for (attr_count--; attr_count >= 0; attr_count--) {
+               sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+                               &attrs[attr_count].attr);
+       }
+
+       cancel_delayed_work_sync(&exp_data.work);
+       flush_workqueue(exp_data.workqueue);
+       destroy_workqueue(exp_data.workqueue);
+
+       synaptics_rmi4_irq_enable(rmi4_data, false);
+
+err_enable_irq:
+
+       synaptics_rmi4_empty_fn_list(rmi4_data);
+       input_unregister_device(rmi4_data->input_dev);
+       rmi4_data->input_dev = NULL;
+
+err_set_input_dev:
+       kfree(rmi4_data);
+
+       return retval;
+}
+
+ /**
+  * synaptics_rmi4_remove()
+  *
+  * Called by the kernel when the association with an I2C device of the
+  * same name is broken (when the driver is unloaded).
+  *
+  * This function terminates the work queue, stops sensor data acquisition,
+  * frees the interrupt, unregisters the driver from the input subsystem,
+  * turns off the power to the sensor, and frees other allocated resources.
+  */
+static int synaptics_rmi4_remove(struct i2c_client *client)
+{
+       unsigned char attr_count;
+       struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+
+       for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+               sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+                               &attrs[attr_count].attr);
+       }
+
+       cancel_delayed_work_sync(&exp_data.work);
+       flush_workqueue(exp_data.workqueue);
+       destroy_workqueue(exp_data.workqueue);
+
+       synaptics_rmi4_irq_enable(rmi4_data, false);
+
+       synaptics_rmi4_empty_fn_list(rmi4_data);
+       input_unregister_device(rmi4_data->input_dev);
+       rmi4_data->input_dev = NULL;
+
+#ifdef USE_I2C_DMA
+       if (wDMABuf_va)
+               dma_free_coherent(&client->dev, WRITE_SIZE_LIMIT, wDMABuf_va, wDMABuf_pa);
+#endif
+
+       kfree(rmi4_data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static void synaptics_rmi4_f11_wg(struct synaptics_rmi4_data *rmi4_data,
+               bool enable)
+{
+       int retval;
+       unsigned char reporting_control;
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_device_info *rmi;
+
+       rmi = &(rmi4_data->rmi4_mod_info);
+
+       list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+               if (fhandler->fn_number == SYNAPTICS_RMI4_F11)
+                       break;
+       }
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.ctrl_base,
+                       &reporting_control,
+                       sizeof(reporting_control));
+       if (retval < 0) {
+               dev_err(&(rmi4_data->input_dev->dev),
+                               "%s: Failed to change reporting mode\n",
+                               __func__);
+               return;
+       }
+
+       reporting_control = (reporting_control & ~MASK_3BIT);
+       if (enable)
+               reporting_control |= F11_WAKEUP_GESTURE_MODE;
+       else
+               reporting_control |= F11_CONTINUOUS_MODE;
+
+       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                       fhandler->full_addr.ctrl_base,
+                       &reporting_control,
+                       sizeof(reporting_control));
+       if (retval < 0) {
+               dev_err(&(rmi4_data->input_dev->dev),
+                               "%s: Failed to change reporting mode\n",
+                               __func__);
+               return;
+       }
+
+       return;
+}
+
+static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data,
+               bool enable)
+{
+       int retval;
+       unsigned char offset;
+       unsigned char reporting_control[3];
+       struct synaptics_rmi4_f12_extra_data *extra_data;
+       struct synaptics_rmi4_fn *fhandler;
+       struct synaptics_rmi4_device_info *rmi;
+
+       rmi = &(rmi4_data->rmi4_mod_info);
+
+       list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+               if (fhandler->fn_number == SYNAPTICS_RMI4_F12)
+                       break;
+       }
+
+       extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+       offset = extra_data->ctrl20_offset;
+
+       retval = synaptics_rmi4_i2c_read(rmi4_data,
+                       fhandler->full_addr.ctrl_base + offset,
+                       reporting_control,
+                       sizeof(reporting_control));
+       if (retval < 0) {
+               dev_err(&(rmi4_data->input_dev->dev),
+                               "%s: Failed to change reporting mode\n",
+                               __func__);
+               return;
+       }
+
+       if (enable)
+               reporting_control[2] = F12_WAKEUP_GESTURE_MODE;
+       else
+               reporting_control[2] = F12_CONTINUOUS_MODE;
+
+       retval = synaptics_rmi4_i2c_write(rmi4_data,
+                       fhandler->full_addr.ctrl_base + offset,
+                       reporting_control,
+                       sizeof(reporting_control));
+       if (retval < 0) {
+               dev_err(&(rmi4_data->input_dev->dev),
+                               "%s: Failed to change reporting mode\n",
+                               __func__);
+               return;
+       }
+
+       return;
+}
+
+static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data,
+               bool enable)
+{
+       if (rmi4_data->f11_wakeup_gesture)
+               synaptics_rmi4_f11_wg(rmi4_data, enable);
+       else if (rmi4_data->f12_wakeup_gesture)
+               synaptics_rmi4_f12_wg(rmi4_data, enable);
+
+       return;
+}
+
+ /**
+  * 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 __maybe_unused synaptics_rmi4_suspend(struct device *dev)
+{
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(g_dev);
+
+       if (rmi4_data->staying_awake)
+               return 0;
+
+       if (rmi4_data->enable_wakeup_gesture) {
+               synaptics_rmi4_wakeup_gesture(rmi4_data, true);
+               goto exit;
+       }
+
+       if (!rmi4_data->sensor_sleep) {
+               rmi4_data->touch_stopped = true;
+               synaptics_rmi4_irq_enable(rmi4_data, false);
+               synaptics_rmi4_sleep_enable(rmi4_data, true);
+               synaptics_rmi4_free_fingers(rmi4_data);
+       }
+
+       tpd_halt = 1;
+
+exit:
+       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);
+
+
+       rmi4_data->sensor_sleep = true;
+
+       return 0;
+}
+
+ /**
+  * synaptics_rmi4_resume()
+  *
+  * Called by the kernel during the resume phase when the system
+  * wakes up from suspend.
+  *
+  * This function turns on the power to the sensor, wakes the sensor
+  * from sleep, enables the interrupt, and starts finger data
+  * acquisition.
+  */
+static int __maybe_unused synaptics_rmi4_resume(struct device *dev)
+{
+       int retval;
+       struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(g_dev);
+
+       if (rmi4_data->staying_awake)
+               return 0;
+
+       if (rmi4_data->enable_wakeup_gesture) {
+               synaptics_rmi4_wakeup_gesture(rmi4_data, false);
+               goto exit;
+       }
+
+       synaptics_rmi4_sleep_enable(rmi4_data, false);
+       synaptics_rmi4_irq_enable(rmi4_data, true);
+       retval = synaptics_rmi4_reinit_device(rmi4_data);
+       if (retval < 0) {
+               dev_err(&rmi4_data->i2c_client->dev,
+                               "%s: Failed to reinit device\n",
+                               __func__);
+               return 0;
+       }
+exit:
+       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->resume != NULL)
+                               exp_fhandler->exp_fn->resume(rmi4_data);
+       }
+       mutex_unlock(&exp_data.mutex);
+
+
+       rmi4_data->sensor_sleep = false;
+       rmi4_data->touch_stopped = false;
+       tpd_halt = 0;
+
+       return 0;
+}
+
+#endif
+
+static const struct i2c_device_id synaptics_rmi4_id_table[] = {
+       {"synaptics_dsx", 0},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+
+static SIMPLE_DEV_PM_OPS(synaptics_rmi4_pm_ops, synaptics_rmi4_suspend, synaptics_rmi4_resume);
+
+
+static const struct of_device_id synaptics_rmi4_dt_ids[] = {
+       { .compatible = "synaptics_dsx" },
+       { /* sentinel */},
+};
+
+static struct i2c_driver synaptics_rmi4_driver = {
+       .driver = {
+               .name   = "synaptics_dsx",
+               .pm     = &synaptics_rmi4_pm_ops,
+               .of_match_table = synaptics_rmi4_dt_ids,
+       },
+       .id_table       = synaptics_rmi4_id_table,
+       .probe          = synaptics_rmi4_probe,
+       .remove         = synaptics_rmi4_remove,
+};
+
+module_i2c_driver(synaptics_rmi4_driver);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("Synaptics DSX I2C Touch Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.h
new file mode 100644 (file)
index 0000000..d2d7381
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * Synaptics DSX touchscreen driver
+ *
+ * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
+ * DOLLARS.
+ */
+#ifndef _SYNAPTICS_DSX_RMI4_H_
+#define _SYNAPTICS_DSX_RMI4_H_
+
+#define SYNAPTICS_DS4 (1 << 0)
+#define SYNAPTICS_DS5 (1 << 1)
+#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5)
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x2000
+#define SYNAPTICS_MTK_DRIVER_VERSION 0x6043
+
+#include <linux/version.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#ifdef CONFIG_OF
+#define CONFIG_OF_TOUCH
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
+#define KERNEL_ABOVE_2_6_38
+#endif
+
+#ifdef KERNEL_ABOVE_2_6_38
+#define sstrtoul(...) kstrtoul(__VA_ARGS__)
+#else
+#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
+#endif
+
+#define WRITE_SIZE_LIMIT 1024
+
+extern unsigned char g_log_enable;
+#define TP_DEBUG(fmt, arg...)          do {\
+                                               if (g_log_enable)\
+                                               printk("%s %d " fmt, __func__, __LINE__, ##arg);\
+                                       } while (0)
+#define PDT_PROPS (0X00EF)
+#define PDT_START (0x00E9)
+#define PDT_END (0x00D0)
+#define PDT_ENTRY_SIZE (0x0006)
+#define PAGES_TO_SERVICE (10)
+#define PAGE_SELECT_LEN (2)
+#define ADDRESS_WORD_LEN (2)
+
+#define SYNAPTICS_RMI4_F01 (0x01)
+#define SYNAPTICS_RMI4_F11 (0x11)
+#define SYNAPTICS_RMI4_F12 (0x12)
+#define SYNAPTICS_RMI4_F1A (0x1a)
+#define SYNAPTICS_RMI4_F34 (0x34)
+#define SYNAPTICS_RMI4_F35 (0x35)
+#define SYNAPTICS_RMI4_F38 (0x38)
+#define SYNAPTICS_RMI4_F51 (0x51)
+#define SYNAPTICS_RMI4_F54 (0x54)
+#define SYNAPTICS_RMI4_F55 (0x55)
+#define SYNAPTICS_RMI4_FDB (0xdb)
+
+#define SYNAPTICS_RMI4_DATE_CODE_SIZE 3
+#define PRODUCT_INFO_SIZE 2
+#define PRODUCT_ID_SIZE 10
+#define BUILD_ID_SIZE 3
+
+#define F12_FINGERS_TO_SUPPORT 10
+#define F12_NO_OBJECT_STATUS 0x00
+#define F12_FINGER_STATUS 0x01
+#define F12_STYLUS_STATUS 0x02
+#define F12_PALM_STATUS 0x03
+#define F12_HOVERING_FINGER_STATUS 0x05
+#define F12_GLOVED_FINGER_STATUS 0x06
+
+#define F12_GESTURE_DETECTION_LEN 5
+
+
+#define MAX_NUMBER_OF_BUTTONS 4
+#define MAX_INTR_REGISTERS 4
+
+#define MASK_16BIT 0xFFFF
+#define MASK_8BIT 0xFF
+#define MASK_7BIT 0x7F
+#define MASK_6BIT 0x3F
+#define MASK_5BIT 0x1F
+#define MASK_4BIT 0x0F
+#define MASK_3BIT 0x07
+#define MASK_2BIT 0x03
+#define MASK_1BIT 0x01
+
+enum exp_fn {
+       RMI_DEV = 0,
+       RMI_F54,
+       RMI_FW_UPDATER,
+       RMI_PROXIMITY,
+       RMI_ACTIVE_PEN,
+       RMI_GESTURE,
+       RMI_LAST,
+};
+
+/*
+ * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT entry
+ * @query_base_addr: base address for query registers
+ * @cmd_base_addr: base address for command registers
+ * @ctrl_base_addr: base address for control registers
+ * @data_base_addr: base address for data registers
+ * @intr_src_count: number of interrupt sources
+ * @fn_version: version of function
+ * @fn_number: function number
+ */
+struct synaptics_rmi4_fn_desc {
+       union {
+               struct {
+                       unsigned char query_base_addr;
+                       unsigned char cmd_base_addr;
+                       unsigned char ctrl_base_addr;
+                       unsigned char data_base_addr;
+                       unsigned char intr_src_count:3;
+                       unsigned char reserved_1:2;
+                       unsigned char fn_version:2;
+                       unsigned char reserved_2:1;
+                       unsigned char fn_number;
+               } __packed;
+               unsigned char data[6];
+       };
+};
+
+/*
+ * synaptics_rmi4_fn_full_addr - full 16-bit base addresses
+ * @query_base: 16-bit base address for query registers
+ * @cmd_base: 16-bit base address for command registers
+ * @ctrl_base: 16-bit base address for control registers
+ * @data_base: 16-bit base address for data registers
+ */
+struct synaptics_rmi4_fn_full_addr {
+       unsigned short query_base;
+       unsigned short cmd_base;
+       unsigned short ctrl_base;
+       unsigned short data_base;
+};
+
+/*
+ * struct synaptics_rmi4_f11_extra_data - extra data of F$11
+ * @data38_offset: offset to F11_2D_DATA38 register
+ */
+struct synaptics_rmi4_f11_extra_data {
+       unsigned char data38_offset;
+};
+
+/*
+ * struct synaptics_rmi4_f12_extra_data - extra data of F$12
+ * @data1_offset: offset to F12_2D_DATA01 register
+ * @data4_offset: offset to F12_2D_DATA04 register
+ * @data15_offset: offset to F12_2D_DATA15 register
+ * @data15_size: size of F12_2D_DATA15 register
+ * @data15_data: buffer for reading F12_2D_DATA15 register
+ * @ctrl20_offset: offset to F12_2D_CTRL20 register
+ */
+struct synaptics_rmi4_f12_extra_data {
+       unsigned char data1_offset;
+       unsigned char data4_offset;
+       unsigned char data15_offset;
+       unsigned char data15_size;
+       unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
+       unsigned char ctrl20_offset;
+       unsigned char ctrl27_offset;
+};
+
+/*
+ * struct synaptics_rmi4_fn - RMI function handler
+ * @fn_number: function number
+ * @num_of_data_sources: number of data sources
+ * @num_of_data_points: maximum number of fingers supported
+ * @intr_reg_num: index to associated interrupt register
+ * @intr_mask: interrupt mask
+ * @full_addr: full 16-bit base addresses of function registers
+ * @link: linked list for function handlers
+ * @data_size: size of private data
+ * @data: pointer to private data
+ * @extra: pointer to extra data
+ */
+struct synaptics_rmi4_fn {
+       unsigned char fn_number;
+       unsigned char num_of_data_sources;
+       unsigned char num_of_data_points;
+       unsigned char intr_reg_num;
+       unsigned char intr_mask;
+       struct synaptics_rmi4_fn_full_addr full_addr;
+       struct list_head link;
+       int data_size;
+       void *data;
+       void *extra;
+};
+
+/*
+ * struct synaptics_rmi4_device_info - device information
+ * @version_major: RMI protocol major version number
+ * @version_minor: RMI protocol minor version number
+ * @manufacturer_id: manufacturer ID
+ * @product_props: product properties
+ * @product_info: product information
+ * @product_id_string: product ID
+ * @build_id: firmware build ID
+ * @support_fn_list: linked list for function handlers
+ */
+struct synaptics_rmi4_device_info {
+       unsigned int version_major;
+       unsigned int version_minor;
+       unsigned char manufacturer_id;
+       unsigned char product_props;
+       unsigned char product_info[PRODUCT_INFO_SIZE];
+       unsigned char date_code[SYNAPTICS_RMI4_DATE_CODE_SIZE];
+       unsigned short tester_id;
+       unsigned short serial_number;
+       unsigned char product_id_string[PRODUCT_ID_SIZE + 1];
+       unsigned char build_id[BUILD_ID_SIZE];
+       struct list_head support_fn_list;
+};
+
+/*
+ * struct synaptics_rmi4_data - rmi4 device instance data
+ * @i2c_client: pointer to associated i2c client
+ * @input_dev: pointer to associated input device
+ * @board: constant pointer to platform data
+ * @rmi4_mod_info: device information
+ * @regulator: pointer to associated 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 access
+ * @button_0d_enabled: flag for 0d button support
+ * @full_pm_cycle: flag for full power management cycle in early suspend stage
+ * @num_of_intr_regs: number of interrupt registers
+ * @f01_query_base_addr: query base address for f01
+ * @f01_cmd_base_addr: command base address for f01
+ * @f01_ctrl_base_addr: control base address for f01
+ * @f01_data_base_addr: data base address for f01
+ * @irq: attention interrupt
+ * @sensor_max_x: sensor maximum x value
+ * @sensor_max_y: sensor maximum y value
+ * @irq_enabled: flag for indicating interrupt enable status
+ * @fingers_on_2d: flag to indicate presence of fingers in 2d area
+ * @sensor_sleep: flag to indicate sleep state of sensor
+ * @wait: wait queue for touch data polling in interrupt thread
+ * @i2c_read: pointer to i2c read function
+ * @i2c_write: pointer to i2c write function
+ * @irq_enable: pointer to irq enable function
+ */
+struct synaptics_rmi4_data {
+       struct i2c_client *i2c_client;
+       struct input_dev *input_dev;
+       const struct synaptics_dsx_platform_data *board;
+       struct synaptics_rmi4_device_info rmi4_mod_info;
+       struct regulator *regulator;
+       struct mutex rmi4_reset_mutex;
+       struct mutex rmi4_io_ctrl_mutex;
+       struct mutex rmi4_exp_init_mutex;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       struct early_suspend early_suspend;
+#endif
+       unsigned char i2c_addr;
+       unsigned char current_page;
+       unsigned char button_0d_enabled;
+       unsigned char full_pm_cycle;
+       unsigned char num_of_rx;
+       unsigned char num_of_tx;
+       unsigned char num_of_fingers;
+       unsigned char max_touch_width;
+       unsigned char report_enable;
+       unsigned char no_sleep_setting;
+       unsigned char intr_mask[MAX_INTR_REGISTERS];
+       unsigned char *button_txrx_mapping;
+       unsigned short num_of_intr_regs;
+       unsigned short f01_query_base_addr;
+       unsigned short f01_cmd_base_addr;
+       unsigned short f01_ctrl_base_addr;
+       unsigned short f01_data_base_addr;
+       unsigned int firmware_id;
+       unsigned int config_id;
+       int irq;
+       int sensor_max_x;
+       int sensor_max_y;
+       bool flash_prog_mode;
+       bool irq_enabled;
+       bool touch_stopped;
+       bool fingers_on_2d;
+       bool sensor_sleep;
+       bool stay_awake;
+       bool f11_wakeup_gesture;
+       bool f12_wakeup_gesture;
+       bool enable_wakeup_gesture;
+       bool staying_awake;
+       bool ext_afe_button;
+       unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN];
+       int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
+                       unsigned char *data, unsigned short length);
+       int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr,
+                       unsigned char *data, unsigned short length);
+       int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
+       int (*reset_device)(struct synaptics_rmi4_data *rmi4_data);
+       void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data,
+                       bool enable);
+};
+
+struct synaptics_rmi4_exp_fn {
+       enum exp_fn fn_type;
+       int (*init)(struct synaptics_rmi4_data *rmi4_data);
+       void (*remove)(struct synaptics_rmi4_data *rmi4_data);
+       void (*reset)(struct synaptics_rmi4_data *rmi4_data);
+       void (*reinit)(struct synaptics_rmi4_data *rmi4_data);
+       void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data);
+       void (*suspend)(struct synaptics_rmi4_data *rmi4_data);
+       void (*resume)(struct synaptics_rmi4_data *rmi4_data);
+       void (*late_resume)(struct synaptics_rmi4_data *rmi4_data);
+       void (*attn)(struct synaptics_rmi4_data *rmi4_data,
+                       unsigned char intr_mask);
+};
+
+struct synaptics_rmi4_access_ptr {
+       int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
+                       unsigned char *data, unsigned short length);
+       int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
+                       unsigned char *data, unsigned short length);
+       int (*enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
+};
+
+static inline int synaptics_rmi4_reg_read(
+               struct synaptics_rmi4_data *rmi4_data,
+               unsigned short addr,
+               unsigned char *data,
+               unsigned short len)
+{
+       return rmi4_data->i2c_read(rmi4_data, addr, data, len);
+}
+
+static inline int synaptics_rmi4_reg_write(
+               struct synaptics_rmi4_data *rmi4_data,
+               unsigned short addr,
+               unsigned char *data,
+               unsigned short len)
+{
+       return rmi4_data->i2c_write(rmi4_data, addr, data, len);
+}
+
+
+
+void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module,
+               bool insert);
+
+int synaptics_fw_updater(const unsigned char *fw_data);
+
+static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
+                       __func__, attr->attr.name);
+       return -EPERM;
+}
+
+static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       dev_warn(dev, "%s Attempted to write to read-only attribute %s\n",
+                       __func__, attr->attr.name);
+       return -EPERM;
+}
+
+static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
+               const unsigned char *src, unsigned int src_size,
+               unsigned int count)
+{
+       if (dest == NULL || src == NULL)
+               return -EINVAL;
+
+       if (count > dest_size || count > src_size)
+               return -EINVAL;
+
+       memcpy((void *)dest, (const void *)src, count);
+
+       return 0;
+}
+
+static inline void batohs(unsigned short *dest, unsigned char *src)
+{
+       *dest = src[1] * 0x100 + src[0];
+}
+
+static inline void hstoba(unsigned char *dest, unsigned short src)
+{
+       dest[0] = src % 0x100;
+       dest[1] = src / 0x100;
+}
+
+#endif