Home
Reading
Searching
Subscribe
Sponsors
Statistics
Posting
Contact
Spam
Lists
Links
About
Hosting
Filtering
Features Download
Marketing
Archives
FAQ
Blog
 
Gmane
From: Alexandra Chin <alexandra.chin <at> tw.synaptics.com>
Subject: [PATCH] Input: Add new driver into Input Subsystem for Synaptics DS4 touchscreen I2C devices
Newsgroups: gmane.linux.kernel.input
Date: Sunday 16th September 2012 09:56:22 UTC (over 4 years ago)
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  and
Naveen Kumar Gaddipati .

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 
---
 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 
+ * Copyright (C) 2012 Scott Lin 
+ * Copyright (C) 2010 Js HA 
+ * Copyright (C) 2010 Naveen Kumar G 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#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 
+ * Copyright (C) 2012 Scott Lin 
+ * Copyright (C) 2010 Js HA 
+ * Copyright (C) 2010 Naveen Kumar G 
+ *
+ * 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 
+ * Copyright (C) 2012 Scott Lin 
+ * Copyright (C) 2010 Js HA 
+ * Copyright (C) 2010 Naveen Kumar G 
+ *
+ * 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-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
 
CD: 4ms