--- /dev/null
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include <linux/earlysuspend.h>
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/input/mt.h>
+
+#include <mach/gpio.h>
+#include <mach/board.h>
+
+#include "synaptics_i2c_rmi4.h"
+
+/* TODO: for multiple device support will need a per-device mutex */
+#define DRIVER_NAME "synaptics_rmi4_i2c"
+
+#define MAX_ERROR_REPORT 6
+#define MAX_TOUCH_MAJOR 15
+#define MAX_RETRY_COUNT 5
+#define STD_QUERY_LEN 21
+#define PAGE_LEN 2
+#define DATA_BUF_LEN 32
+#define BUF_LEN 37
+#define QUERY_LEN 9
+#define DATA_LEN 12
+#define HAS_TAP 0x01
+#define HAS_PALMDETECT 0x01
+#define HAS_ROTATE 0x02
+#define HAS_TAPANDHOLD 0x02
+#define HAS_DOUBLETAP 0x04
+#define HAS_EARLYTAP 0x08
+#define HAS_RELEASE 0x08
+#define HAS_FLICK 0x10
+#define HAS_PRESS 0x20
+#define HAS_PINCH 0x40
+
+#define MASK_16BIT 0xFFFF
+#define MASK_8BIT 0xFF
+#define MASK_7BIT 0x7F
+#define MASK_5BIT 0x1F
+#define MASK_4BIT 0x0F
+#define MASK_3BIT 0x07
+#define MASK_2BIT 0x03
+/* cwz: change 0x08 -> 0x04 for RMI version 4.03 */
+#if 0
+#define TOUCHPAD_CTRL_INTR 0x8
+#else
+#define TOUCHPAD_CTRL_INTR 0x4 //rmi4_acgzx modified
+#endif
+#define PDT_START_SCAN_LOCATION (0x00E9)
+#define PDT_END_SCAN_LOCATION (0x000A)
+#define PDT_ENTRY_SIZE (0x0006)
+
+#define RMI4_NUMBER_OF_MAX_FINGERS (8)
+#define SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM (0x11)
+#define SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM (0x01)
+
+#define SYNA_SUPPORT_POINT_MAX (5)
+#define SYNA_FINGER_MAX (5)
+
+#define SYNA_I2C_BUS_IO 1 /* cwz: 1 for i2c io poart. */
+#define RMI4_MULTI_TOUCH 1 /* cwz: 1 for kernel new report mode */
+
+#define RMI4_I2C_SPEED (400*1000) /* cwz: i2c io speed */
+
+#define SYNA_WIDTH_DELTA (2) /* rmi4_acgzx: test empirical value */
+
+#define SYNA_AIXS_REVISE_FORCE (0)
+#if SYNA_AIXS_REVISE_FORCE
+#define SYNA_AIXS_X_DELTA (0x40) //rmi4_acgzx: revise synaptics s7010 demo tp axis x for kindle
+#define SYNA_WIDTH_DELTA_FOR_X_MAX (6)
+#else
+#define SYNA_AIXS_X_DELTA (0)
+#define SYNA_WIDTH_DELTA_FOR_X_MAX (0)
+#endif
+
+static struct i2c_client *syna_client;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void synaptics_rmi4_early_suspend(struct early_suspend *h);
+static void synaptics_rmi4_late_resume(struct early_suspend *h);
+#endif
+
+#if 1
+#define rmi4_debug(level, ...) \
+ do { \
+ printk(KERN_ERR __VA_ARGS__); \
+ } while (0)
+#else
+#define rmi4_debug(level, ...)
+#endif
+
+#if (RMI4_MULTI_TOUCH != 0)
+enum synaptics_rmi4_touch_status {
+ SYNA_TOUCH_ORIGINAL = 0,
+ SYNA_TOUCH_PRESS,
+ SYNA_TOUCH_RELEASE
+};
+#endif
+
+/**
+ * struct synaptics_rmi4_fn_desc - contains the function descriptor information
+ * @query_base_addr: base address for query
+ * @cmd_base_addr: base address for command
+ * @ctrl_base_addr: base address for control
+ * @data_base_addr: base address for data
+ * @intr_src_count: count for the interrupt source
+ * @fn_number: function number
+ *
+ * This structure is used to gives the function descriptor information
+ * of the particular functionality.
+ */
+struct synaptics_rmi4_fn_desc {
+ 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;
+ unsigned char fn_number;
+};
+
+/**
+ * struct synaptics_rmi4_fn - contains the function information
+ * @fn_number: function number
+ * @num_of_data_sources: number of data sources
+ * @num_of_data_points: number of fingers touched
+ * @size_of_data_register_block: data register block size
+ * @index_to_intr_reg: index for interrupt register
+ * @intr_mask: interrupt mask value
+ * @fn_desc: variable for function descriptor structure
+ * @link: linked list for function descriptors
+ *
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+struct synaptics_rmi4_fn {
+ unsigned char fn_number;
+ unsigned char num_of_data_sources;
+ unsigned char num_of_data_points;
+ unsigned char size_of_data_register_block;
+ unsigned char index_to_intr_reg;
+ unsigned char intr_mask;
+ struct synaptics_rmi4_fn_desc fn_desc;
+ struct list_head link;
+};
+
+/**
+ * struct synaptics_rmi4_device_info - contains the rmi4 device information
+ * @version_major: protocol major version number
+ * @version_minor: protocol minor version number
+ * @manufacturer_id: manufacturer identification byte
+ * @product_props: product properties information
+ * @product_info: product info array
+ * @date_code: device manufacture date
+ * @tester_id: tester id array
+ * @serial_number: serial number for that device
+ * @product_id_string: product id for the device
+ * @support_fn_list: linked list for device information
+ *
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+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[2];
+ unsigned char date_code[3];
+ unsigned short tester_id;
+ unsigned short serial_number;
+ unsigned char product_id_string[11];
+ struct list_head support_fn_list;
+};
+
+/**
+ * struct synaptics_rmi4_data - contains the rmi4 device data
+ * @rmi4_mod_info: structure variable for rmi4 device info
+ * @input_dev: pointer for input device
+ * @i2c_client: pointer for i2c client
+ * @board: constant pointer for touch platform data
+ * @fn_list_mutex: mutex for function list
+ * @rmi4_page_mutex: mutex for rmi4 page
+ * @current_page: variable for integer
+ * @number_of_interrupt_register: interrupt registers count
+ * @fn01_ctrl_base_addr: control base address for fn01
+ * @fn01_query_base_addr: query base address for fn01
+ * @fn01_data_base_addr: data base address for fn01
+ * @sensor_max_x: sensor maximum x value
+ * @sensor_max_y: sensor maximum y value
+ * @regulator: pointer to the regulator structure
+ * @wait: wait queue structure variable
+ * @touch_stopped: flag to stop the thread function
+ *
+ * This structure gives the device data information.
+ */
+struct synaptics_rmi4_data {
+ struct synaptics_rmi4_device_info rmi4_mod_info;
+ struct input_dev *input_dev;
+ struct i2c_client *i2c_client;
+ const struct synaptics_rmi4_platform_data *board;
+ struct mutex fn_list_mutex;
+ struct mutex rmi4_page_mutex;
+ int current_page;
+ unsigned int number_of_interrupt_register;
+ unsigned short fn01_ctrl_base_addr;
+ unsigned short fn01_query_base_addr;
+ unsigned short fn01_data_base_addr;
+ int sensor_max_x;
+ int sensor_max_y;
+ struct regulator *regulator;
+ wait_queue_head_t wait;
+ bool touch_stopped;
+
+ struct mutex rmi4_wq_mutex;
+ struct work_struct work;
+ struct workqueue_struct *rmi4_wq;
+ struct early_suspend m_early_suspend;
+};
+
+#if (SYNA_I2C_BUS_IO != 0)
+static int synaptics_rmi4_read_block(struct i2c_client *client,
+ u16 addr,
+ u16 length,
+ u8 *value)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct i2c_msg msg[2];
+ __le16 le_addr;
+ int ret;
+
+ le_addr = cpu_to_le16(addr);
+
+ msg[0].scl_rate = RMI4_I2C_SPEED;
+ msg[0].addr = client->addr;
+ msg[0].flags = 0x00;
+ msg[0].len = 1;
+ msg[0].buf = (u8*) &le_addr;
+
+ msg[1].scl_rate = RMI4_I2C_SPEED;
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = length;
+ msg[1].buf = (u8*) value;
+
+ ret = i2c_transfer(adapter, msg, 2);
+
+ return (ret == 2)? length : ret;
+}
+#endif
+
+/**
+ * synaptics_rmi4_set_page() - sets the page
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: set the address of the page
+ *
+ * This function is used to set the page and returns integer.
+ */
+static int synaptics_rmi4_set_page(struct synaptics_rmi4_data *pdata,
+ unsigned int address)
+{
+ unsigned char txbuf[PAGE_LEN];
+ int retval;
+ unsigned int page;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ page = ((address >> 8) & MASK_8BIT);
+ if (page != pdata->current_page) {
+ txbuf[0] = MASK_8BIT;
+ txbuf[1] = page;
+ retval = i2c_master_send(i2c, txbuf, PAGE_LEN);
+ if (retval != PAGE_LEN)
+ dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+ else
+ pdata->current_page = page;
+ } else
+ retval = PAGE_LEN;
+ return retval;
+}
+/**
+ * synaptics_rmi4_i2c_block_read() - read the block of data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: read the block of data from this offset
+ * @valp: pointer to a buffer containing the data to be read
+ * @size: number of bytes to read
+ *
+ * This function is to read the block of data and returns integer.
+ */
+static int synaptics_rmi4_i2c_block_read(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char *valp, int size)
+{
+ int retval = 0;
+ int retry_count = 0;
+ int index;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ mutex_lock(&(pdata->rmi4_page_mutex));
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ index = address & MASK_8BIT;
+retry:
+#if (SYNA_I2C_BUS_IO != 0)
+ retval = synaptics_rmi4_read_block(i2c, index, size, valp);
+#else
+ retval = i2c_smbus_read_i2c_block_data(i2c, index, size, valp);
+#endif
+ if (retval != size) {
+ if (++retry_count == MAX_RETRY_COUNT)
+ dev_err(&i2c->dev,
+ "%s:address 0x%04x size %d failed:%d\n",
+ __func__, address, size, retval);
+ else {
+ synaptics_rmi4_set_page(pdata, address);
+ goto retry;
+ }
+ }
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+
+/**
+ * synaptics_rmi4_i2c_byte_write() - write the single byte data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: write the block of data from this offset
+ * @data: data to be write
+ *
+ * This function is to write the single byte data and returns integer.
+ */
+static int synaptics_rmi4_i2c_byte_write(struct synaptics_rmi4_data *pdata,
+ unsigned short address,
+ unsigned char data)
+{
+ unsigned char txbuf[2];
+ int retval = 0;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ /* Can't have anyone else changing the page behind our backs */
+ mutex_lock(&(pdata->rmi4_page_mutex));
+
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ txbuf[0] = address & MASK_8BIT;
+ txbuf[1] = data;
+ retval = i2c_master_send(pdata->i2c_client, txbuf, 2);
+ /* Add in retry on writes only in certain error return values */
+ if (retval != 2) {
+ dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+ retval = -EIO;
+ } else
+ retval = 1;
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+//hhb@rock-chips.com
+static int synaptics_rmi4_i2c_block_write(struct synaptics_rmi4_data *pdata,
+ unsigned short address, unsigned char *data, unsigned char size)
+{
+ unsigned char txbuf[8];
+ int retval = 0;
+ struct i2c_client *i2c = pdata->i2c_client;
+
+ /* Can't have anyone else changing the page behind our backs */
+ mutex_lock(&(pdata->rmi4_page_mutex));
+
+ retval = synaptics_rmi4_set_page(pdata, address);
+ if (retval != PAGE_LEN)
+ goto exit;
+ txbuf[0] = address & MASK_8BIT;
+ memcpy(txbuf + 1, data, size);
+ retval = i2c_master_send(pdata->i2c_client, txbuf, size + 1);
+ /* Add in retry on writes only in certain error return values */
+ if (retval != 2) {
+ dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+ retval = -EIO;
+ } else
+ retval = 1;
+exit:
+ mutex_unlock(&(pdata->rmi4_page_mutex));
+ return retval;
+}
+
+
+/**
+ * synpatics_rmi4_touchpad_report() - reports for the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to reports for the rmi4 touchpad device
+ */
+static int synpatics_rmi4_touchpad_report(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ /* number of touch points - fingers down in this case */
+ int touch_count = 0;
+ int finger;
+ int fingers_supported;
+ int finger_registers;
+ int reg;
+ int finger_shift;
+ int finger_status;
+ int retval;
+ unsigned short data_base_addr;
+ unsigned short data_offset;
+ unsigned char data_reg_blk_size;
+ unsigned char values[2];
+ unsigned char data[DATA_LEN];
+ int x[RMI4_NUMBER_OF_MAX_FINGERS];
+ int y[RMI4_NUMBER_OF_MAX_FINGERS];
+ int wx[RMI4_NUMBER_OF_MAX_FINGERS];
+ int wy[RMI4_NUMBER_OF_MAX_FINGERS];
+ struct i2c_client *client = pdata->i2c_client;
+
+#if (RMI4_MULTI_TOUCH != 0)
+ volatile enum synaptics_rmi4_touch_status cur_touch_status[SYNA_SUPPORT_POINT_MAX];
+ static volatile enum synaptics_rmi4_touch_status pre_touch_status[SYNA_SUPPORT_POINT_MAX];
+#endif
+
+ /* get 2D sensor finger data */
+ /*
+ * First get the finger status field - the size of the finger status
+ * field is determined by the number of finger supporte - 2 bits per
+ * finger, so the number of registers to read is:
+ * registerCount = ceil(numberOfFingers/4).
+ * Read the required number of registers and check each 2 bit field to
+ * determine if a finger is down:
+ * 00 = finger not present,
+ * 01 = finger present and data accurate,
+ * 10 = finger present but data may not be accurate,
+ * 11 = reserved for product use.
+ */
+ fingers_supported = rfi->num_of_data_points;
+ finger_registers = (fingers_supported + 3)/4;
+ data_base_addr = rfi->fn_desc.data_base_addr;
+ retval = synaptics_rmi4_i2c_block_read(pdata, data_base_addr, values,
+ finger_registers);
+ if (retval != finger_registers) {
+ dev_err(&client->dev, "%s:read status registers failed\n",
+ __func__);
+ return 0;
+ }
+ /*
+ * For each finger present, read the proper number of registers
+ * to get absolute data.
+ */
+ data_reg_blk_size = rfi->size_of_data_register_block;
+
+ for (finger = 0; finger < fingers_supported; finger++) {
+ //mutex_lock(&pdata->rmi4_wq_mutex);
+ cur_touch_status[finger] = SYNA_TOUCH_ORIGINAL;
+ //mutex_unlock(&pdata->rmi4_wq_mutex);
+ }
+
+ for (finger = 0; finger < fingers_supported; finger++) {
+ /* determine which data byte the finger status is in */
+ reg = finger/4;
+ /* bit shift to get finger's status */
+ finger_shift = (finger % 4) * 2;
+ finger_status = (values[reg] >> finger_shift) & 3;
+ /*
+ * if finger status indicates a finger is present then
+ * read the finger data and report it
+ */
+ if (finger_status == 1 || finger_status == 2) {
+ rmi4_debug(DEBUG_TRACE, "---> finger[%d] press ??\n", finger);
+
+ //mutex_lock(&pdata->rmi4_wq_mutex);
+ cur_touch_status[finger] = SYNA_TOUCH_PRESS;
+ //mutex_unlock(&pdata->rmi4_wq_mutex);
+
+ /* Read the finger data */
+ data_offset = data_base_addr +
+ ((finger * data_reg_blk_size) +
+ finger_registers);
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ data_offset, data, data_reg_blk_size);
+ if (retval != data_reg_blk_size) {
+ printk(KERN_ERR "%s:read data failed\n", __func__);
+ //mutex_lock(&pdata->rmi4_wq_mutex);
+ cur_touch_status[finger] = SYNA_TOUCH_ORIGINAL;
+ //mutex_unlock(&pdata->rmi4_wq_mutex);
+ return 0;
+ } else {
+ x[finger] =
+ (data[0] << 4) | (data[2] & MASK_4BIT);
+ y[finger] =
+ (data[1] << 4) |
+ ((data[2] >> 4) & MASK_4BIT);
+ wy[finger] =
+ (data[3] >> 4) & MASK_4BIT;
+ wx[finger] =
+ (data[3] & MASK_4BIT);
+
+ #if 0
+ if (x[finger] >= pdata->sensor_max_x)
+ rmi4_debug(DEBUG_TRACE, "x[%d] = 0x%x, y[%d] = 0x%x\n"
+ "wx[%d] = 0x%x, wy[%d] = 0x%x\n"
+ "sensor_max_x = 0x%x, sensor_max_y = 0x%x\n",
+ finger, x[finger], finger, y[finger],
+ finger, wx[finger], finger, wy[finger],
+ pdata->sensor_max_x, pdata->sensor_max_y
+ );
+ #endif
+
+ #if SYNA_AIXS_REVISE_FORCE
+ {
+ int axis_bak;
+
+ axis_bak = x[finger];
+
+ /*rmi4_acgzx: because these s7010 tp is assembling for a short time, sensor and lines isn't matching.
+ * force revise axis x and special handing.
+ */
+ x[finger] -= SYNA_AIXS_X_DELTA;
+ x[finger] = (x[finger] < 0) ? 0 : x[finger];
+
+ //rmi4_acgzx: special handing for sensor_max_x.
+ if (axis_bak >= pdata->sensor_max_x && wx[finger] <= SYNA_WIDTH_DELTA_FOR_X_MAX)
+ x[finger] += SYNA_AIXS_X_DELTA;
+ }
+ #endif
+
+ /* rmi4_acgzx: do not support touch key, ignore outside touch */
+ if (x[finger] >= (pdata->sensor_max_x - SYNA_AIXS_X_DELTA) && wx[finger] <= SYNA_WIDTH_DELTA) {
+ //mutex_lock(&pdata->rmi4_wq_mutex);
+ cur_touch_status[finger] = SYNA_TOUCH_RELEASE;
+ //mutex_unlock(&pdata->rmi4_wq_mutex);
+ rmi4_debug(DEBUG_TRACE, "touch point beyond lcd display area.\n");
+ }
+
+ if (pdata->board->x_flip)
+ x[finger] = pdata->sensor_max_x - x[finger];
+ if (pdata->board->y_flip)
+ y[finger] = pdata->sensor_max_y - y[finger];
+
+ }
+ /* rmi4_acgzx: touch press, touch_count increase */
+ if (SYNA_TOUCH_PRESS == cur_touch_status[finger])
+ touch_count++;
+ }
+ else {
+ //mutex_lock(&pdata->rmi4_wq_mutex);
+ cur_touch_status[finger] = SYNA_TOUCH_RELEASE;
+ //mutex_unlock(&pdata->rmi4_wq_mutex);
+ }
+ }
+
+ for (finger = 0; finger < fingers_supported; finger++) {
+ if (SYNA_TOUCH_PRESS == cur_touch_status[finger]) {
+ rmi4_debug(DEBUG_TRACE, "====> finger[%d] press!\n", finger);
+ /* number of active touch points */
+ input_mt_slot(pdata->input_dev, finger);
+ input_mt_report_slot_state(pdata->input_dev, MT_TOOL_FINGER, true);
+ input_report_abs(pdata->input_dev, ABS_MT_TRACKING_ID, finger);
+ input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR, MAX_TOUCH_MAJOR);
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_X, x[finger]);
+ input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y, y[finger]);
+ //mutex_lock(&pdata->rmi4_wq_mutex);
+ pre_touch_status[finger] = cur_touch_status[finger];
+ //mutex_unlock(&pdata->rmi4_wq_mutex);
+ }
+ }
+
+ for (finger = 0; finger < fingers_supported; finger++) {
+ if (SYNA_TOUCH_RELEASE == cur_touch_status[finger] &&
+ SYNA_TOUCH_PRESS == pre_touch_status[finger]) {
+ rmi4_debug(DEBUG_TRACE, "====> finger[%d] release!\n", finger);
+ /* number of active touch points */
+ input_mt_slot(pdata->input_dev, finger);
+ input_mt_report_slot_state(pdata->input_dev, MT_TOOL_FINGER, false);
+ input_report_abs(pdata->input_dev, ABS_MT_TRACKING_ID, -1);
+ //mutex_lock(&pdata->rmi4_wq_mutex);
+ pre_touch_status[finger] = cur_touch_status[finger];
+ //mutex_unlock(&pdata->rmi4_wq_mutex);
+ }
+ }
+
+ /* sync after groups of events */
+ input_sync(pdata->input_dev);
+ /* return the number of touch points */
+ return touch_count;
+}
+
+/**
+ * synaptics_rmi4_report_device() - reports the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn
+ *
+ * This function is used to call the report function of the rmi4 device.
+ */
+static int synaptics_rmi4_report_device(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ int touch = 0;
+ struct i2c_client *client = pdata->i2c_client;
+ static int num_error_reports;
+ if (rfi->fn_number != SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) {
+ rmi4_debug(DEBUG_TRACE, "====> %s fn_number no equal enter!\n", __func__);
+ num_error_reports++;
+ if (num_error_reports < MAX_ERROR_REPORT)
+ dev_err(&client->dev, "%s:report not supported\n",
+ __func__);
+ } else
+ touch = synpatics_rmi4_touchpad_report(pdata, rfi);
+ return touch;
+}
+/**
+ * synaptics_rmi4_sensor_report() - reports to input subsystem
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to reads in all data sources and reports
+ * them to the input subsystem.
+ */
+static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *pdata)
+{
+ unsigned char intr_status[4];
+ /* number of touch points - fingers or buttons */
+ int touch = 0;
+ unsigned int retval;
+ struct synaptics_rmi4_fn *rfi;
+ struct synaptics_rmi4_device_info *rmi;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /*
+ * Get the interrupt status from the function $01
+ * control register+1 to find which source(s) were interrupting
+ * so we can read the data from the source(s) (2D sensor, buttons..)
+ */
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ pdata->fn01_data_base_addr + 1,
+ intr_status,
+ pdata->number_of_interrupt_register);
+ if (retval != pdata->number_of_interrupt_register) {
+ dev_err(&client->dev,
+ "could not read interrupt status registers\n");
+ return 0;
+ }
+ /*
+ * check each function that has data sources and if the interrupt for
+ * that triggered then call that RMI4 functions report() function to
+ * gather data and report it to the input subsystem
+ */
+ rmi = &(pdata->rmi4_mod_info);
+ list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+ if (rfi->num_of_data_sources) {
+ if (intr_status[rfi->index_to_intr_reg] &
+ rfi->intr_mask)
+ touch = synaptics_rmi4_report_device(pdata,
+ rfi);
+ }
+ }
+ /* return the number of touch points */
+ return touch;
+}
+
+static void synaptics_rmi4_work_func(struct work_struct *work)
+{
+ struct synaptics_rmi4_data *rmi4_data = container_of(work, struct synaptics_rmi4_data, work);
+ struct i2c_client *client = rmi4_data->i2c_client;
+ unsigned char intr_status;
+
+ /* rmi4_acgzx note: important!! disable tp interrupt avoid lost attn */
+ synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x00);
+
+ synaptics_rmi4_sensor_report(rmi4_data);
+
+ enable_irq(client->irq);
+
+ /* rmi4_acgzx note: important!! enable tp interrupt again*/
+ synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x0f);
+
+ /* rmi4_acgzx note: may be cause lose attn, gpio irq is low, that is small probability in rk30 platform.
+ * need read int status register again just in case.
+ */
+ if (0 == gpio_get_value(client->irq)) {
+ rmi4_debug(DEBUG_TRACE, "----> %s: irq change low value enter! <----\n", __func__);
+ synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1,
+ &intr_status,
+ rmi4_data->number_of_interrupt_register);
+
+ }
+
+ //rmi4_debug(DEBUG_TRACE, "%s: exit!\n", __func__); //rmi4_acgzx
+}
+
+/**
+ * synaptics_rmi4_irq() - thread function for rmi4 attention line
+ * @irq: irq value
+ * @data: void pointer
+ *
+ * This function is interrupt thread function. It just notifies the
+ * application layer that attention is required.
+ */
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
+{
+ struct synaptics_rmi4_data *pdata = data;
+
+ //rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx
+
+ disable_irq_nosync(irq);
+ queue_work(pdata->rmi4_wq, &pdata->work);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * synpatics_rmi4_touchpad_detect() - detects the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ * @fd: pointer to synaptics_rmi4_fn_desc structure
+ * @interruptcount: count the number of interrupts
+ *
+ * This function calls to detects the rmi4 touchpad device
+ */
+static int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int interruptcount)
+{
+ unsigned char queries[QUERY_LEN];
+ unsigned short intr_offset;
+ unsigned char abs_data_size;
+ unsigned char abs_data_blk_size;
+ unsigned char egr_0, egr_1;
+ unsigned int all_data_blk_size;
+ int has_pinch, has_flick, has_tap;
+ int has_tapandhold, has_doubletap;
+ int has_earlytap, has_press;
+ int has_palmdetect, has_rotate;
+ int has_rel;
+ int i;
+ int retval;
+ struct i2c_client *client = pdata->i2c_client;
+
+ rfi->fn_desc.query_base_addr = fd->query_base_addr;
+ rfi->fn_desc.data_base_addr = fd->data_base_addr;
+ rfi->fn_desc.intr_src_count = fd->intr_src_count;
+ rfi->fn_desc.fn_number = fd->fn_number;
+ rfi->fn_number = fd->fn_number;
+ rfi->num_of_data_sources = fd->intr_src_count;
+ rfi->fn_desc.ctrl_base_addr = fd->ctrl_base_addr;
+ rfi->fn_desc.cmd_base_addr = fd->cmd_base_addr;
+
+ /*
+ * need to get number of fingers supported, data size, etc.
+ * to be used when getting data since the number of registers to
+ * read depends on the number of fingers supported and data size.
+ */
+ retval = synaptics_rmi4_i2c_block_read(pdata, fd->query_base_addr,
+ queries,
+ sizeof(queries));
+ if (retval != sizeof(queries)) {
+ dev_err(&client->dev, "%s:read function query registers\n",
+ __func__);
+ return retval;
+ }
+ /*
+ * 2D data sources have only 3 bits for the number of fingers
+ * supported - so the encoding is a bit weird.
+ */
+ if ((queries[1] & MASK_3BIT) <= 4)
+ /* add 1 since zero based */
+ rfi->num_of_data_points = (queries[1] & MASK_3BIT) + 1;
+ else {
+ /*
+ * a value of 5 is up to 10 fingers - 6 and 7 are reserved
+ * (shouldn't get these i int retval;n a normal 2D source).
+ */
+ if ((queries[1] & MASK_3BIT) == 5)
+ rfi->num_of_data_points = 10;
+ }
+ /* Need to get interrupt info for handling interrupts */
+ rfi->index_to_intr_reg = (interruptcount + 7)/8;
+ if (rfi->index_to_intr_reg != 0)
+ rfi->index_to_intr_reg -= 1;
+ /*
+ * loop through interrupts for each source in fn $11
+ * and or in a bit to the interrupt mask for each.
+ */
+ intr_offset = interruptcount % 8;
+ rfi->intr_mask = 0;
+ for (i = intr_offset;
+ i < ((fd->intr_src_count & MASK_3BIT) + intr_offset); i++)
+ rfi->intr_mask |= 1 << i;
+
+ /* Size of just the absolute data for one finger */
+ abs_data_size = queries[5] & MASK_2BIT;
+ /* One each for X and Y, one for LSB for X & Y, one for W, one for Z */
+ abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0));
+ rfi->size_of_data_register_block = abs_data_blk_size;
+
+ /*
+ * need to determine the size of data to read - this depends on
+ * conditions such as whether Relative data is reported and if Gesture
+ * data is reported.
+ */
+ egr_0 = queries[7];
+ egr_1 = queries[8];
+
+ /*
+ * Get info about what EGR data is supported, whether it has
+ * Relative data supported, etc.
+ */
+ has_pinch = egr_0 & HAS_PINCH;
+ has_flick = egr_0 & HAS_FLICK;
+ has_tap = egr_0 & HAS_TAP;
+ has_earlytap = egr_0 & HAS_EARLYTAP;
+ has_press = egr_0 & HAS_PRESS;
+ has_rotate = egr_1 & HAS_ROTATE;
+ has_rel = queries[1] & HAS_RELEASE;
+ has_tapandhold = egr_0 & HAS_TAPANDHOLD;
+ has_doubletap = egr_0 & HAS_DOUBLETAP;
+ has_palmdetect = egr_1 & HAS_PALMDETECT;
+
+ /*
+ * Size of all data including finger status, absolute data for each
+ * finger, relative data and EGR data
+ */
+ all_data_blk_size =
+ /* finger status, four fingers per register */
+ ((rfi->num_of_data_points + 3) / 4) +
+ /* absolute data, per finger times number of fingers */
+ (abs_data_blk_size * rfi->num_of_data_points) +
+ /*
+ * two relative registers (if relative is being reported)
+ */
+ 2 * has_rel +
+ /*
+ * F11_2D_data8 is only present if the egr_0
+ * register is non-zero.
+ */
+ !!(egr_0) +
+ /*
+ * F11_2D_data9 is only present if either egr_0 or
+ * egr_1 registers are non-zero.
+ */
+ (egr_0 || egr_1) +
+ /*
+ * F11_2D_data10 is only present if EGR_PINCH or EGR_FLICK of
+ * egr_0 reports as 1.
+ */
+ !!(has_pinch | has_flick) +
+ /*
+ * F11_2D_data11 and F11_2D_data12 are only present if
+ * EGR_FLICK of egr_0 reports as 1.
+ */
+ 2 * !!(has_flick);
+ return retval;
+}
+
+/**
+ * synpatics_rmi4_touchpad_config() - confiures the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to confiures the rmi4 touchpad device
+ */
+int synpatics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata,
+ struct synaptics_rmi4_fn *rfi)
+{
+ /*
+ * For the data source - print info and do any
+ * source specific configuration.
+ */
+ unsigned char data[BUF_LEN];
+ int retval = 0;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /* Get and print some info about the data source... */
+ /* To Query 2D devices we need to read from the address obtained
+ * from the function descriptor stored in the RMI function info.
+ */
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ rfi->fn_desc.query_base_addr,
+ data, QUERY_LEN);
+ if (retval != QUERY_LEN)
+ dev_err(&client->dev, "%s:read query registers failed\n",
+ __func__);
+ else {
+
+ //hhb@rock-chips.com add virtual_keys function
+ if (pdata->board->virtual_keys == true) {
+
+ int w, h;
+ char buf[2];
+
+ pdata->sensor_max_x = pdata->board->lcd_width;
+ pdata->sensor_max_y = pdata->board->lcd_height;
+
+ w = pdata->board->lcd_width + pdata->board->w_delta;
+ h = pdata->board->lcd_height + pdata->board->h_delta;
+
+#if 0
+ buf[0] = w & MASK_8BIT;
+ buf[1] = (w >> 8) & MASK_4BIT;
+ synaptics_rmi4_i2c_block_write(pdata, rfi->fn_desc.ctrl_base_addr + 6, buf, 2);
+ buf[0] = h & MASK_8BIT;
+ buf[1] = (h >> 8) & MASK_4BIT;
+ synaptics_rmi4_i2c_block_write(pdata, rfi->fn_desc.ctrl_base_addr + 8, buf, 2);
+#else
+ synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 6, w & MASK_8BIT);
+ synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 7, (w >> 8) & MASK_4BIT);
+
+ synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 8, h & MASK_8BIT);
+ synaptics_rmi4_i2c_byte_write(pdata, rfi->fn_desc.ctrl_base_addr + 9, (h >> 8) & MASK_4BIT);
+#endif
+
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ rfi->fn_desc.ctrl_base_addr,
+ data, DATA_BUF_LEN);
+ if (retval != DATA_BUF_LEN) {
+ dev_err(&client->dev,
+ "%s:read control registers failed\n",
+ __func__);
+ return retval;
+ }
+
+ w = ((data[6] & MASK_8BIT) << 0) |
+ ((data[7] & MASK_4BIT) << 8);
+ h = ((data[8] & MASK_8BIT) << 0) |
+ ((data[9] & MASK_4BIT) << 8);
+
+ if(pdata->board->lcd_width != w || pdata->board->lcd_height != h){
+ printk("set tp x:%d, y:%d, but read x:%d, y:%d\n", pdata->board->lcd_width, pdata->board->lcd_height, w, h);
+ }
+
+ } else {
+
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ rfi->fn_desc.ctrl_base_addr,
+ data, DATA_BUF_LEN);
+ if (retval != DATA_BUF_LEN) {
+ dev_err(&client->dev,
+ "%s:read control registers failed\n",
+ __func__);
+ return retval;
+ }
+
+ /* Store these for use later*/
+
+ pdata->sensor_max_x = ((data[6] & MASK_8BIT) << 0) |
+ ((data[7] & MASK_4BIT) << 8);
+ pdata->sensor_max_y = ((data[8] & MASK_8BIT) << 0) |
+ ((data[9] & MASK_4BIT) << 8);
+ }
+
+ rmi4_debug(DEBUG_TRACE, "sensor_max_x = 0x%x, sensor_max_y = 0x%x.\n",
+ pdata->sensor_max_x, pdata->sensor_max_y);
+ }
+ return retval;
+}
+
+/**
+ * synaptics_rmi4_i2c_query_device() - query the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to query the rmi4 device.
+ */
+static int synaptics_rmi4_i2c_query_device(struct synaptics_rmi4_data *pdata)
+{
+ int i;
+ int retval;
+ unsigned char std_queries[STD_QUERY_LEN];
+ unsigned char intr_count = 0;
+ int data_sources = 0;
+ unsigned int ctrl_offset;
+ struct synaptics_rmi4_fn *rfi;
+ struct synaptics_rmi4_fn_desc rmi_fd;
+ struct synaptics_rmi4_device_info *rmi;
+ struct i2c_client *client = pdata->i2c_client;
+
+ /*
+ * init the physical drivers RMI module
+ * info list of functions
+ */
+ INIT_LIST_HEAD(&pdata->rmi4_mod_info.support_fn_list);
+
+ /*
+ * Read the Page Descriptor Table to determine what functions
+ * are present
+ */
+ for (i = PDT_START_SCAN_LOCATION; i > PDT_END_SCAN_LOCATION;
+ i -= PDT_ENTRY_SIZE) {
+ retval = synaptics_rmi4_i2c_block_read(pdata, i,
+ (unsigned char *)&rmi_fd,
+ sizeof(rmi_fd));
+ if (retval != sizeof(rmi_fd)) {
+ /* failed to read next PDT entry */
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return -EIO;
+ }
+
+ rmi4_debug(DEBUG_TRACE, "----> query_base_addr = 0x%x\n"
+ "cmd_base_addr = 0x%x\n"
+ "ctrl_base_addr = 0x%x\n"
+ "data_base_addr = 0x%x\n"
+ "intr_src_count = 0x%x\n"
+ "fn_number = 0x%x\n",
+ rmi_fd.query_base_addr,
+ rmi_fd.cmd_base_addr,
+ rmi_fd.ctrl_base_addr,
+ rmi_fd.data_base_addr,
+ rmi_fd.intr_src_count,
+ rmi_fd.fn_number
+ );
+
+ rfi = NULL;
+ if (rmi_fd.fn_number) {
+ switch (rmi_fd.fn_number & MASK_8BIT) {
+ case SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM:
+ pdata->fn01_query_base_addr =
+ rmi_fd.query_base_addr;
+ pdata->fn01_ctrl_base_addr =
+ rmi_fd.ctrl_base_addr;
+ pdata->fn01_data_base_addr =
+ rmi_fd.data_base_addr;
+
+ rmi4_debug(DEBUG_TRACE, "----> fn01_query_base_addr = 0x%x\n,"
+ "fn01_ctrl_base_addr = 0x%x\n,"
+ "fn01_data_base_addr = 0x%x\n,",
+ pdata->fn01_query_base_addr,
+ pdata->fn01_ctrl_base_addr,
+ pdata->fn01_data_base_addr
+ );
+ break;
+ case SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM:
+ if (rmi_fd.intr_src_count) {
+ rfi = kmalloc(sizeof(*rfi),
+ GFP_KERNEL);
+ if (!rfi) {
+ dev_err(&client->dev,
+ "%s:kmalloc failed\n",
+ __func__);
+ return -ENOMEM;
+ }
+ retval = synpatics_rmi4_touchpad_detect
+ (pdata, rfi,
+ &rmi_fd,
+ intr_count);
+ if (retval < 0) {
+ kfree(rfi);
+ return retval;
+ }
+ }
+ break;
+ }
+ /* interrupt count for next iteration */
+ intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+ /*
+ * We only want to add functions to the list
+ * that have data associated with them.
+ */
+ if (rfi && rmi_fd.intr_src_count) {
+ /* link this function info to the RMI module */
+ mutex_lock(&(pdata->fn_list_mutex));
+ list_add_tail(&rfi->link,
+ &pdata->rmi4_mod_info.support_fn_list);
+ mutex_unlock(&(pdata->fn_list_mutex));
+ }
+ } else {
+ /*
+ * A zero in the function number
+ * signals the end of the PDT
+ */
+ dev_dbg(&client->dev,
+ "%s:end of PDT\n", __func__);
+ break;
+ }
+ }
+ /*
+ * calculate the interrupt register count - used in the
+ * ISR to read the correct number of interrupt registers
+ */
+ pdata->number_of_interrupt_register = (intr_count + 7) / 8;
+ /*
+ * Function $01 will be used to query the product properties,
+ * and product ID so we had to read the PDT above first to get
+ * the Fn $01 query address and prior to filling in the product
+ * info. NOTE: Even an unflashed device will still have FN $01.
+ */
+
+ /* Load up the standard queries and get the RMI4 module info */
+ retval = synaptics_rmi4_i2c_block_read(pdata,
+ pdata->fn01_query_base_addr,
+ std_queries,
+ sizeof(std_queries));
+ if (retval != sizeof(std_queries)) {
+ dev_err(&client->dev, "%s:Failed reading queries\n",
+ __func__);
+ return -EIO;
+ }
+
+ /* Currently supported RMI version is 4.0 */
+ pdata->rmi4_mod_info.version_major = 4;
+ pdata->rmi4_mod_info.version_minor = 0;
+ /*
+ * get manufacturer id, product_props, product info,
+ * date code, tester id, serial num and product id (name)
+ */
+ pdata->rmi4_mod_info.manufacturer_id = std_queries[0];
+ pdata->rmi4_mod_info.product_props = std_queries[1];
+ pdata->rmi4_mod_info.product_info[0] = std_queries[2];
+ pdata->rmi4_mod_info.product_info[1] = std_queries[3];
+ /* year - 2001-2032 */
+ pdata->rmi4_mod_info.date_code[0] = std_queries[4] & MASK_5BIT;
+ /* month - 1-12 */
+ pdata->rmi4_mod_info.date_code[1] = std_queries[5] & MASK_4BIT;
+ /* day - 1-31 */
+ pdata->rmi4_mod_info.date_code[2] = std_queries[6] & MASK_5BIT;
+ pdata->rmi4_mod_info.tester_id = ((std_queries[7] & MASK_7BIT) << 8) |
+ (std_queries[8] & MASK_7BIT);
+ pdata->rmi4_mod_info.serial_number =
+ ((std_queries[9] & MASK_7BIT) << 8) |
+ (std_queries[10] & MASK_7BIT);
+ memcpy(pdata->rmi4_mod_info.product_id_string, &std_queries[11], 10);
+
+ rmi4_debug(DEBUG_TRACE, "version_major = 0x%x, version_minor = 0x%x.\n"
+ "manufacturer_id = 0x%x, product_props = 0x%x.\n"
+ "product_info[1] = 0x%x, product_info[0] = 0x%x.\n"
+ "date_code[2] = 0x%x, date_code[1] = 0x%x, date_code[0] = 0x%x.\n"
+ "tester_id = 0x%x, serial_number = 0x%x.\n"
+ "product_id_string = %s.\n",
+ pdata->rmi4_mod_info.version_major, pdata->rmi4_mod_info.version_minor,
+ pdata->rmi4_mod_info.manufacturer_id, pdata->rmi4_mod_info.product_props,
+ pdata->rmi4_mod_info.product_info[1], pdata->rmi4_mod_info.product_info[0],
+ pdata->rmi4_mod_info.date_code[2], pdata->rmi4_mod_info.date_code[1], pdata->rmi4_mod_info.date_code[0],
+ pdata->rmi4_mod_info.tester_id, pdata->rmi4_mod_info.serial_number,
+ pdata->rmi4_mod_info.product_id_string
+ );
+
+ /* Check if this is a Synaptics device - report if not. */
+ if (pdata->rmi4_mod_info.manufacturer_id != 1)
+ dev_err(&client->dev, "%s: non-Synaptics mfg id:%d\n",
+ __func__, pdata->rmi4_mod_info.manufacturer_id);
+
+ list_for_each_entry(rfi, &pdata->rmi4_mod_info.support_fn_list, link)
+ data_sources += rfi->num_of_data_sources;
+ if (data_sources) {
+ rmi = &(pdata->rmi4_mod_info);
+ list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+ if (rfi->num_of_data_sources) {
+ if (rfi->fn_number ==
+ SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) {
+ retval = synpatics_rmi4_touchpad_config
+ (pdata, rfi);
+ if (retval < 0)
+ return retval;
+ } else
+ dev_err(&client->dev,
+ "%s:fn_number not supported\n",
+ __func__);
+ /*
+ * Turn on interrupts for this
+ * function's data sources.
+ */
+ ctrl_offset = pdata->fn01_ctrl_base_addr + 1 +
+ rfi->index_to_intr_reg;
+
+ rmi4_debug(DEBUG_TRACE, "----> fn01_ctrl_base_addr = 0x%x, intr_mask = 0x%x\n"
+ "index_to_intr_reg = 0x%x, ctrl_offset = 0x%x.\n",
+ pdata->fn01_ctrl_base_addr, rfi->intr_mask,
+ rfi->index_to_intr_reg, ctrl_offset
+ );
+
+ retval = synaptics_rmi4_i2c_byte_write(pdata,
+ ctrl_offset,
+ rfi->intr_mask);
+ if (retval < 0)
+ return retval;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * synaptics_rmi4_probe() - Initialze the i2c-client touchscreen driver
+ * @i2c: i2c client structure pointer
+ * @id:i2c device id pointer
+ *
+ * This function will allocate and initialize the instance
+ * data and request the irq and set the instance data as the clients
+ * platform data then register the physical driver which will do a scan of
+ * the rmi4 Physical Device Table and enumerate any rmi4 functions that
+ * have data sources associated with them.
+ */
+static int __devinit synaptics_rmi4_probe
+ (struct i2c_client *client, const struct i2c_device_id *dev_id)
+{
+ int retval;
+ unsigned char intr_status[4];
+ struct synaptics_rmi4_data *rmi4_data;
+ struct synaptics_rmi4_platform_data *platformdata =
+ client->dev.platform_data;
+
+#if (SYNA_I2C_BUS_IO != 0)
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c smbus byte data not supported\n");
+ return -EIO;
+ }
+#else
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "i2c smbus byte data not supported\n");
+ return -EIO;
+ }
+#endif
+
+ if (!platformdata) {
+ dev_err(&client->dev, "%s: no platform data\n", __func__);
+ return -EINVAL;
+ }
+
+ //if (platformdata->init_hw)
+ // platformdata->init_hw();
+
+ platformdata->irq_number = gpio_to_irq(client->irq);
+ //platformdata->x_flip = false; // hhb
+ //platformdata->y_flip = false;
+ //platformdata->irq_type = IRQF_TRIGGER_FALLING;
+ //platformdata->regulator_en = false;
+
+ rmi4_debug(DEBUG_TRACE, "irq_number = %d, client->irq = %d\n",
+ platformdata->irq_number, client->irq);
+
+ /* Allocate and initialize the instance data for this client */
+ rmi4_data = kzalloc(sizeof(struct synaptics_rmi4_data) * 2,
+ GFP_KERNEL);
+ if (!rmi4_data) {
+ dev_err(&client->dev, "%s: no memory allocated\n", __func__);
+ return -ENOMEM;
+ }
+
+ rmi4_data->input_dev = input_allocate_device();
+ if (rmi4_data->input_dev == NULL) {
+ dev_err(&client->dev, "%s:input device alloc failed\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_input;
+ }
+
+ if (platformdata->regulator_en) {
+ rmi4_data->regulator = regulator_get(&client->dev, "vdd");
+ if (IS_ERR(rmi4_data->regulator)) {
+ dev_err(&client->dev, "%s:get regulator failed\n",
+ __func__);
+ retval = PTR_ERR(rmi4_data->regulator);
+ goto err_regulator;
+ }
+ regulator_enable(rmi4_data->regulator);
+ }
+
+ init_waitqueue_head(&rmi4_data->wait);
+ /*
+ * Copy i2c_client pointer into RTID's i2c_client pointer for
+ * later use in rmi4_read, rmi4_write, etc.
+ */
+ rmi4_data->i2c_client = client;
+ /* So we set the page correctly the first time */
+ rmi4_data->current_page = MASK_16BIT;
+ rmi4_data->board = platformdata;
+ rmi4_data->touch_stopped = false;
+
+ /* init the mutexes for maintain the lists */
+ mutex_init(&(rmi4_data->fn_list_mutex));
+ mutex_init(&(rmi4_data->rmi4_page_mutex));
+
+ mutex_init(&(rmi4_data->rmi4_wq_mutex));
+
+ /*
+ * Register physical driver - this will call the detect function that
+ * will then scan the device and determine the supported
+ * rmi4 functions.
+ */
+ retval = synaptics_rmi4_i2c_query_device(rmi4_data);
+ if (retval) {
+ dev_err(&client->dev, "%s: rmi4 query device failed\n",
+ __func__);
+ goto err_query_dev;
+ }
+
+ /* Store the instance data in the i2c_client */
+ i2c_set_clientdata(client, rmi4_data);
+
+ /*initialize the input device parameters */
+ rmi4_data->input_dev->name = DRIVER_NAME;
+ rmi4_data->input_dev->phys = "Synaptics_Clearpad";
+ rmi4_data->input_dev->id.bustype = BUS_I2C;
+ rmi4_data->input_dev->dev.parent = &client->dev;
+ input_set_drvdata(rmi4_data->input_dev, rmi4_data);
+
+ /* Initialize the function handlers for rmi4 */
+
+ __set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
+ __set_bit(EV_ABS, rmi4_data->input_dev->evbit);
+
+ input_mt_init_slots(rmi4_data->input_dev, SYNA_SUPPORT_POINT_MAX);
+
+ 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);
+ input_set_abs_params(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, 0,
+ MAX_TOUCH_MAJOR, 0, 0);
+
+ /* Clear interrupts */
+ synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1, intr_status,
+ rmi4_data->number_of_interrupt_register);
+
+ rmi4_debug(DEBUG_TRACE, "intr_status: %d %d %d %d, number_of_interrupt_register = %d\n",
+ intr_status[0], intr_status[1], intr_status[2], intr_status[3],
+ rmi4_data->number_of_interrupt_register);
+
+ rmi4_data->rmi4_wq = create_workqueue("rmi4_wq");
+ rmi4_debug(DEBUG_TRACE, "----> create_workqueue start!\n");
+
+ INIT_WORK(&rmi4_data->work, synaptics_rmi4_work_func);
+
+ retval = request_threaded_irq(platformdata->irq_number, NULL,
+ synaptics_rmi4_irq,
+ platformdata->irq_type,
+ DRIVER_NAME, rmi4_data);
+ if (retval) {
+ dev_err(&client->dev, "%s:Unable to get attn irq %d\n",
+ __func__, platformdata->irq_number);
+ goto err_query_dev;
+ }
+
+ retval = input_register_device(rmi4_data->input_dev);
+ if (retval) {
+ dev_err(&client->dev, "%s:input register failed\n", __func__);
+ goto err_free_irq;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ syna_client = client;
+
+ rmi4_data->m_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
+ rmi4_data->m_early_suspend.suspend = synaptics_rmi4_early_suspend;
+ rmi4_data->m_early_suspend.resume = synaptics_rmi4_late_resume;
+ register_early_suspend(&rmi4_data->m_early_suspend);
+#else
+ rmi4_data->m_early_suspend.level = -1;
+ rmi4_data->m_early_suspend.suspend = NULL;
+ rmi4_data->m_early_suspend.resume = NULL;
+#endif
+
+ return retval;
+
+err_free_irq:
+ free_irq(platformdata->irq_number, rmi4_data);
+err_query_dev:
+ if (platformdata->regulator_en) {
+ regulator_disable(rmi4_data->regulator);
+ regulator_put(rmi4_data->regulator);
+ }
+err_regulator:
+ input_free_device(rmi4_data->input_dev);
+ rmi4_data->input_dev = NULL;
+err_input:
+ kfree(rmi4_data);
+
+ return retval;
+}
+/**
+ * synaptics_rmi4_remove() - Removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This function uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit synaptics_rmi4_remove(struct i2c_client *client)
+{
+ struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+ const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ if (rmi4_data->m_early_suspend.suspend && rmi4_data->m_early_suspend.resume)
+ unregister_early_suspend(&rmi4_data->m_early_suspend);
+#endif
+
+ rmi4_data->touch_stopped = true;
+ wake_up(&rmi4_data->wait);
+ free_irq(pdata->irq_number, rmi4_data);
+ input_unregister_device(rmi4_data->input_dev);
+ if (pdata->regulator_en) {
+ regulator_disable(rmi4_data->regulator);
+ regulator_put(rmi4_data->regulator);
+ }
+ kfree(rmi4_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void synaptics_rmi4_early_suspend(struct early_suspend *h)
+{
+ struct i2c_client *client = syna_client;
+ struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+
+ rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx
+
+ disable_irq(client->irq);
+ synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x00);
+
+}
+static void synaptics_rmi4_late_resume(struct early_suspend *h)
+{
+ struct i2c_client *client = syna_client;
+ struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+ int retval;
+ unsigned char intr_status;
+
+ rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx
+
+ enable_irq(client->irq);
+
+ retval = synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1,
+ &intr_status,
+ rmi4_data->number_of_interrupt_register);
+ if (retval < 0)
+ return;
+
+ synaptics_rmi4_i2c_byte_write(rmi4_data, rmi4_data->fn01_data_base_addr + 1, 0x0f);
+
+}
+#endif
+
+#ifdef CONFIG_PM
+/**
+ * synaptics_rmi4_suspend() - suspend the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int synaptics_rmi4_suspend(struct device *dev)
+{
+ /* Touch sleep mode */
+ int retval;
+ unsigned char intr_status;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+ rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx
+
+ rmi4_data->touch_stopped = true;
+ disable_irq(pdata->irq_number);
+
+ retval = synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1,
+ &intr_status,
+ rmi4_data->number_of_interrupt_register);
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_byte_write(rmi4_data,
+ rmi4_data->fn01_ctrl_base_addr + 1,
+ (intr_status & ~TOUCHPAD_CTRL_INTR));
+ if (retval < 0)
+ return retval;
+
+ if (pdata->regulator_en)
+ regulator_disable(rmi4_data->regulator);
+
+ return 0;
+}
+/**
+ * synaptics_rmi4_resume() - resume the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int synaptics_rmi4_resume(struct device *dev)
+{
+ int retval;
+ unsigned char intr_status;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+ rmi4_debug(DEBUG_TRACE, "%s: enter!\n", __func__); //rmi4_acgzx
+
+ if (pdata->regulator_en)
+ regulator_enable(rmi4_data->regulator);
+
+ enable_irq(pdata->irq_number);
+ rmi4_data->touch_stopped = false;
+
+ retval = synaptics_rmi4_i2c_block_read(rmi4_data,
+ rmi4_data->fn01_data_base_addr + 1,
+ &intr_status,
+ rmi4_data->number_of_interrupt_register);
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_byte_write(rmi4_data,
+ rmi4_data->fn01_ctrl_base_addr + 1,
+ (intr_status | TOUCHPAD_CTRL_INTR));
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+ .suspend = synaptics_rmi4_suspend,
+ .resume = synaptics_rmi4_resume,
+};
+#endif
+
+static const struct i2c_device_id synaptics_rmi4_id_table[] = {
+ { DRIVER_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+
+static struct i2c_driver synaptics_rmi4_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+#if (0 == CONFIG_HAS_EARLYSUSPEND) //rmi4_acgzx
+#ifdef CONFIG_PM
+ .pm = &synaptics_rmi4_dev_pm_ops,
+#endif
+#endif
+ },
+ .probe = synaptics_rmi4_probe,
+ .remove = __devexit_p(synaptics_rmi4_remove),
+ .id_table = synaptics_rmi4_id_table,
+};
+/**
+ * synaptics_rmi4_init() - Initialize the touchscreen driver
+ *
+ * This function uses to initializes the synaptics
+ * touchscreen driver and returns integer.
+ */
+static int __init synaptics_rmi4_init(void)
+{
+ return i2c_add_driver(&synaptics_rmi4_driver);
+}
+/**
+ * synaptics_rmi4_exit() - De-initialize the touchscreen driver
+ *
+ * This function uses to de-initialize the synaptics
+ * touchscreen driver and returns none.
+ */
+static void __exit synaptics_rmi4_exit(void)
+{
+ i2c_del_driver(&synaptics_rmi4_driver);
+}
+
+
+module_init(synaptics_rmi4_init);
+module_exit(synaptics_rmi4_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("naveen.gaddipati@stericsson.com, js.ha@stericsson.com");
+MODULE_DESCRIPTION("synaptics rmi4 i2c touch Driver");
+MODULE_ALIAS("i2c:synaptics_rmi4_ts");
+
+
+
+
--- /dev/null
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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.
+ *
+ *#############################################################################
+ */
+
+#ifndef _SYNAPTICS_RMI4_H_INCLUDED_
+#define _SYNAPTICS_RMI4_H_INCLUDED_
+
+
+/* Register Name Address Register Description */
+/* ------------- ------- -------------------- */
+#define SYNA_F34_FLASH_DATA00 0x0000 /* Block Number Low */
+#define SYNA_F34_FLASH_DATA01 0x0001 /* Block Number High */
+#define SYNA_F34_FLASH_DATA02_00 0x0002 /* Block Data 0 */
+#define SYNA_F34_FLASH_DATA02_01 0x0003 /* Block Data 1 */
+#define SYNA_F34_FLASH_DATA02_02 0x0004 /* Block Data 2 */
+#define SYNA_F34_FLASH_DATA02_03 0x0005 /* Block Data 3 */
+#define SYNA_F34_FLASH_DATA02_04 0x0006 /* Block Data 4 */
+#define SYNA_F34_FLASH_DATA02_05 0x0007 /* Block Data 5 */
+#define SYNA_F34_FLASH_DATA02_06 0x0008 /* Block Data 6 */
+#define SYNA_F34_FLASH_DATA02_07 0x0009 /* Block Data 7 */
+#define SYNA_F34_FLASH_DATA02_08 0x000A /* Block Data 8 */
+#define SYNA_F34_FLASH_DATA02_09 0x000B /* Block Data 9 */
+#define SYNA_F34_FLASH_DATA02_10 0x000C /* Block Data 10 */
+#define SYNA_F34_FLASH_DATA02_11 0x000D /* Block Data 11 */
+#define SYNA_F34_FLASH_DATA02_12 0x000E /* Block Data 12 */
+#define SYNA_F34_FLASH_DATA02_13 0x000F /* Block Data 13 */
+#define SYNA_F34_FLASH_DATA02_14 0x0010 /* Block Data 14 */
+#define SYNA_F34_FLASH_DATA02_15 0x0011 /* Block Data 15 */
+#define SYNA_F34_FLASH_DATA03 0x0012 /* Flash Control */
+#define SYNA_F01_RMI_DATA00 0x0013 /* Device Status */
+#define SYNA_F01_RMI_DATA01_00 0x0014 /* Interrupt Status */
+#define SYNA_F11_2D_DATA00_00 0x0015 /* 2D Finger State */
+#define SYNA_F11_2D_DATA00_01 0x0016 /* 2D Finger State */
+#define SYNA_F11_2D_DATA01_00 0x0017 /* 2D X Position (11:4) Finger 0 */
+#define SYNA_F11_2D_DATA02_00 0x0018 /* 2D Y Position (11:4) Finger 0 */
+#define SYNA_F11_2D_DATA03_00 0x0019 /* 2D Y/X Position (3:0) Finger 0 */
+#define SYNA_F11_2D_DATA04_00 0x001A /* 2D Wy/Wx Finger 0 */
+#define SYNA_F11_2D_DATA05_00 0x001B /* 2D Z Finger 0 */
+#define SYNA_F11_2D_DATA01_01 0x001C /* 2D X Position (11:4) Finger 1 */
+#define SYNA_F11_2D_DATA02_01 0x001D /* 2D Y Position (11:4) Finger 1 */
+#define SYNA_F11_2D_DATA03_01 0x001E /* 2D Y/X Position (3:0) Finger 1 */
+#define SYNA_F11_2D_DATA04_01 0x001F /* 2D Wy/Wx Finger 1 */
+#define SYNA_F11_2D_DATA05_01 0x0020 /* 2D Z Finger 1 */
+#define SYNA_F11_2D_DATA01_02 0x0021 /* 2D X Position (11:4) Finger 2 */
+#define SYNA_F11_2D_DATA02_02 0x0022 /* 2D Y Position (11:4) Finger 2 */
+#define SYNA_F11_2D_DATA03_02 0x0023 /* 2D Y/X Position (3:0) Finger 2 */
+#define SYNA_F11_2D_DATA04_02 0x0024 /* 2D Wy/Wx Finger 2 */
+#define SYNA_F11_2D_DATA05_02 0x0025 /* 2D Z Finger 2 */
+#define SYNA_F11_2D_DATA01_03 0x0026 /* 2D X Position (11:4) Finger 3 */
+#define SYNA_F11_2D_DATA02_03 0x0027 /* 2D Y Position (11:4) Finger 3 */
+#define SYNA_F11_2D_DATA03_03 0x0028 /* 2D Y/X Position (3:0) Finger 3 */
+#define SYNA_F11_2D_DATA04_03 0x0029 /* 2D Wy/Wx Finger 3 */
+#define SYNA_F11_2D_DATA05_03 0x002A /* 2D Z Finger 3 */
+#define SYNA_F11_2D_DATA01_04 0x002B /* 2D X Position (11:4) Finger 4 */
+#define SYNA_F11_2D_DATA02_04 0x002C /* 2D Y Position (11:4) Finger 4 */
+#define SYNA_F11_2D_DATA03_04 0x002D /* 2D Y/X Position (3:0) Finger 4 */
+#define SYNA_F11_2D_DATA04_04 0x002E /* 2D Wy/Wx Finger 4 */
+#define SYNA_F11_2D_DATA05_04 0x002F /* 2D Z Finger 4 */
+#define SYNA_F01_RMI_CTRL00 0x0030 /* Device Control */
+#define SYNA_F01_RMI_CTRL01_00 0x0031 /* Interrupt Enable 0 */
+#define SYNA_F11_2D_CTRL00 0x0032 /* 2D Report Mode */
+#define SYNA_F11_2D_CTRL01 0x0033 /* 2D Palm Detect */
+#define SYNA_F11_2D_CTRL02 0x0034 /* 2D Delta-X Thresh */
+#define SYNA_F11_2D_CTRL03 0x0035 /* 2D Delta-Y Thresh */
+#define SYNA_F11_2D_CTRL04 0x0036 /* 2D Velocity */
+#define SYNA_F11_2D_CTRL05 0x0037 /* 2D Acceleration */
+#define SYNA_F11_2D_CTRL06 0x0038 /* 2D Max X Position (7:0) */
+#define SYNA_F11_2D_CTRL07 0x0039 /* 2D Max X Position (11:8) */
+#define SYNA_F11_2D_CTRL08 0x003A /* 2D Max Y Position (7:0) */
+#define SYNA_F11_2D_CTRL09 0x003B /* 2D Max Y Position (11:8) */
+#define SYNA_F11_2D_CTRL12_00 0x003C /* 2D Sensor Map 0 */
+#define SYNA_F11_2D_CTRL12_01 0x003D /* 2D Sensor Map 1 */
+#define SYNA_F11_2D_CTRL12_02 0x003E /* 2D Sensor Map 2 */
+#define SYNA_F11_2D_CTRL12_03 0x003F /* 2D Sensor Map 3 */
+#define SYNA_F11_2D_CTRL12_04 0x0040 /* 2D Sensor Map 4 */
+#define SYNA_F11_2D_CTRL12_05 0x0041 /* 2D Sensor Map 5 */
+#define SYNA_F11_2D_CTRL12_06 0x0042 /* 2D Sensor Map 6 */
+#define SYNA_F11_2D_CTRL12_07 0x0043 /* 2D Sensor Map 7 */
+#define SYNA_F11_2D_CTRL12_08 0x0044 /* 2D Sensor Map 8 */
+#define SYNA_F11_2D_CTRL12_09 0x0045 /* 2D Sensor Map 9 */
+#define SYNA_F11_2D_CTRL12_10 0x0046 /* 2D Sensor Map 10 */
+#define SYNA_F11_2D_CTRL12_11 0x0047 /* 2D Sensor Map 11 */
+#define SYNA_F11_2D_CTRL12_12 0x0048 /* 2D Sensor Map 12 */
+#define SYNA_F11_2D_CTRL12_13 0x0049 /* 2D Sensor Map 13 */
+#define SYNA_F11_2D_CTRL12_14 0x004A /* 2D Sensor Map 14 */
+#define SYNA_F11_2D_CTRL12_15 0x004B /* 2D Sensor Map 15 */
+#define SYNA_F11_2D_CTRL12_16 0x004C /* 2D Sensor Map 16 */
+#define SYNA_F11_2D_CTRL12_17 0x004D /* 2D Sensor Map 17 */
+#define SYNA_F11_2D_CTRL12_18 0x004E /* 2D Sensor Map 18 */
+#define SYNA_F11_2D_CTRL12_19 0x004F /* 2D Sensor Map 19 */
+#define SYNA_F11_2D_CTRL12_20 0x0050 /* 2D Sensor Map 20 */
+#define SYNA_F11_2D_CTRL12_21 0x0051 /* 2D Sensor Map 21 */
+#define SYNA_F11_2D_CTRL12_22 0x0052 /* 2D Sensor Map 22 */
+#define SYNA_F11_2D_CTRL12_23 0x0053 /* 2D Sensor Map 23 */
+#define SYNA_F11_2D_CTRL12_24 0x0054 /* 2D Sensor Map 24 */
+#define SYNA_F11_2D_CTRL12_25 0x0055 /* 2D Sensor Map 25 */
+#define SYNA_F11_2D_CTRL12_26 0x0056 /* 2D Sensor Map 26 */
+#define SYNA_F11_2D_CTRL12_27 0x0057 /* 2D Sensor Map 27 */
+#define SYNA_F11_2D_CTRL12_28 0x0058 /* 2D Sensor Map 28 */
+#define SYNA_F11_2D_CTRL12_29 0x0059 /* 2D Sensor Map 29 */
+#define SYNA_F11_2D_CTRL12_30 0x005A /* 2D Sensor Map 30 */
+#define SYNA_F11_2D_CTRL12_31 0x005B /* 2D Sensor Map 31 */
+#define SYNA_F11_2D_CTRL12_32 0x005C /* 2D Sensor Map 32 */
+#define SYNA_F11_2D_CTRL12_33 0x005D /* 2D Sensor Map 33 */
+#define SYNA_F11_2D_CTRL12_34 0x005E /* 2D Sensor Map 34 */
+#define SYNA_F11_2D_CTRL12_35 0x005F /* 2D Sensor Map 35 */
+#define SYNA_F11_2D_CTRL12_36 0x0060 /* 2D Sensor Map 36 */
+#define SYNA_F11_2D_CTRL12_37 0x0061 /* 2D Sensor Map 37 */
+#define SYNA_F11_2D_CTRL12_38 0x0062 /* 2D Sensor Map 38 */
+#define SYNA_F11_2D_CTRL12_39 0x0063 /* 2D Sensor Map 39 */
+#define SYNA_F11_2D_CTRL12_40 0x0064 /* 2D Sensor Map 40 */
+#define SYNA_F11_2D_CTRL12_41 0x0065 /* 2D Sensor Map 41 */
+#define SYNA_F11_2D_CTRL12_42 0x0066 /* 2D Sensor Map 42 */
+#define SYNA_F11_2D_CTRL12_43 0x0067 /* 2D Sensor Map 43 */
+#define SYNA_F11_2D_CTRL12_44 0x0068 /* 2D Sensor Map 44 */
+#define SYNA_F11_2D_CTRL14 0x0096 /* 2D Sensitivity Adjustment */
+#define SYNA_F01_RMI_CMD00 0x0097 /* Device Command */
+#define SYNA_F11_2D_CMD00 0x0098 /* 2D Command */
+#define SYNA_F34_FLASH_QUERY00 0x0099 /* Bootloader ID 0 */
+#define SYNA_F34_FLASH_QUERY01 0x009A /* Bootloader ID 1 */
+#define SYNA_F34_FLASH_QUERY02 0x009B /* Flash Properties */
+#define SYNA_F34_FLASH_QUERY03 0x009C /* Block Size 0 */
+#define SYNA_F34_FLASH_QUERY04 0x009D /* Block Size 1 */
+#define SYNA_F34_FLASH_QUERY05 0x009E /* Firmware Block Count 0 */
+#define SYNA_F34_FLASH_QUERY06 0x009F /* Firmware Block Count 1 */
+#define SYNA_F34_FLASH_QUERY07 0x00A0 /* Configuration Block Count 0 */
+#define SYNA_F34_FLASH_QUERY08 0x00A1 /* Configuration Block Count 1 */
+#define SYNA_F01_RMI_QUERY00 0x00A2 /* Manufacturer ID Query */
+#define SYNA_F01_RMI_QUERY01 0x00A3 /* Product Properties Query */
+#define SYNA_F01_RMI_QUERY02 0x00A4 /* Customer Family Query */
+#define SYNA_F01_RMI_QUERY03 0x00A5 /* Firmware Revision Query */
+#define SYNA_F01_RMI_QUERY04 0x00A6 /* Device Serialization Query 0 */
+#define SYNA_F01_RMI_QUERY05 0x00A7 /* Device Serialization Query 1 */
+#define SYNA_F01_RMI_QUERY06 0x00A8 /* Device Serialization Query 2 */
+#define SYNA_F01_RMI_QUERY07 0x00A9 /* Device Serialization Query 3 */
+#define SYNA_F01_RMI_QUERY08 0x00AA /* Device Serialization Query 4 */
+#define SYNA_F01_RMI_QUERY09 0x00AB /* Device Serialization Query 5 */
+#define SYNA_F01_RMI_QUERY10 0x00AC /* Device Serialization Query 6 */
+#define SYNA_F01_RMI_QUERY11 0x00AD /* Product ID Query 0 */
+#define SYNA_F01_RMI_QUERY12 0x00AE /* Product ID Query 1 */
+#define SYNA_F01_RMI_QUERY13 0x00AF /* Product ID Query 2 */
+#define SYNA_F01_RMI_QUERY14 0x00B0 /* Product ID Query 3 */
+#define SYNA_F01_RMI_QUERY15 0x00B1 /* Product ID Query 4 */
+#define SYNA_F01_RMI_QUERY16 0x00B2 /* Product ID Query 5 */
+#define SYNA_F01_RMI_QUERY17 0x00B3 /* Product ID Query 6 */
+#define SYNA_F01_RMI_QUERY18 0x00B4 /* Product ID Query 7 */
+#define SYNA_F01_RMI_QUERY19 0x00B5 /* Product ID Query 8 */
+#define SYNA_F01_RMI_QUERY20 0x00B6 /* Product ID Query 9 */
+#define SYNA_F11_2D_QUERY00 0x00B7 /* Per-device Query */
+#define SYNA_F11_2D_QUERY01 0x00B8 /* 2D Reporting Mode */
+#define SYNA_F11_2D_QUERY02 0x00B9 /* 2D Number of X Electrodes */
+#define SYNA_F11_2D_QUERY03 0x00BA /* 2D Number of Y Electrodes */
+#define SYNA_F11_2D_QUERY04 0x00BB /* 2D Maximum Electrodes */
+#define SYNA_F11_2D_QUERY05 0x00BC /* 2D Absolute Query */
+
+/* Start of Page Description Table (PDT) */
+
+#define SYNA_PDT_P00_F11_2D_QUERY_BASE 0x00DD /* Query Base */
+#define SYNA_PDT_P00_F11_2D_COMMAND_BASE 0x00DE /* Command Base */
+#define SYNA_PDT_P00_F11_2D_CONTROL_BASE 0x00DF /* Control Base */
+#define SYNA_PDT_P00_F11_2D_DATA_BASE 0x00E0 /* Data Base */
+#define SYNA_PDT_P00_F11_2D_INTERRUPTS 0x00E1 /* Interrupt Source Count */
+#define SYNA_PDT_P00_F11_2D_EXISTS 0x00E2 /* Function Exists */
+#define SYNA_PDT_P00_F01_RMI_QUERY_BASE 0x00E3 /* Query Base */
+#define SYNA_PDT_P00_F01_RMI_COMMAND_BASE 0x00E4 /* Command Base */
+#define SYNA_PDT_P00_F01_RMI_CONTROL_BASE 0x00E5 /* Control Base */
+#define SYNA_PDT_P00_F01_RMI_DATA_BASE 0x00E6 /* Data Base */
+#define SYNA_PDT_P00_F01_RMI_INTERRUPTS 0x00E7 /* Interrupt Source Count */
+#define SYNA_PDT_P00_F01_RMI_EXISTS 0x00E8 /* Function Exists */
+#define SYNA_PDT_P00_F34_FLASH_QUERY_BASE 0x00E9 /* Query Base */
+#define SYNA_PDT_P00_F34_FLASH_COMMAND_BASE 0x00EA /* Command Base */
+#define SYNA_PDT_P00_F34_FLASH_CONTROL_BASE 0x00EB /* Control Base */
+#define SYNA_PDT_P00_F34_FLASH_DATA_BASE 0x00EC /* Data Base */
+#define SYNA_PDT_P00_F34_FLASH_INTERRUPTS 0x00ED /* Interrupt Source Count */
+#define SYNA_PDT_P00_F34_FLASH_EXISTS 0x00EE /* Function Exists */
+#define SYNA_P00_PDT_PROPERTIES 0x00EF /* P00_PDT Properties */
+#define SYNA_P00_PAGESELECT 0x00FF /* Page Select register */
+
+/* Registers on Page 0x01 */
+
+/* Register Name Address Register Description */
+/* ------------- ------- -------------------- */
+#define SYNA_F05_ANALOG_DATA00 0x0100 /* Reserved */
+#define SYNA_F05_ANALOG_DATA01 0x0101 /* Report Mode and Index */
+#define SYNA_F05_ANALOG_DATA02_00 0x0102 /* Report Data Window 0 */
+#define SYNA_F05_ANALOG_DATA02_01 0x0103 /* Report Data Window 1 */
+#define SYNA_F05_ANALOG_DATA02_02 0x0104 /* Report Data Window 2 */
+#define SYNA_F05_ANALOG_DATA02_03 0x0105 /* Report Data Window 3 */
+#define SYNA_F05_ANALOG_DATA02_04 0x0106 /* Report Data Window 4 */
+#define SYNA_F05_ANALOG_DATA02_05 0x0107 /* Report Data Window 5 */
+#define SYNA_F05_ANALOG_DATA02_06 0x0108 /* Report Data Window 6 */
+#define SYNA_F05_ANALOG_DATA02_07 0x0109 /* Report Data Window 7 */
+#define SYNA_F05_ANALOG_DATA02_08 0x010A /* Report Data Window 8 */
+#define SYNA_F05_ANALOG_DATA02_09 0x010B /* Report Data Window 9 */
+#define SYNA_F05_ANALOG_DATA02_10 0x010C /* Report Data Window 10 */
+#define SYNA_F05_ANALOG_DATA02_11 0x010D /* Report Data Window 11 */
+#define SYNA_F05_ANALOG_DATA02_12 0x010E /* Report Data Window 12 */
+#define SYNA_F05_ANALOG_DATA02_13 0x010F /* Report Data Window 13 */
+#define SYNA_F05_ANALOG_DATA02_14 0x0110 /* Report Data Window 14 */
+#define SYNA_F05_ANALOG_DATA02_15 0x0111 /* Report Data Window 15 */
+#define SYNA_F05_ANALOG_DATA02_16 0x0112 /* Report Data Window 16 */
+#define SYNA_F05_ANALOG_DATA02_17 0x0113 /* Report Data Window 17 */
+#define SYNA_F05_ANALOG_DATA02_18 0x0114 /* Report Data Window 18 */
+#define SYNA_F05_ANALOG_DATA02_19 0x0115 /* Report Data Window 19 */
+#define SYNA_F05_ANALOG_DATA02_20 0x0116 /* Report Data Window 20 */
+#define SYNA_F05_ANALOG_DATA02_21 0x0117 /* Report Data Window 21 */
+#define SYNA_F05_ANALOG_DATA02_22 0x0118 /* Report Data Window 22 */
+#define SYNA_F05_ANALOG_DATA02_23 0x0119 /* Report Data Window 23 */
+#define SYNA_F05_ANALOG_DATA02_24 0x011A /* Report Data Window 24 */
+#define SYNA_F05_ANALOG_DATA02_25 0x011B /* Report Data Window 25 */
+#define SYNA_F05_ANALOG_DATA02_26 0x011C /* Report Data Window 26 */
+#define SYNA_F05_ANALOG_DATA02_27 0x011D /* Report Data Window 27 */
+#define SYNA_F05_ANALOG_DATA02_28 0x011E /* Report Data Window 28 */
+#define SYNA_F05_ANALOG_DATA02_29 0x011F /* Report Data Window 29 */
+#define SYNA_F05_ANALOG_DATA02_30 0x0120 /* Report Data Window 30 */
+#define SYNA_F05_ANALOG_DATA02_31 0x0121 /* Report Data Window 31 */
+#define SYNA_F05_ANALOG_DATA02_32 0x0122 /* Report Data Window 32 */
+#define SYNA_F05_ANALOG_DATA02_33 0x0123 /* Report Data Window 33 */
+#define SYNA_F05_ANALOG_CTRL00 0x0124 /* Algo Control */
+#define SYNA_F05_ANALOG_CTRL01 0x0125 /* Reserved */
+#define SYNA_F05_ANALOG_CTRL02 0x0126 /* Reserved */
+#define SYNA_F05_ANALOG_CTRL03 0x0127 /* Reserved */
+#define SYNA_F05_ANALOG_CTRL04 0x0128 /* Reserved */
+#define SYNA_F05_ANALOG_CTRL05 0x0129 /* Reserved */
+#define SYNA_F05_ANALOG_CMD00 0x012A /* Analog Command */
+#define SYNA_F05_ANALOG_QUERY00 0x012B /* Receiver Electrodes */
+#define SYNA_F05_ANALOG_QUERY01 0x012C /* Transmitter Electrodes */
+#define SYNA_F05_ANALOG_QUERY02 0x012D /* Reserved */
+#define SYNA_F05_ANALOG_QUERY03 0x012E /* Features */
+#define SYNA_F05_ANALOG_QUERY04 0x012F /* Image Window Count */
+#define SYNA_F05_ANALOG_QUERY05 0x0130 /* Reserved */
+
+/* Start of Page Description Table (PDT) for Page 0x01 */
+
+#define SYNA_PDT_P01_F05_ANALOG_QUERY_BASE 0x01E9 /* Query Base */
+#define SYNA_PDT_P01_F05_ANALOG_COMMAND_BASE 0x01EA /* Command Base */
+#define SYNA_PDT_P01_F05_ANALOG_CONTROL_BASE 0x01EB /* Control Base */
+#define SYNA_PDT_P01_F05_ANALOG_DATA_BASE 0x01EC /* Data Base */
+#define SYNA_PDT_P01_F05_ANALOG_INTERRUPTS 0x01ED /* Interrupt Source Count */
+#define SYNA_PDT_P01_F05_ANALOG_EXISTS 0x01EE /* Function Exists */
+#define SYNA_P01_PDT_PROPERTIES 0x01EF /* P01_PDT Properties */
+#define SYNA_P01_PAGESELECT 0x01FF /* Page Select register */
+
+/* Offsets within the configuration block */
+
+/* Register Name Offset Register Description */
+/* ------------- ------ -------------------- */
+#define SYNA_F01_RMI_CTRL00_CFGBLK_OFS 0x0000 /* Device Control */
+#define SYNA_F01_RMI_CTRL01_00_CFGBLK_OFS 0x0001 /* Interrupt Enable 0 */
+#define SYNA_F11_2D_CTRL00_CFGBLK_OFS 0x0002 /* 2D Report Mode */
+#define SYNA_F11_2D_CTRL01_CFGBLK_OFS 0x0003 /* 2D Palm Detect */
+#define SYNA_F11_2D_CTRL02_CFGBLK_OFS 0x0004 /* 2D Delta-X Thresh */
+#define SYNA_F11_2D_CTRL03_CFGBLK_OFS 0x0005 /* 2D Delta-Y Thresh */
+#define SYNA_F11_2D_CTRL04_CFGBLK_OFS 0x0006 /* 2D Velocity */
+#define SYNA_F11_2D_CTRL05_CFGBLK_OFS 0x0007 /* 2D Acceleration */
+#define SYNA_F11_2D_CTRL06_CFGBLK_OFS 0x0008 /* 2D Max X Position (7:0) */
+#define SYNA_F11_2D_CTRL07_CFGBLK_OFS 0x0009 /* 2D Max X Position (11:8) */
+#define SYNA_F11_2D_CTRL08_CFGBLK_OFS 0x000A /* 2D Max Y Position (7:0) */
+#define SYNA_F11_2D_CTRL09_CFGBLK_OFS 0x000B /* 2D Max Y Position (11:8) */
+#define SYNA_F11_2D_CTRL12_00_CFGBLK_OFS 0x000C /* 2D Sensor Map 0 */
+#define SYNA_F11_2D_CTRL12_01_CFGBLK_OFS 0x000D /* 2D Sensor Map 1 */
+#define SYNA_F11_2D_CTRL12_02_CFGBLK_OFS 0x000E /* 2D Sensor Map 2 */
+#define SYNA_F11_2D_CTRL12_03_CFGBLK_OFS 0x000F /* 2D Sensor Map 3 */
+#define SYNA_F11_2D_CTRL12_04_CFGBLK_OFS 0x0010 /* 2D Sensor Map 4 */
+#define SYNA_F11_2D_CTRL12_05_CFGBLK_OFS 0x0011 /* 2D Sensor Map 5 */
+#define SYNA_F11_2D_CTRL12_06_CFGBLK_OFS 0x0012 /* 2D Sensor Map 6 */
+#define SYNA_F11_2D_CTRL12_07_CFGBLK_OFS 0x0013 /* 2D Sensor Map 7 */
+#define SYNA_F11_2D_CTRL12_08_CFGBLK_OFS 0x0014 /* 2D Sensor Map 8 */
+#define SYNA_F11_2D_CTRL12_09_CFGBLK_OFS 0x0015 /* 2D Sensor Map 9 */
+#define SYNA_F11_2D_CTRL12_10_CFGBLK_OFS 0x0016 /* 2D Sensor Map 10 */
+#define SYNA_F11_2D_CTRL12_11_CFGBLK_OFS 0x0017 /* 2D Sensor Map 11 */
+#define SYNA_F11_2D_CTRL12_12_CFGBLK_OFS 0x0018 /* 2D Sensor Map 12 */
+#define SYNA_F11_2D_CTRL12_13_CFGBLK_OFS 0x0019 /* 2D Sensor Map 13 */
+#define SYNA_F11_2D_CTRL12_14_CFGBLK_OFS 0x001A /* 2D Sensor Map 14 */
+#define SYNA_F11_2D_CTRL12_15_CFGBLK_OFS 0x001B /* 2D Sensor Map 15 */
+#define SYNA_F11_2D_CTRL12_16_CFGBLK_OFS 0x001C /* 2D Sensor Map 16 */
+#define SYNA_F11_2D_CTRL12_17_CFGBLK_OFS 0x001D /* 2D Sensor Map 17 */
+#define SYNA_F11_2D_CTRL12_18_CFGBLK_OFS 0x001E /* 2D Sensor Map 18 */
+#define SYNA_F11_2D_CTRL12_19_CFGBLK_OFS 0x001F /* 2D Sensor Map 19 */
+#define SYNA_F11_2D_CTRL12_20_CFGBLK_OFS 0x0020 /* 2D Sensor Map 20 */
+#define SYNA_F11_2D_CTRL12_21_CFGBLK_OFS 0x0021 /* 2D Sensor Map 21 */
+#define SYNA_F11_2D_CTRL12_22_CFGBLK_OFS 0x0022 /* 2D Sensor Map 22 */
+#define SYNA_F11_2D_CTRL12_23_CFGBLK_OFS 0x0023 /* 2D Sensor Map 23 */
+#define SYNA_F11_2D_CTRL12_24_CFGBLK_OFS 0x0024 /* 2D Sensor Map 24 */
+#define SYNA_F11_2D_CTRL12_25_CFGBLK_OFS 0x0025 /* 2D Sensor Map 25 */
+#define SYNA_F11_2D_CTRL12_26_CFGBLK_OFS 0x0026 /* 2D Sensor Map 26 */
+#define SYNA_F11_2D_CTRL12_27_CFGBLK_OFS 0x0027 /* 2D Sensor Map 27 */
+#define SYNA_F11_2D_CTRL12_28_CFGBLK_OFS 0x0028 /* 2D Sensor Map 28 */
+#define SYNA_F11_2D_CTRL12_29_CFGBLK_OFS 0x0029 /* 2D Sensor Map 29 */
+#define SYNA_F11_2D_CTRL12_30_CFGBLK_OFS 0x002A /* 2D Sensor Map 30 */
+#define SYNA_F11_2D_CTRL12_31_CFGBLK_OFS 0x002B /* 2D Sensor Map 31 */
+#define SYNA_F11_2D_CTRL12_32_CFGBLK_OFS 0x002C /* 2D Sensor Map 32 */
+#define SYNA_F11_2D_CTRL12_33_CFGBLK_OFS 0x002D /* 2D Sensor Map 33 */
+#define SYNA_F11_2D_CTRL12_34_CFGBLK_OFS 0x002E /* 2D Sensor Map 34 */
+#define SYNA_F11_2D_CTRL12_35_CFGBLK_OFS 0x002F /* 2D Sensor Map 35 */
+#define SYNA_F11_2D_CTRL12_36_CFGBLK_OFS 0x0030 /* 2D Sensor Map 36 */
+#define SYNA_F11_2D_CTRL12_37_CFGBLK_OFS 0x0031 /* 2D Sensor Map 37 */
+#define SYNA_F11_2D_CTRL12_38_CFGBLK_OFS 0x0032 /* 2D Sensor Map 38 */
+#define SYNA_F11_2D_CTRL12_39_CFGBLK_OFS 0x0033 /* 2D Sensor Map 39 */
+#define SYNA_F11_2D_CTRL12_40_CFGBLK_OFS 0x0034 /* 2D Sensor Map 40 */
+#define SYNA_F11_2D_CTRL12_41_CFGBLK_OFS 0x0035 /* 2D Sensor Map 41 */
+#define SYNA_F11_2D_CTRL12_42_CFGBLK_OFS 0x0036 /* 2D Sensor Map 42 */
+#define SYNA_F11_2D_CTRL12_43_CFGBLK_OFS 0x0037 /* 2D Sensor Map 43 */
+#define SYNA_F11_2D_CTRL12_44_CFGBLK_OFS 0x0038 /* 2D Sensor Map 44 */
+#define SYNA_F11_2D_CTRL14_CFGBLK_OFS 0x0066 /* 2D Sensitivity Adjustment */
+#define SYNA_F05_ANALOG_CTRL00_CFGBLK_OFS 0x0067 /* Algo Control */
+#define SYNA_F05_ANALOG_CTRL01_CFGBLK_OFS 0x0068 /* Reserved */
+#define SYNA_F05_ANALOG_CTRL02_CFGBLK_OFS 0x0069 /* Reserved */
+#define SYNA_F05_ANALOG_CTRL03_CFGBLK_OFS 0x006A /* Reserved */
+#define SYNA_F05_ANALOG_CTRL04_CFGBLK_OFS 0x006B /* Reserved */
+#define SYNA_F05_ANALOG_CTRL05_CFGBLK_OFS 0x006C /* Reserved */
+#define SYNA_CFGBLK_CRC1_CFGBLK_OFS 0x01FC /* Configuration CRC [7:0] */
+#define SYNA_CFGBLK_CRC2_CFGBLK_OFS 0x01FD /* Configuration CRC [15:8] */
+#define SYNA_CFGBLK_CRC3_CFGBLK_OFS 0x01FE /* Configuration CRC [23:16] */
+#define SYNA_CFGBLK_CRC4_CFGBLK_OFS 0x01FF /* Configuration CRC [31:24] */
+
+/* Masks for interrupt sources */
+
+/* Symbol Name Mask Description */
+/* ----------- ---- ----------- */
+#define SYNA_F01_RMI_INT_SOURCE_MASK_ALL 0x0002 /* Mask of all Func $01 (RMI) interrupts */
+#define SYNA_F01_RMI_INT_SOURCE_MASK_STATUS 0x0002 /* Mask of Func $01 (RMI) 'STATUS' interrupt */
+#define SYNA_F05_ANALOG_INT_SOURCE_MASK_ALL 0x0008 /* Mask of all Func $05 (ANALOG) interrupts */
+#define SYNA_F05_ANALOG_INT_SOURCE_MASK_ANALOG 0x0008 /* Mask of Func $05 (ANALOG) 'ANALOG' interrupt */
+#define SYNA_F11_2D_INT_SOURCE_MASK_ABS0 0x0004 /* Mask of Func $11 (2D) 'ABS0' interrupt */
+#define SYNA_F11_2D_INT_SOURCE_MASK_ALL 0x0004 /* Mask of all Func $11 (2D) interrupts */
+#define SYNA_F34_FLASH_INT_SOURCE_MASK_ALL 0x0001 /* Mask of all Func $34 (FLASH) interrupts */
+#define SYNA_F34_FLASH_INT_SOURCE_MASK_FLASH 0x0001 /* Mask of Func $34 (FLASH) 'FLASH' interrupt */
+
+/* cwz: change to arch/board.h */
+#if 1
+/**
+ * struct synaptics_rmi4_platform_data - contains the rmi4 platform data
+ * @irq_number: irq number
+ * @irq_type: irq type
+ * @x flip: x flip flag
+ * @y flip: y flip flag
+ * @regulator_en: regulator enable flag
+ *
+ * This structure gives platform data for rmi4.
+ */
+struct synaptics_rmi4_platform_data {
+ int irq_number;
+ int irq_type;
+ bool virtual_keys; //virtual_keys for touch screen without real keys
+ int lcd_width;
+ int lcd_height;
+ int w_delta;
+ int h_delta;
+ bool x_flip;
+ bool y_flip;
+ bool regulator_en;
+};
+#endif
+
+#endif /* _SYNAPTICS_RMI4_H_INCLUDED_ */