Synaptics DS4 touchscreen driver implements a generic driver supporting I2C
protocol for Synaptics Design Studio 4 (DS4) family of Touchscreen Controllers
which include the following:

- S32xX series
- S730X series
- S22xx series

The driver supports multifinger pointing functionality and power management.
The driver is based on the original work submitted by
Linus Walleij <[email protected]> and
Naveen Kumar Gaddipati <[email protected]>.

This patch is against the v3.1-rc9 tag of Dmitry Torokhov's kernel tree,
commit bd68dfe0071b50bc69416a92ee22b63d1cc33a3b.

Changes in this patch:
 - modified:   drivers/input/touchscreen/Kconfig
 - modified:   drivers/input/touchscreen/Makefile
 - new file:   drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.c
 - new file:   drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.h
 - new file:   include/linux/input/synaptics_dsx.h

This patch is functionally tested on omap beagleboard-xm.

We will continue to maintain and support this driver officially, including 
making updates, as well as supporting future Touch Controller revisions 
from Synaptics.

Any comments are much appreciated.

Alexandra Chin

Signed-off-by: Alexandra Chin <[email protected]>
---
 drivers/input/touchscreen/Kconfig                  |   12 +
 drivers/input/touchscreen/Makefile                 |    1 +
 drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.c | 1085 ++++++++++++++++++++
 drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.h |   94 ++
 include/linux/input/synaptics_dsx.h                |   49 +
 5 files changed, 1241 insertions(+), 0 deletions(-)

diff --git a/drivers/input/touchscreen/Kconfig 
b/drivers/input/touchscreen/Kconfig
index 1ba232c..431c72b 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -900,4 +900,16 @@ config TOUCHSCREEN_TPS6507X
          To compile this driver as a module, choose M here: the
          module will be called tps6507x_ts.
 
+config TOUCHSCREEN_SYNAPTICS_DS4_RMI4_I2C
+       tristate "Synaptics ds4 i2c touchscreen"
+       depends on I2C
+       help
+         Say Y here if you have a Synaptics DS4 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_ds4_rmi4_i2c.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile 
b/drivers/input/touchscreen/Makefile
index 178eb12..61f5f22 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -73,3 +73,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)    += 
mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)      += zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)      += w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)     += tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DS4_RMI4_I2C)       += 
synaptics_ds4_rmi4_i2c.o
diff --git a/drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.c 
b/drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.c
new file mode 100644
index 0000000..c3bf46f
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.c
@@ -0,0 +1,1085 @@
+/*
+ * Synaptics DS4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <[email protected]>
+ * Copyright (C) 2012 Scott Lin <[email protected]>
+ * Copyright (C) 2010 Js HA <[email protected]>
+ * Copyright (C) 2010 Naveen Kumar G <[email protected]>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/input/synaptics_dsx.h>
+#include "synaptics_ds4_rmi4_i2c.h"
+
+#define DRIVER_NAME "synaptics_ds4_i2c"
+#define INPUT_PHYS_NAME "synaptics_ds4_i2c/input0"
+
+#define PAGES_TO_SERVICE       0xFF
+#define MAX_INTR_REGISTERS     4
+#define MAX_TOUCH_MAJOR        15
+#define BUF_LEN                37
+#define PAGE_LEN               2
+#define DATA_LEN               12
+#define QUERY_LEN              9
+#define DATA_BUF_LEN           10
+#define STD_QUERY_LEN  21
+
+#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
+#define TOUCH_CTRL_INTR        0x8
+
+#define NO_SLEEP_ON            (1 << 3)
+#define NO_SLEEP_OFF           (0 << 3)
+#define NORMAL_OPERATION       (0 << 0)
+#define SENSOR_SLEEP           (1 << 0)
+#define RMI4_NUMBER_OF_MAX_FINGERS     (10)
+
+#ifdef CONFIG_PM
+static int synaptics_rmi4_suspend(struct device *dev);
+static int synaptics_rmi4_resume(struct device *dev);
+#endif
+
+/*
+ * Called by synaptics_rmi4_i2c_read() and synaptics_rmi4_i2c_write().
+ *
+ * This function writes to the page select register to switch to the
+ * assigned page.
+ */
+static int synaptics_rmi4_set_page(struct synaptics_ds4_rmi4_data *pdata,
+                                       unsigned int address)
+{
+       unsigned char   txbuf[PAGE_LEN];
+       int retval = 0;
+       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)
+                       retval = -EIO;
+               else
+                       pdata->current_page = page;
+       } else
+               retval = PAGE_LEN;
+
+       return retval;
+}
+
+/*
+ * Called by various functions in this driver
+ *
+ * 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_ds4_rmi4_data *pdata,
+                       unsigned short addr, unsigned char *data,
+                       unsigned short length)
+{
+       int retval = 0;
+       unsigned char buf;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = pdata->i2c_client->addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &buf,
+               },
+               {
+                       .addr = pdata->i2c_client->addr,
+                       .flags = I2C_M_RD,
+                       .len = length,
+                       .buf = data,
+               }
+       };
+       buf = addr & MASK_8BIT;
+
+       mutex_lock(&(pdata->io_ctrl_mutex));
+       retval = synaptics_rmi4_set_page(pdata, addr);
+       if (retval != PAGE_LEN)
+               goto exit;
+       retval = i2c_transfer(pdata->i2c_client->adapter, msg, ARRAY_SIZE(msg));
+       if (retval != ARRAY_SIZE(msg))
+               retval = -EIO;
+exit:
+       mutex_unlock(&(pdata->io_ctrl_mutex));
+       return retval;
+}
+
+/*
+ * Called by various functions in this driver
+ *
+ * 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_ds4_rmi4_data *pdata,
+                       unsigned short addr, unsigned char *data,
+                       unsigned short length)
+{
+       int retval = 0;
+       unsigned char buf[length + 1];
+
+       struct i2c_msg msg[] = {
+               {
+                       .addr = pdata->i2c_client->addr,
+                       .flags = 0,
+                       .len = length + 1,
+                       .buf = buf,
+               }
+       };
+
+       mutex_lock(&(pdata->io_ctrl_mutex));
+       retval = synaptics_rmi4_set_page(pdata, addr);
+       if (retval != PAGE_LEN)
+               goto exit;
+
+       buf[0] = addr & MASK_8BIT;
+       memcpy(&buf[1], &data[0], length);
+
+       retval = i2c_transfer(pdata->i2c_client->adapter, msg, ARRAY_SIZE(msg));
+       if (retval != ARRAY_SIZE(msg))
+               retval = -EIO;
+exit:
+       mutex_unlock(&(pdata->io_ctrl_mutex));
+       return 0;
+}
+
+/*
+ * Called by synaptics_rmi4_report_device() 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
+ */
+static int synaptics_rmi4_abs_report(struct synaptics_ds4_rmi4_data *pdata,
+                       struct synaptics_ds4_rmi4_fn *function_handler)
+{
+       int touch_count = 0;    /* number of touch points */
+       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];
+
+       /* 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 = function_handler->num_of_data_points;
+       finger_registers = (fingers_supported + 3) / 4;
+       data_base_addr = function_handler->fn_full_addr.data_base_addr;
+
+       retval = synaptics_rmi4_i2c_read(pdata, data_base_addr, values,
+                                                       finger_registers);
+       if (retval < 0)
+               return retval;
+       /*
+        * For each finger present, read the proper number of registers
+        * to get absolute data.
+        */
+       data_reg_blk_size = function_handler->size_of_data_register_block;
+       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) {
+                       /* Read the finger data */
+                       data_offset = data_base_addr +
+                                       ((finger * data_reg_blk_size) +
+                                       finger_registers);
+                       retval = synaptics_rmi4_i2c_read(pdata,
+                                               data_offset, data,
+                                               data_reg_blk_size);
+                       if (retval < 0)
+                               return retval;
+                       else {
+                               x[touch_count] =
+                                       (data[0] << 4) | (data[2] & MASK_4BIT);
+                               y[touch_count] =
+                                       (data[1] << 4) |
+                                       ((data[2] >> 4) & MASK_4BIT);
+                               wy[touch_count] = (data[3] >> 4) & MASK_4BIT;
+                               wx[touch_count] = (data[3] & MASK_4BIT);
+
+                               if (pdata->board->x_flip)
+                                       x[touch_count] =
+                                               pdata->sensor_max_x -
+                                                               x[touch_count];
+                               if (pdata->board->y_flip)
+                                       y[touch_count] =
+                                               pdata->sensor_max_y -
+                                                               y[touch_count];
+                       }
+                       /* Number of active touch points */
+                       touch_count++;
+               }
+       }
+
+       /* Report to input subsystem */
+       if (touch_count) {
+               for (finger = 0; finger < touch_count; finger++) {
+                       input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR,
+                                               max(wx[finger] , wy[finger]));
+                       input_report_abs(pdata->input_dev, ABS_MT_POSITION_X,
+                                                               x[finger]);
+                       input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y,
+                                                               y[finger]);
+                       input_mt_sync(pdata->input_dev);
+               }
+       } else
+               input_mt_sync(pdata->input_dev);
+
+       /* sync after groups of events */
+       input_sync(pdata->input_dev);
+       return touch_count;
+}
+
+/*
+ * Called by synaptics_rmi4_sensor_report().
+ *
+ * This function calls the appropriate finger data reporting function
+ * based on the function handler it receives
+ */
+static int synaptics_rmi4_report_device(struct synaptics_ds4_rmi4_data *pdata,
+                               struct synaptics_ds4_rmi4_fn *function_handler)
+{
+       int touch_count = 0;
+       struct i2c_client *client = pdata->i2c_client;
+
+       dev_dbg(&pdata->i2c_client->dev, "%s: function number 0x%X\n",
+                               __func__, function_handler->fn_number);
+
+       switch (function_handler->fn_number) {
+       case SYNAPTICS_DS4_RMI4_2D_SENSOR_FUNC:
+               touch_count = synaptics_rmi4_abs_report(
+                                               pdata, function_handler);
+               break;
+       default:
+               dev_info(&client->dev, "%s: F%02X not supported\n",
+                                       __func__, function_handler->fn_number);
+               break;
+       }
+       return touch_count;
+}
+
+/*
+ * Called by synaptics_rmi4_irq().
+ *
+ * This function determines the interrupt source(s) from the sensor and
+ * calls synaptics_rmi4_report_device() with the appropriate function
+ * handler for each function with valid data inputs.
+ */
+static int synaptics_rmi4_sensor_report(struct synaptics_ds4_rmi4_data *pdata)
+{
+       unsigned char   intr_status[MAX_INTR_REGISTERS];
+       int retval;
+       int touch_count = 0;
+       struct synaptics_ds4_rmi4_fn *function_handler;
+       struct synaptics_ds4_rmi4_device_info *rmi;
+
+       /*
+        * 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_read(pdata,
+                                       pdata->fn01_data_base_addr + 1,
+                                       intr_status,
+                                       pdata->number_of_interrupt_register);
+       if (retval < 0)
+               return 0;
+
+       if (pdata->touch_stopped) {
+               dev_warn(&pdata->i2c_client->dev,
+                        "Not ready to handle interrupts yet!\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(function_handler, &rmi->support_fn_list, link) {
+               if (function_handler->num_of_data_sources) {
+                       if (intr_status[function_handler->index_to_intr_reg] &
+                                               function_handler->intr_mask)
+                               touch_count = synaptics_rmi4_report_device(
+                                               pdata, function_handler);
+               }
+       }
+       return touch_count;
+}
+
+/*
+ * 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.
+ */
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
+{
+       struct synaptics_ds4_rmi4_data *pdata = data;
+       int touch_count;
+       do {
+               touch_count = synaptics_rmi4_sensor_report(pdata);
+               if (touch_count)
+                       wait_event_timeout(pdata->wait, pdata->touch_stopped,
+                                                       msecs_to_jiffies(1));
+               else
+                       break;
+       } while (!pdata->touch_stopped);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Called by synaptics_rmi4_probe() and the power management functions in
+ * this driver
+ *
+ * This function handles the enabling of the attention irq
+ * including the setting up of the ISR thread.
+ */
+static int synaptics_rmi4_irq_enable(struct synaptics_ds4_rmi4_data *pdata,
+                                       bool request)
+{
+       int retval = 0;
+       char intr_status;
+       const struct synaptics_dsx_platform_data *platformdata =
+                               pdata->i2c_client->dev.platform_data;
+
+       mutex_lock(&pdata->irq_request_mutex);
+       if (pdata->irq_enabled)
+               goto exit;
+
+       /* Clear interrupts */
+       retval = synaptics_rmi4_i2c_read(pdata,
+                                       pdata->fn01_data_base_addr + 1,
+                                       &intr_status,
+                                       pdata->number_of_interrupt_register);
+       if (retval < 0)
+               return retval;
+       if (request) {
+               retval = request_threaded_irq(pdata->irq, NULL,
+                                         synaptics_rmi4_irq,
+                                         platformdata->irq_type,
+                                         DRIVER_NAME, pdata);
+               if (retval) {
+                       dev_err(&pdata->i2c_client->dev,
+                               "%s:Unable to get attn irq %d, type %d\n",
+                               __func__,
+                               pdata->irq,
+                               platformdata->irq_type);
+                       goto exit;
+               }
+       } else
+               enable_irq(pdata->irq);
+       pdata->irq_enabled  = true;
+
+exit:
+       mutex_unlock(&pdata->irq_request_mutex);
+       return retval;
+}
+
+/*
+ * Called by synaptics_rmi4_probe() and the power management functions in
+ * this driver
+ *
+ * This function handles the disabling of the attention irq
+ * including the setting up of the ISR thread.
+ */
+static int synaptics_rmi4_irq_disable(struct synaptics_ds4_rmi4_data *pdata,
+                                       bool release)
+{
+       int retval = 0;
+       mutex_lock(&pdata->irq_request_mutex);
+
+       if (pdata->irq_enabled) {
+               disable_irq(pdata->irq);
+               if (release)
+                       free_irq(pdata->irq, pdata);
+               pdata->irq_enabled = false;
+       } else
+               dev_warn(&pdata->i2c_client->dev,
+                        "%s:irq has not been reqested\n", __func__);
+       mutex_unlock(&pdata->irq_request_mutex);
+       return retval;
+}
+
+/*
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This funtion parses information from the Function 11 registers and
+ * determines the number of fingers supported, x and y data ranges,
+ * offset to the associated interrupt status register, interrupt bit mask,
+ * and gathers finger data acquisition capabilities from the query registers.
+ */
+static int synaptics_rmi4_2d_touch_detect(
+                               struct synaptics_ds4_rmi4_data *pdata,
+                               struct synaptics_ds4_rmi4_fn *function_handler,
+                               struct synaptics_ds4_rmi4_fn_desc *fd,
+                               unsigned int interruptcount)
+{
+       unsigned char   queries[QUERY_LEN];
+       unsigned char data[BUF_LEN];
+       unsigned char   abs_data_size;
+       unsigned char   abs_data_blk_size;
+       unsigned short intr_offset;
+       int i;
+       int retval;
+
+       function_handler->fn_number = fd->fn_number;
+       function_handler->num_of_data_sources = fd->intr_src_count;
+
+       /*
+        * 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_read(pdata,
+                               function_handler->fn_full_addr.query_base_addr,
+                               queries, sizeof(queries));
+       if (retval < 0)
+               return retval;
+
+       /* Number of fingers */
+       if ((queries[1] & MASK_3BIT) <= 4)      /* add 1 since zero based */
+               function_handler->num_of_data_points =
+                                       (queries[1] & MASK_3BIT) + 1;
+       else
+               if ((queries[1] & MASK_3BIT) == 5)
+                       function_handler->num_of_data_points = 10;
+
+       /* Max x/y */
+       retval = synaptics_rmi4_i2c_read(pdata,
+                               function_handler->fn_full_addr.ctrl_base_addr,
+                               data, DATA_BUF_LEN);
+       if (retval < 0)
+               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);
+
+
+       /* Interrupt info for handling interrupts */
+       function_handler->index_to_intr_reg = (interruptcount + 7) / 8;
+       if (function_handler->index_to_intr_reg != 0)
+               function_handler->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;
+       function_handler->intr_mask = 0;
+       for (i = intr_offset;
+               i < ((fd->intr_src_count & MASK_3BIT) + intr_offset); i++)
+               function_handler->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));
+       function_handler->size_of_data_register_block = abs_data_blk_size;
+
+       return retval;
+}
+
+static int synaptics_rmi4_alloc_func_handler(
+                       struct synaptics_ds4_rmi4_fn **function_handler,
+                       struct synaptics_ds4_rmi4_fn_desc *rmi_fd,
+                       int page_number)
+{
+       *function_handler =
+               kmalloc(sizeof(struct synaptics_ds4_rmi4_fn), GFP_KERNEL);
+       if (!(*function_handler)) {
+               return -ENOMEM;
+       }
+       (*function_handler)->fn_full_addr.data_base_addr =
+               (rmi_fd->data_base_addr | (page_number << 8));
+       (*function_handler)->fn_full_addr.ctrl_base_addr =
+               (rmi_fd->ctrl_base_addr | (page_number << 8));
+       (*function_handler)->fn_full_addr.cmd_base_addr =
+               (rmi_fd->cmd_base_addr | (page_number << 8));
+       (*function_handler)->fn_full_addr.query_base_addr =
+               (rmi_fd->query_base_addr | (page_number << 8));
+       return 0;
+}
+
+/*
+ * Called by synaptics_rmi4_probe().
+ *
+ * This funtion scans the page description table, records the offsets to the
+ * register types of Function $01, sets up the function handlers for Function
+ * $11, 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_ds4_rmi4_data *pdata)
+{
+       int i, page_number;
+       int retval;
+       int data_sources = 0;
+       unsigned char std_queries[STD_QUERY_LEN];
+       unsigned char interrupt_mask[MAX_INTR_REGISTERS];
+       unsigned char intr_count = 0;
+       unsigned char intr_index = 0;
+       unsigned short ctrl_offset;
+       struct synaptics_ds4_rmi4_fn *function_handler;
+       struct synaptics_ds4_rmi4_fn_desc rmi_fd;
+       struct synaptics_ds4_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);
+
+       /* Scan the Page Descriptor Table */
+       for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
+               for (i = SYNAPTICS_DS4_RMI4_PDT_START;
+                       i > SYNAPTICS_DS4_RMI4_PDT_END;
+                       i -= SYNAPTICS_DS4_RMI4_PDT_ENTRY_SIZE) {
+                       function_handler = NULL;
+                       i |= (page_number << 8);
+
+                       retval = synaptics_rmi4_i2c_read(pdata, i,
+                                               (unsigned char *)&rmi_fd,
+                                               sizeof(rmi_fd));
+                       if (retval < 0)
+                               return retval;
+
+                       if (rmi_fd.fn_number == 0)      /* end of the PDT */
+                               break;
+                       dev_dbg(&pdata->i2c_client->dev,
+                                       "%s: function F%02X is present\n",
+                                       __func__, rmi_fd.fn_number);
+                       switch (rmi_fd.fn_number & MASK_8BIT) {
+                       case SYNAPTICS_DS4_RMI4_DEVICE_CONTROL_FUNC:
+                               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;
+                               break;
+                       case SYNAPTICS_DS4_RMI4_2D_SENSOR_FUNC:
+                               if (rmi_fd.intr_src_count) {
+                                       retval =
+                                       synaptics_rmi4_alloc_func_handler(
+                                                       &function_handler,
+                                                       &rmi_fd,
+                                                       page_number);
+                                       if (retval < 0)
+                                               return retval;
+                                       retval =
+                                       synaptics_rmi4_2d_touch_detect(
+                                                       pdata,
+                                                       function_handler,
+                                                       &rmi_fd,
+                                                       intr_count);
+                                       if (retval < 0)
+                                               return retval;
+                               }
+                               break;
+                       }
+                       /* interrupt count for next iteration */
+                       intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+                       /*
+                        * add functions to the list that have data associated
+                        */
+                       if (function_handler && rmi_fd.intr_src_count) {
+                               /* link this function info to RMI module */
+                               mutex_lock(&(pdata->fn_list_mutex));
+                               dev_dbg(&pdata->i2c_client->dev,
+                                   "%s: add fiunction handler 0x%X to list\n",
+                                   __func__, function_handler->fn_number);
+                               list_add_tail(&function_handler->link,
+                                       &pdata->rmi4_mod_info.support_fn_list);
+                               mutex_unlock(&(pdata->fn_list_mutex));
+                       }
+               }
+       }
+       /*
+        * 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;
+       dev_dbg(&client->dev, "%s: interrupt register count :%d\n",
+                                       __func__,
+                                       pdata->number_of_interrupt_register);
+
+       /* Load up the standard queries and get the RMI4 module info */
+       retval = synaptics_rmi4_i2c_read(pdata, pdata->fn01_query_base_addr,
+                                       std_queries, sizeof(std_queries));
+       if (retval < 0)
+               return retval;
+
+       /*
+        * 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);
+
+       /* 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);
+
+       memset(interrupt_mask, 0x00, sizeof(interrupt_mask));
+       list_for_each_entry(function_handler,
+                       &pdata->rmi4_mod_info.support_fn_list, link)
+                       data_sources += function_handler->num_of_data_sources;
+       if (data_sources) {
+               rmi = &(pdata->rmi4_mod_info);
+               list_for_each_entry(function_handler,
+                                       &rmi->support_fn_list, link) {
+                       if (function_handler->num_of_data_sources)
+                               intr_index =
+                                       function_handler->index_to_intr_reg;
+                               interrupt_mask[intr_index] |=
+                               function_handler->intr_mask;
+               }
+       }
+
+       for (i = 0; i < MAX_INTR_REGISTERS; i++) {
+               if (interrupt_mask[i] != 0x00) {
+                       dev_dbg(&client->dev,
+                                       "%s: interrupt %d enable mask :0x%X\n",
+                                       __func__, i, interrupt_mask[i]);
+                       ctrl_offset = pdata->fn01_ctrl_base_addr + 1 + i;
+                       retval = synaptics_rmi4_i2c_write(pdata,
+                                                       ctrl_offset,
+                                                       &(interrupt_mask[i]),
+                                                       
sizeof(interrupt_mask[i]));
+                       if (retval < 0)
+                               return retval;
+               }
+       }
+       return 0;
+}
+
+static int __devinit synaptics_rmi4_probe(
+               struct i2c_client *client, const struct i2c_device_id *dev_id)
+{
+       int retval;
+       struct synaptics_ds4_rmi4_data *pdata;
+       struct synaptics_ds4_rmi4_fn *function_handler;
+       const struct synaptics_dsx_platform_data *platformdata =
+                                               client->dev.platform_data;
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "i2c smbus byte data not supported\n");
+               return -EIO;
+       }
+
+       if (!platformdata) {
+               dev_err(&client->dev, "%s: no platform data\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Allocate and initialize the instance data for this client */
+       pdata = kzalloc(sizeof(struct synaptics_ds4_rmi4_data) * 2,
+                                                       GFP_KERNEL);
+       if (!pdata) {
+               dev_err(&client->dev, "%s: no memory allocated\n", __func__);
+               return -ENOMEM;
+       }
+
+       pdata->input_dev = input_allocate_device();
+       if (pdata->input_dev == NULL) {
+               dev_err(&client->dev, "%s:input device alloc failed\n",
+                                               __func__);
+               retval = -ENOMEM;
+               goto err_input;
+       }
+
+       if (platformdata->regulator_en) {
+               pdata->regulator = regulator_get(&client->dev, "vdd");
+               if (IS_ERR(pdata->regulator)) {
+                       dev_err(&client->dev, "%s:get regulator failed\n",
+                                                               __func__);
+                       retval = PTR_ERR(pdata->regulator);
+                       goto err_regulator;
+               }
+               regulator_enable(pdata->regulator);
+       }
+       init_waitqueue_head(&pdata->wait);
+       pdata->i2c_client               = client;
+       pdata->current_page     = MASK_16BIT;
+       pdata->board            = platformdata;
+       pdata->sensor_sleep     = false;
+       pdata->irq_enabled      = false;
+       pdata->touch_stopped    = false;
+
+       /* Init the mutexes for maintain the lists */
+       mutex_init(&(pdata->fn_list_mutex));
+       mutex_init(&(pdata->io_ctrl_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_query_device(pdata);
+       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, pdata);
+
+       /* Initialize the input device parameters */
+       pdata->input_dev->name = DRIVER_NAME;
+       pdata->input_dev->phys = INPUT_PHYS_NAME;
+       pdata->input_dev->id.bustype = BUS_I2C;
+       pdata->input_dev->dev.parent = &client->dev;
+       input_set_drvdata(pdata->input_dev, pdata);
+
+       /* Initialize the function handlers for rmi4 */
+       set_bit(EV_SYN, pdata->input_dev->evbit);
+       set_bit(EV_KEY, pdata->input_dev->evbit);
+       set_bit(EV_ABS, pdata->input_dev->evbit);
+#ifdef INPUT_PROP_DIRECT
+       set_bit(INPUT_PROP_DIRECT, pdata->input_dev->propbit);
+#endif
+
+       input_set_abs_params(pdata->input_dev, ABS_MT_POSITION_X, 0,
+                                               pdata->sensor_max_x, 0, 0);
+       input_set_abs_params(pdata->input_dev, ABS_MT_POSITION_Y, 0,
+                                               pdata->sensor_max_y, 0, 0);
+       input_set_abs_params(pdata->input_dev, ABS_MT_TOUCH_MAJOR, 0,
+                                               MAX_TOUCH_MAJOR, 0, 0);
+
+       retval = input_register_device(pdata->input_dev);
+       if (retval) {
+               dev_err(&client->dev, "%s:input register failed\n", __func__);
+               goto err_query_dev;
+       }
+
+       /* Gpio configuration */
+       if (platformdata->gpio_config) {
+               retval = platformdata->gpio_config(platformdata->gpio, true);
+               if (retval < 0) {
+                       dev_err(&client->dev,
+                               "Failed to configure GPIOs, code: %d.\n",
+                               retval);
+                       return retval;
+               }
+               dev_info(&client->dev, "Done with GPIO configuration.\n");
+       }
+       pdata->irq = gpio_to_irq(platformdata->gpio);
+       mutex_init(&(pdata->irq_request_mutex));
+       pdata->touch_stopped = false;
+       retval = synaptics_rmi4_irq_enable(pdata, true);
+       if (retval) {
+               dev_err(&client->dev,
+                       "%s:Unable to get attn irq %d, type %d\n, name: %s",
+                       __func__, pdata->irq, platformdata->irq_type,
+                       DRIVER_NAME);
+               goto err_request_irq;
+       }
+
+       return retval;
+
+err_request_irq:
+       input_unregister_device(pdata->input_dev);
+err_query_dev:
+       if (platformdata->regulator_en) {
+               regulator_disable(pdata->regulator);
+               regulator_put(pdata->regulator);
+       }
+
+       if (!list_empty(&pdata->rmi4_mod_info.support_fn_list)) {
+               list_for_each_entry(function_handler,
+                       &pdata->rmi4_mod_info.support_fn_list, link) {
+                       if (function_handler) {
+                               if (function_handler->data)
+                                       kfree(function_handler->data);
+                               kfree(function_handler);
+                       }
+               }
+       }
+
+err_regulator:
+       input_free_device(pdata->input_dev);
+       pdata->input_dev = NULL;
+err_input:
+       kfree(pdata);
+
+       return retval;
+}
+
+static int __devexit synaptics_rmi4_remove(struct i2c_client *client)
+{
+       struct synaptics_ds4_rmi4_data *pdata = i2c_get_clientdata(client);
+       const struct synaptics_dsx_platform_data *platformdata = pdata->board;
+
+       pdata->touch_stopped = true;
+       synaptics_rmi4_irq_disable(pdata, true);
+
+       input_unregister_device(pdata->input_dev);
+       if (platformdata->regulator_en) {
+               regulator_disable(pdata->regulator);
+               regulator_put(pdata->regulator);
+       }
+       kfree(pdata);
+       return 0;
+}
+
+/*
+ * Called by synaptics_rmi4_early_suspend() and synaptics_rmi4_suspend().
+ *
+ * This function stops finger data acquisition and puts the sensor to sleep.
+ */
+static void synaptics_rmi4_sensor_sleep(struct synaptics_ds4_rmi4_data *pdata)
+{
+       int retval;
+       unsigned char device_ctrl;
+
+       if (pdata->sensor_sleep == true)
+               return;
+
+       pdata->touch_stopped = true;
+       wake_up(&pdata->wait);
+
+       retval = synaptics_rmi4_i2c_read(pdata,
+                               pdata->fn01_ctrl_base_addr,
+                               &device_ctrl,
+                               1);
+
+       if (retval < 0) {
+               dev_err(&(pdata->input_dev->dev),
+                       "Failed to enter sleep mode. Code: %d.\n", retval);
+               pdata->sensor_sleep = false;
+               return;
+       }
+
+       device_ctrl = (device_ctrl & ~MASK_3BIT);
+       device_ctrl = (device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP);
+
+       retval = synaptics_rmi4_i2c_write(pdata, pdata->fn01_ctrl_base_addr,
+                                               &device_ctrl, 1);
+
+       if (retval < 0) {
+               dev_err(&(pdata->input_dev->dev),
+                       "Failed to enter sleep mode. Code: %d.\n", retval);
+               pdata->sensor_sleep = false;
+               return;
+       } else
+               pdata->sensor_sleep = true;
+
+       return;
+}
+
+/*
+ * Called by synaptics_rmi4_resume() and synaptics_rmi4_late_resume().
+ *
+ * This function wakes the sensor from sleep.
+ */
+static void synaptics_rmi4_sensor_wake(struct synaptics_ds4_rmi4_data *pdata)
+{
+       int retval;
+       unsigned char device_ctrl;
+
+       if (pdata->sensor_sleep == false)
+               return;
+       retval = synaptics_rmi4_i2c_read(pdata,
+                               pdata->fn01_ctrl_base_addr,
+                               &device_ctrl,
+                               1);
+
+       if (retval < 0) {
+               dev_err(&(pdata->input_dev->dev),
+                       "Failed to wake from sleep mode. Code: %d.\n",
+                       retval);
+               pdata->sensor_sleep = true;
+               return;
+       }
+
+       device_ctrl = (device_ctrl & ~MASK_3BIT);
+       device_ctrl = (device_ctrl | NO_SLEEP_OFF | NORMAL_OPERATION);
+
+       retval = synaptics_rmi4_i2c_write(pdata, pdata->fn01_ctrl_base_addr,
+                                               &device_ctrl, 1);
+
+       if (retval < 0) {
+               dev_err(&(pdata->input_dev->dev),
+                       "Failed to wake from sleep mode. Code: %d.\n",
+                       retval);
+               pdata->sensor_sleep = true;
+               return;
+       } else
+               pdata->sensor_sleep = false;
+
+       return;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Called by the kernel during the suspend phase when the system
+ * enters suspend.
+ *
+ * This function stops finger data acquisition and puts the sensor to
+ * sleep (if not already done so during the early suspend phase),
+ * disables the interrupt, and turns off the power to the sensor.
+ */
+static int synaptics_rmi4_suspend(struct device *dev)
+{
+       struct synaptics_ds4_rmi4_data *pdata = dev_get_drvdata(dev);
+       const struct synaptics_dsx_platform_data *platformdata = pdata->board;
+
+       synaptics_rmi4_irq_disable(pdata, false);
+       synaptics_rmi4_sensor_sleep(pdata);
+
+       if (platformdata->regulator_en)
+               regulator_disable(pdata->regulator);
+       return 0;
+}
+
+/*
+ * 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 synaptics_rmi4_resume(struct device *dev)
+{
+       struct synaptics_ds4_rmi4_data *pdata = dev_get_drvdata(dev);
+       const struct synaptics_dsx_platform_data *platformdata = pdata->board;
+
+       if (platformdata->regulator_en)
+               regulator_enable(pdata->regulator);
+
+       synaptics_rmi4_sensor_wake(pdata);
+       synaptics_rmi4_irq_enable(pdata, false);
+       pdata->touch_stopped = false;
+
+       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,
+#ifdef CONFIG_PM
+               .pm     =       &synaptics_rmi4_dev_pm_ops,
+#endif
+       },
+       .probe          =       synaptics_rmi4_probe,
+       .remove         =       __devexit_p(synaptics_rmi4_remove),
+       .id_table       =       synaptics_rmi4_id_table,
+};
+
+static int __init synaptics_rmi4_init(void)
+{
+       return i2c_add_driver(&synaptics_rmi4_driver);
+}
+
+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");
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("synaptics ds4 i2c touch driver");
\ No newline at end of file
diff --git a/drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.h 
b/drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.h
new file mode 100644
index 0000000..58329d9
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_ds4_rmi4_i2c.h
@@ -0,0 +1,94 @@
+/*
+ * Synaptics DS4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <[email protected]>
+ * Copyright (C) 2012 Scott Lin <[email protected]>
+ * Copyright (C) 2010 Js HA <[email protected]>
+ * Copyright (C) 2010 Naveen Kumar G <[email protected]>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SYNAPTICS_DS4_RMI4_H_
+#define _SYNAPTICS_DS4_RMI4_H_
+
+#define SYNAPTICS_DS4_RMI4_PDT_START                           (0x00E9)
+#define SYNAPTICS_DS4_RMI4_PDT_END                             (0x000A)
+#define SYNAPTICS_DS4_RMI4_PDT_ENTRY_SIZE              (0x0006)
+#define SYNAPTICS_DS4_RMI4_DEVICE_CONTROL_FUNC (0x01)
+#define SYNAPTICS_DS4_RMI4_2D_SENSOR_FUNC              (0x11)
+
+/* funtion descriptor information */
+struct synaptics_ds4_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;
+};
+
+/*  funtion information */
+struct synaptics_ds4_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_ds4_rmi4_fn_desc fn_full_addr;
+       struct list_head link;
+       void *data;
+};
+
+/* device information */
+struct synaptics_ds4_rmi4_device_info {
+       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;
+};
+
+/* ds4 rmi4 touch screen data */
+struct synaptics_ds4_rmi4_data {
+       const struct synaptics_dsx_platform_data *board;
+       struct input_dev *input_dev;
+       struct i2c_client *i2c_client;
+       struct mutex fn_list_mutex;
+       struct mutex io_ctrl_mutex;
+       struct mutex irq_request_mutex;
+       struct synaptics_ds4_rmi4_device_info rmi4_mod_info;
+       struct regulator *regulator;
+       unsigned int number_of_interrupt_register;
+       unsigned short current_page;
+       unsigned short fn01_ctrl_base_addr;
+       unsigned short fn01_query_base_addr;
+       unsigned short fn01_data_base_addr;
+       unsigned short sensor_max_x;
+       unsigned short sensor_max_y;
+       wait_queue_head_t        wait;
+       bool touch_stopped;
+       bool irq_enabled;
+       bool sensor_sleep;
+       int irq;
+};
+
+#endif
diff --git a/include/linux/input/synaptics_dsx.h 
b/include/linux/input/synaptics_dsx.h
new file mode 100644
index 0000000..4f0d0d6
--- /dev/null
+++ b/include/linux/input/synaptics_dsx.h
@@ -0,0 +1,49 @@
+/*
+ * Synaptics DS4 touchscreen driver
+ *
+ * Copyright (C) 2012 Synaptics Incorporated
+ *
+ * Copyright (C) 2012 Alexandra Chin <[email protected]>
+ * Copyright (C) 2012 Scott Lin <[email protected]>
+ * Copyright (C) 2010 Js HA <[email protected]>
+ * Copyright (C) 2010 Naveen Kumar G <[email protected]>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SYNAPTICS_DSX_H_
+#define _SYNAPTICS_DSX_H_
+
+/*
+ * struct synaptics_dsx_platform_data - contains the dsx platform data
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * @regulator_en: regulator enable flag
+ * @irq_type: irq type
+ * @gpio: gpio pin assignment
+ * @gpio_config: callback for gpio set up
+ *
+ * This structure gives platform data for dsx.
+ */
+struct synaptics_dsx_platform_data {
+       bool x_flip;
+       bool y_flip;
+       bool regulator_en;
+       int irq_type;
+       unsigned gpio;
+       int (*gpio_config)(unsigned interrupt_gpio, bool configure);
+};
+
+#endif
-----
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to