zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/88pm860x-ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/88pm860x-ts.c
new file mode 100644
index 0000000..05f30b7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/88pm860x-ts.c
@@ -0,0 +1,226 @@
+/*
+ * Touchscreen driver for Marvell 88PM860x
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * 	Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/slab.h>
+
+#define MEAS_LEN		(8)
+#define ACCURATE_BIT		(12)
+
+/* touch register */
+#define MEAS_EN3		(0x52)
+
+#define MEAS_TSIX_1		(0x8D)
+#define MEAS_TSIX_2		(0x8E)
+#define MEAS_TSIY_1		(0x8F)
+#define MEAS_TSIY_2		(0x90)
+#define MEAS_TSIZ1_1		(0x91)
+#define MEAS_TSIZ1_2		(0x92)
+#define MEAS_TSIZ2_1		(0x93)
+#define MEAS_TSIZ2_2		(0x94)
+
+/* bit definitions of touch */
+#define MEAS_PD_EN		(1 << 3)
+#define MEAS_TSIX_EN		(1 << 4)
+#define MEAS_TSIY_EN		(1 << 5)
+#define MEAS_TSIZ1_EN		(1 << 6)
+#define MEAS_TSIZ2_EN		(1 << 7)
+
+struct pm860x_touch {
+	struct input_dev *idev;
+	struct i2c_client *i2c;
+	struct pm860x_chip *chip;
+	int irq;
+	int res_x;		/* resistor of Xplate */
+};
+
+static irqreturn_t pm860x_touch_handler(int irq, void *data)
+{
+	struct pm860x_touch *touch = data;
+	struct pm860x_chip *chip = touch->chip;
+	unsigned char buf[MEAS_LEN];
+	int x, y, pen_down;
+	int z1, z2, rt = 0;
+	int ret;
+
+	ret = pm860x_bulk_read(touch->i2c, MEAS_TSIX_1, MEAS_LEN, buf);
+	if (ret < 0)
+		goto out;
+
+	pen_down = buf[1] & (1 << 6);
+	x = ((buf[0] & 0xFF) << 4) | (buf[1] & 0x0F);
+	y = ((buf[2] & 0xFF) << 4) | (buf[3] & 0x0F);
+	z1 = ((buf[4] & 0xFF) << 4) | (buf[5] & 0x0F);
+	z2 = ((buf[6] & 0xFF) << 4) | (buf[7] & 0x0F);
+
+	if (pen_down) {
+		if ((x != 0) && (z1 != 0) && (touch->res_x != 0)) {
+			rt = z2 / z1 - 1;
+			rt = (rt * touch->res_x * x) >> ACCURATE_BIT;
+			dev_dbg(chip->dev, "z1:%d, z2:%d, rt:%d\n",
+				z1, z2, rt);
+		}
+		input_report_abs(touch->idev, ABS_X, x);
+		input_report_abs(touch->idev, ABS_Y, y);
+		input_report_abs(touch->idev, ABS_PRESSURE, rt);
+		input_report_key(touch->idev, BTN_TOUCH, 1);
+		dev_dbg(chip->dev, "pen down at [%d, %d].\n", x, y);
+	} else {
+		input_report_abs(touch->idev, ABS_PRESSURE, 0);
+		input_report_key(touch->idev, BTN_TOUCH, 0);
+		dev_dbg(chip->dev, "pen release\n");
+	}
+	input_sync(touch->idev);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int pm860x_touch_open(struct input_dev *dev)
+{
+	struct pm860x_touch *touch = input_get_drvdata(dev);
+	int data, ret;
+
+	data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN
+		| MEAS_TSIZ1_EN | MEAS_TSIZ2_EN;
+	ret = pm860x_set_bits(touch->i2c, MEAS_EN3, data, data);
+	if (ret < 0)
+		goto out;
+	return 0;
+out:
+	return ret;
+}
+
+static void pm860x_touch_close(struct input_dev *dev)
+{
+	struct pm860x_touch *touch = input_get_drvdata(dev);
+	int data;
+
+	data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN
+		| MEAS_TSIZ1_EN | MEAS_TSIZ2_EN;
+	pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0);
+}
+
+static int __devinit pm860x_touch_probe(struct platform_device *pdev)
+{
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm860x_platform_data *pm860x_pdata =		\
+				pdev->dev.parent->platform_data;
+	struct pm860x_touch_pdata *pdata = NULL;
+	struct pm860x_touch *touch;
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "No IRQ resource!\n");
+		return -EINVAL;
+	}
+
+	if (!pm860x_pdata) {
+		dev_err(&pdev->dev, "platform data is missing\n");
+		return -EINVAL;
+	}
+
+	pdata = pm860x_pdata->touch;
+	if (!pdata) {
+		dev_err(&pdev->dev, "touchscreen data is missing\n");
+		return -EINVAL;
+	}
+
+	touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
+	if (touch == NULL)
+		return -ENOMEM;
+	dev_set_drvdata(&pdev->dev, touch);
+
+	touch->idev = input_allocate_device();
+	if (touch->idev == NULL) {
+		dev_err(&pdev->dev, "Failed to allocate input device!\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	touch->idev->name = "88pm860x-touch";
+	touch->idev->phys = "88pm860x/input0";
+	touch->idev->id.bustype = BUS_I2C;
+	touch->idev->dev.parent = &pdev->dev;
+	touch->idev->open = pm860x_touch_open;
+	touch->idev->close = pm860x_touch_close;
+	touch->chip = chip;
+	touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+	touch->irq = irq + chip->irq_base;
+	touch->res_x = pdata->res_x;
+	input_set_drvdata(touch->idev, touch);
+
+	ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler,
+				   IRQF_ONESHOT, "touch", touch);
+	if (ret < 0)
+		goto out_irq;
+
+	__set_bit(EV_ABS, touch->idev->evbit);
+	__set_bit(ABS_X, touch->idev->absbit);
+	__set_bit(ABS_Y, touch->idev->absbit);
+	__set_bit(ABS_PRESSURE, touch->idev->absbit);
+	__set_bit(EV_SYN, touch->idev->evbit);
+	__set_bit(EV_KEY, touch->idev->evbit);
+	__set_bit(BTN_TOUCH, touch->idev->keybit);
+
+	input_set_abs_params(touch->idev, ABS_X, 0, 1 << ACCURATE_BIT, 0, 0);
+	input_set_abs_params(touch->idev, ABS_Y, 0, 1 << ACCURATE_BIT, 0, 0);
+	input_set_abs_params(touch->idev, ABS_PRESSURE, 0, 1 << ACCURATE_BIT,
+				0, 0);
+
+	ret = input_register_device(touch->idev);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to register touch!\n");
+		goto out_rg;
+	}
+
+	platform_set_drvdata(pdev, touch);
+	return 0;
+out_rg:
+	free_irq(touch->irq, touch);
+out_irq:
+	input_free_device(touch->idev);
+out:
+	kfree(touch);
+	return ret;
+}
+
+static int __devexit pm860x_touch_remove(struct platform_device *pdev)
+{
+	struct pm860x_touch *touch = platform_get_drvdata(pdev);
+
+	input_unregister_device(touch->idev);
+	free_irq(touch->irq, touch);
+	platform_set_drvdata(pdev, NULL);
+	kfree(touch);
+	return 0;
+}
+
+static struct platform_driver pm860x_touch_driver = {
+	.driver	= {
+		.name	= "88pm860x-touch",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= pm860x_touch_probe,
+	.remove	= __devexit_p(pm860x_touch_remove),
+};
+module_platform_driver(pm860x_touch_driver);
+
+MODULE_DESCRIPTION("Touchscreen driver for Marvell Semiconductor 88PM860x");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-touch");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/Kconfig b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/Kconfig
new file mode 100644
index 0000000..7f1c019
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/Kconfig
@@ -0,0 +1,868 @@
+#
+# Touchscreen driver configuration
+#
+menuconfig INPUT_TOUCHSCREEN
+	bool "Touchscreens"
+	help
+	  Say Y here, and a list of supported touchscreens will be displayed.
+	  This option doesn't affect the kernel.
+
+	  If unsure, say Y.
+
+if INPUT_TOUCHSCREEN
+
+config TOUCHSCREEN_88PM860X
+	tristate "Marvell 88PM860x touchscreen"
+	depends on MFD_88PM860X
+	help
+	  Say Y here if you have a 88PM860x PMIC and want to enable
+	  support for the built-in touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called 88pm860x-ts.
+
+config TOUCHSCREEN_ADS7846
+	tristate "ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens"
+	depends on SPI_MASTER
+	depends on HWMON = n || HWMON
+	help
+	  Say Y here if you have a touchscreen interface using the
+	  ADS7846/TSC2046/AD7873 or ADS7843/AD7843 controller,
+	  and your board-specific setup code includes that in its
+	  table of SPI devices.
+
+	  If HWMON is selected, and the driver is told the reference voltage
+	  on your board, you will also get hwmon interfaces for the voltage
+	  (and on ads7846/tsc2046/ad7873, temperature) sensors of this chip.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ads7846.
+
+config TOUCHSCREEN_AD7877
+	tristate "AD7877 based touchscreens"
+	depends on SPI_MASTER
+	help
+	  Say Y here if you have a touchscreen interface using the
+	  AD7877 controller, and your board-specific initialization
+	  code includes that in its table of SPI devices.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7877.
+
+config TOUCHSCREEN_AD7879
+	tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
+	help
+	  Say Y here if you want to support a touchscreen interface using
+	  the AD7879-1/AD7889-1 controller.
+
+	  You should select a bus connection too.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7879.
+
+config TOUCHSCREEN_AD7879_I2C
+	tristate "support I2C bus connection"
+	depends on TOUCHSCREEN_AD7879 && I2C
+	help
+	  Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7879-i2c.
+
+config TOUCHSCREEN_AD7879_SPI
+	tristate "support SPI bus connection"
+	depends on TOUCHSCREEN_AD7879 && SPI_MASTER
+	help
+	  Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7879-spi.
+
+config TOUCHSCREEN_ATMEL_MXT
+	tristate "Atmel mXT I2C Touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have Atmel mXT series I2C touchscreen,
+	  such as AT42QT602240/ATMXT224, connected to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atmel_mxt_ts.
+
+config TOUCHSCREEN_AUO_PIXCIR
+	tristate "AUO in-cell touchscreen using Pixcir ICs"
+	depends on I2C
+	depends on GPIOLIB
+	help
+	  Say Y here if you have a AUO display with in-cell touchscreen
+	  using Pixcir ICs.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called auo-pixcir-ts.
+
+config TOUCHSCREEN_BITSY
+	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
+	depends on SA1100_BITSY
+	select SERIO
+	help
+	  Say Y here if you have the h3600 (Bitsy) touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called h3600_ts_input.
+
+config TOUCHSCREEN_BU21013
+	tristate "BU21013 based touch panel controllers"
+	depends on I2C
+	help
+	  Say Y here if you have a bu21013 touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bu21013_ts.
+
+config TOUCHSCREEN_CY8CTMG110
+	tristate "cy8ctmg110 touchscreen"
+	depends on I2C
+	depends on GPIOLIB
+	help
+	  Say Y here if you have a cy8ctmg110 capacitive touchscreen on
+	  an AAVA device.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cy8ctmg110_ts.
+
+config TOUCHSCREEN_CYTTSP_CORE
+	tristate "Cypress TTSP touchscreen"
+	help
+	  Say Y here if you have a touchscreen using controller from
+	  the Cypress TrueTouch(tm) Standard Product family connected
+	  to your system. You will also need to select appropriate
+	  bus connection below.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_core.
+
+config TOUCHSCREEN_CYTTSP_I2C
+	tristate "support I2C bus connection"
+	depends on TOUCHSCREEN_CYTTSP_CORE && I2C
+	help
+	  Say Y here if the touchscreen is connected via I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_i2c.
+
+config TOUCHSCREEN_CYTTSP_SPI
+	tristate "support SPI bus connection"
+	depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER
+	help
+	  Say Y here if the touchscreen is connected via SPI bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_spi.
+
+config TOUCHSCREEN_DA9034
+	tristate "Touchscreen support for Dialog Semiconductor DA9034"
+	depends on PMIC_DA903X
+	default y
+	help
+	  Say Y here to enable the support for the touchscreen found
+	  on Dialog Semiconductor DA9034 PMIC.
+
+config TOUCHSCREEN_DYNAPRO
+	tristate "Dynapro serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have a Dynapro serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dynapro.
+
+config TOUCHSCREEN_HAMPSHIRE
+	tristate "Hampshire serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have a Hampshire serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hampshire.
+
+config TOUCHSCREEN_EETI
+	tristate "EETI touchscreen panel support"
+	depends on I2C
+	help
+	  Say Y here to enable support for I2C connected EETI touch panels.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called eeti_ts.
+
+config TOUCHSCREEN_EGALAX
+	tristate "EETI eGalax multi-touch panel support"
+	depends on I2C
+	help
+	  Say Y here to enable support for I2C connected EETI
+	  eGalax multi-touch panels.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called egalax_ts.
+
+config TOUCHSCREEN_FT6X06 
+	tristate "FT6x06 I2C toucscreen" 
+	depends on I2C 
+	help 
+		Say Y here to enable support for the I2C connected FT6x06 family 
+		of capacitive touchscreen drivers. 
+		
+config TOUCHSCREEN_CST716 
+	tristate "CST716 I2C toucscreen" 
+	depends on I2C 
+	help 
+		Say Y here to enable support for the I2C connected CST716 family 
+		of capacitive touchscreen drivers.
+		
+config TOUCHSCREEN_FUJITSU
+	tristate "Fujitsu serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have the Fujitsu touchscreen (such as one
+	  installed in Lifebook P series laptop) connected to your
+	  system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called fujitsu-ts.
+
+config TOUCHSCREEN_ILI210X
+	tristate "Ilitek ILI210X based touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have a ILI210X based touchscreen
+	  controller. This driver supports models ILI2102,
+	  ILI2102s, ILI2103, ILI2103s and ILI2105.
+	  Such kind of chipsets can be found in Amazon Kindle Fire
+	  touchscreens.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ili210x.
+
+config TOUCHSCREEN_S3C2410
+	tristate "Samsung S3C2410/generic touchscreen input driver"
+	depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
+	select S3C_ADC
+	help
+	  Say Y here if you have the s3c2410 touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called s3c2410_ts.
+
+config TOUCHSCREEN_GUNZE
+	tristate "Gunze AHL-51S touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have the Gunze AHL-51 touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gunze.
+
+config TOUCHSCREEN_ELO
+	tristate "Elo serial touchscreens"
+	select SERIO
+	help
+	  Say Y here if you have an Elo serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called elo.
+
+config TOUCHSCREEN_WACOM_W8001
+	tristate "Wacom W8001 penabled serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have an Wacom W8001 penabled serial touchscreen
+	  connected to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wacom_w8001.
+
+config TOUCHSCREEN_LPC32XX
+	tristate "LPC32XX touchscreen controller"
+	depends on ARCH_LPC32XX
+	help
+	  Say Y here if you have a LPC32XX device and want
+	  to support the built-in touchscreen.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called lpc32xx_ts.
+
+config TOUCHSCREEN_MAX11801
+	tristate "MAX11801 based touchscreens"
+	depends on I2C
+	help
+	  Say Y here if you have a MAX11801 based touchscreen
+	  controller.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called max11801_ts.
+
+config TOUCHSCREEN_MCS5000
+	tristate "MELFAS MCS-5000 touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have the MELFAS MCS-5000 touchscreen controller
+	  chip in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mcs5000_ts.
+
+config TOUCHSCREEN_MTOUCH
+	tristate "MicroTouch serial touchscreens"
+	select SERIO
+	help
+	  Say Y here if you have a MicroTouch (3M) serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mtouch.
+
+config TOUCHSCREEN_INEXIO
+	tristate "iNexio serial touchscreens"
+	select SERIO
+	help
+	  Say Y here if you have an iNexio serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called inexio.
+
+config TOUCHSCREEN_INTEL_MID
+	tristate "Intel MID platform resistive touchscreen"
+	depends on INTEL_SCU_IPC
+	help
+	  Say Y here if you have a Intel MID based touchscreen in
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called intel_mid_touch.
+
+config TOUCHSCREEN_MK712
+	tristate "ICS MicroClock MK712 touchscreen"
+	help
+	  Say Y here if you have the ICS MicroClock MK712 touchscreen
+	  controller chip in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mk712.
+
+config TOUCHSCREEN_HP600
+	tristate "HP Jornada 6xx touchscreen"
+	depends on SH_HP6XX && SH_ADC
+	help
+	  Say Y here if you have a HP Jornada 620/660/680/690 and want to
+          support the built-in touchscreen.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hp680_ts_input.
+
+config TOUCHSCREEN_HP7XX
+	tristate "HP Jornada 7xx touchscreen"
+	depends on SA1100_JORNADA720_SSP
+	help
+	  Say Y here if you have a HP Jornada 710/720/728 and want
+	  to support the built-in touchscreen.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called jornada720_ts.
+
+config TOUCHSCREEN_HTCPEN
+	tristate "HTC Shift X9500 touchscreen"
+	depends on ISA
+	help
+	  Say Y here if you have an HTC Shift UMPC also known as HTC X9500
+	  Clio / Shangrila and want to support the built-in touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called htcpen.
+
+config TOUCHSCREEN_PENMOUNT
+	tristate "Penmount serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have a Penmount serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called penmount.
+
+config TOUCHSCREEN_MIGOR
+	tristate "Renesas MIGO-R touchscreen"
+	depends on SH_MIGOR && I2C
+	help
+	  Say Y here to enable MIGO-R touchscreen support.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called migor_ts.
+
+config TOUCHSCREEN_TNETV107X
+	tristate "TI TNETV107X touchscreen support"
+	depends on ARCH_DAVINCI_TNETV107X
+	help
+	  Say Y here if you want to use the TNETV107X touchscreen.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tnetv107x-ts.
+
+config TOUCHSCREEN_SYNAPTICS_I2C_RMI
+	tristate "Synaptics i2c touchscreen"
+	depends on I2C
+	help
+	  This enables support for Synaptics RMI over I2C based touchscreens.
+
+config TOUCHSCREEN_TOUCHRIGHT
+	tristate "Touchright serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have a Touchright serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called touchright.
+
+config TOUCHSCREEN_TOUCHWIN
+	tristate "Touchwin serial touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have a Touchwin serial touchscreen connected to
+	  your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called touchwin.
+
+config TOUCHSCREEN_TI_TSCADC
+	tristate "TI Touchscreen Interface"
+	depends on ARCH_OMAP2PLUS
+	help
+	  Say Y here if you have 4/5/8 wire touchscreen controller
+	  to be connected to the ADC controller on your TI AM335x SoC.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ti_tscadc.
+
+config TOUCHSCREEN_ATMEL_TSADCC
+	tristate "Atmel Touchscreen Interface"
+	depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+	help
+	  Say Y here if you have a 4-wire touchscreen connected to the
+          ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atmel_tsadcc.
+
+config TOUCHSCREEN_UCB1400
+	tristate "Philips UCB1400 touchscreen"
+	depends on AC97_BUS
+	depends on UCB1400_CORE
+	help
+	  This enables support for the Philips UCB1400 touchscreen interface.
+	  The UCB1400 is an AC97 audio codec.  The touchscreen interface
+	  will be initialized only after the ALSA subsystem has been
+	  brought up and the UCB1400 detected.  You therefore have to
+	  configure ALSA support as well (either built-in or modular,
+	  independently of whether this driver is itself built-in or
+	  modular) for this driver to work.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ucb1400_ts.
+
+config TOUCHSCREEN_PIXCIR
+	tristate "PIXCIR I2C touchscreens"
+	depends on I2C
+	help
+	  Say Y here if you have a pixcir i2c touchscreen
+	  controller.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pixcir_i2c_ts.
+
+config TOUCHSCREEN_WM831X
+	tristate "Support for WM831x touchscreen controllers"
+	depends on MFD_WM831X
+	help
+	  This enables support for the touchscreen controller on the WM831x
+	  series of PMICs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wm831x-ts.
+
+config TOUCHSCREEN_WM97XX
+	tristate "Support for WM97xx AC97 touchscreen controllers"
+	depends on AC97_BUS
+	help
+	  Say Y here if you have a Wolfson Microelectronics WM97xx
+	  touchscreen connected to your system. Note that this option
+	  only enables core driver, you will also need to select
+	  support for appropriate chip below.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wm97xx-ts.
+
+config TOUCHSCREEN_WM9705
+	bool "WM9705 Touchscreen interface support"
+	depends on TOUCHSCREEN_WM97XX
+	default y
+	help
+	  Say Y here to enable support for the Wolfson Microelectronics
+	  WM9705 touchscreen controller.
+
+config TOUCHSCREEN_WM9712
+	bool "WM9712 Touchscreen interface support"
+	depends on TOUCHSCREEN_WM97XX
+	default y
+	help
+	  Say Y here to enable support for the Wolfson Microelectronics
+	  WM9712 touchscreen controller.
+
+config TOUCHSCREEN_WM9713
+	bool "WM9713 Touchscreen interface support"
+	depends on TOUCHSCREEN_WM97XX
+	default y
+	help
+	  Say Y here to enable support for the Wolfson Microelectronics
+	  WM9713 touchscreen controller.
+
+config TOUCHSCREEN_WM97XX_ATMEL
+	tristate "WM97xx Atmel accelerated touch"
+	depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91)
+	help
+	  Say Y here for support for streaming mode with WM97xx touchscreens
+	  on Atmel AT91 or AVR32 systems with an AC97C module.
+
+	  Be aware that this will use channel B in the controller for
+	  streaming data, this must not conflict with other AC97C drivers.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called atmel-wm97xx.
+
+config TOUCHSCREEN_WM97XX_MAINSTONE
+	tristate "WM97xx Mainstone/Palm accelerated touch"
+	depends on TOUCHSCREEN_WM97XX && ARCH_PXA
+	help
+	  Say Y here for support for streaming mode with WM97xx touchscreens
+	  on Mainstone, Palm Tungsten T5, TX and LifeDrive systems.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mainstone-wm97xx.
+
+config TOUCHSCREEN_WM97XX_ZYLONITE
+	tristate "Zylonite accelerated touch"
+	depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE
+	select TOUCHSCREEN_WM9713
+	help
+	  Say Y here for support for streaming mode with the touchscreen
+	  on Zylonite systems.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zylonite-wm97xx.
+
+config TOUCHSCREEN_USB_COMPOSITE
+	tristate "USB Touchscreen Driver"
+	depends on USB_ARCH_HAS_HCD
+	select USB
+	help
+	  USB Touchscreen driver for:
+	  - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
+	  - PanJit TouchSet USB
+	  - 3M MicroTouch USB (EX II series)
+	  - ITM
+	  - some other eTurboTouch
+	  - Gunze AHL61
+	  - DMC TSC-10/25
+	  - IRTOUCHSYSTEMS/UNITOP
+	  - IdealTEK URTC1000
+	  - GoTop Super_Q2/GogoPen/PenPower tablets
+	  - JASTEC USB Touch Controller/DigiTech DTR-02U
+	  - Zytronic controllers
+	  - Elo TouchSystems 2700 IntelliTouch
+	  - EasyTouch USB Touch Controller from Data Modul
+
+	  Have a look at <http://linux.chapter7.ch/touchkit/> for
+	  a usage description and the required user-space stuff.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called usbtouchscreen.
+
+config TOUCHSCREEN_MC13783
+	tristate "Freescale MC13783 touchscreen input driver"
+	depends on MFD_MC13783
+	help
+	  Say Y here if you have an Freescale MC13783 PMIC on your
+	  board and want to use its touchscreen
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mc13783_ts.
+
+config TOUCHSCREEN_USB_EGALAX
+	default y
+	bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_PANJIT
+	default y
+	bool "PanJit device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_3M
+	default y
+	bool "3M/Microtouch EX II series device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ITM
+	default y
+	bool "ITM device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ETURBO
+	default y
+	bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GUNZE
+	default y
+	bool "Gunze AHL61 device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_DMC_TSC10
+	default y
+	bool "DMC TSC-10/25 device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_IRTOUCH
+	default y
+	bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_IDEALTEK
+	default y
+	bool "IdealTEK URTC1000 device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GENERAL_TOUCH
+	default y
+	bool "GeneralTouch Touchscreen device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GOTOP
+	default y
+	bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_JASTEC
+	default y
+	bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ELO
+	default y
+	bool "Elo TouchSystems 2700 IntelliTouch controller device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_E2I
+	default y
+	bool "e2i Touchscreen controller (e.g. from Mimo 740)"
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ZYTRONIC
+	default y
+	bool "Zytronic controller" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ETT_TC45USB
+	default y
+	bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_NEXIO
+	default y
+	bool "NEXIO/iNexio device support" if EXPERT
+	depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_EASYTOUCH
+	default y
+	bool "EasyTouch USB Touch controller device support" if EMBEDDED
+	depends on TOUCHSCREEN_USB_COMPOSITE
+	help
+	  Say Y here if you have a EasyTouch USB Touch controller device support.
+	  If unsure, say N.
+
+config TOUCHSCREEN_TOUCHIT213
+	tristate "Sahara TouchIT-213 touchscreen"
+	select SERIO
+	help
+	  Say Y here if you have a Sahara TouchIT-213 Tablet PC.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called touchit213.
+
+config TOUCHSCREEN_TSC_SERIO
+	tristate "TSC-10/25/40 serial touchscreen support"
+	select SERIO
+	help
+	  Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected
+	  to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tsc40.
+
+config TOUCHSCREEN_TSC2005
+        tristate "TSC2005 based touchscreens"
+        depends on SPI_MASTER && GENERIC_HARDIRQS
+        help
+          Say Y here if you have a TSC2005 based touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tsc2005.
+
+config TOUCHSCREEN_TSC2007
+	tristate "TSC2007 based touchscreens"
+	depends on I2C
+	help
+	  Say Y here if you have a TSC2007 based touchscreen.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tsc2007.
+
+config TOUCHSCREEN_W90X900
+	tristate "W90P910 touchscreen driver"
+	depends on HAVE_CLK
+	help
+	  Say Y here if you have a W90P910 based touchscreen.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called w90p910_ts.
+
+config TOUCHSCREEN_PCAP
+	tristate "Motorola PCAP touchscreen"
+	depends on EZX_PCAP
+	help
+	  Say Y here if you have a Motorola EZX telephone and
+	  want to enable support for the built-in touchscreen.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pcap_ts.
+
+config TOUCHSCREEN_ST1232
+	tristate "Sitronix ST1232 touchscreen controllers"
+	depends on I2C
+	help
+	  Say Y here if you want to support Sitronix ST1232
+	  touchscreen controller.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called st1232_ts.
+
+config TOUCHSCREEN_STMPE
+	tristate "STMicroelectronics STMPE touchscreens"
+	depends on MFD_STMPE
+	help
+	  Say Y here if you want support for STMicroelectronics
+	  STMPE touchscreen controllers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called stmpe-ts.
+
+config TOUCHSCREEN_TPS6507X
+	tristate "TPS6507x based touchscreens"
+	depends on I2C
+	help
+	  Say Y here if you have a TPS6507x based touchscreen
+	  controller.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tps6507x_ts.
+
+endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/Makefile b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/Makefile
new file mode 100644
index 0000000..31db000
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/Makefile
@@ -0,0 +1,75 @@
+#
+# Makefile for the touchscreen drivers.
+#
+
+# Each configuration option enables a list of files.
+
+wm97xx-ts-y := wm97xx-core.o
+
+obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879)	+= ad7879.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C)	+= ad7879-i2c.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)	+= ad7879-spi.o
+obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)	+= atmel_mxt_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
+obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)	+= auo-pixcir-ts.o
+obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_BU21013)	+= bu21013_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)	+= cyttsp_spi.o
+obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
+obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
+obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
+obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
+obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
+obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
+obj-$(CONFIG_INPUT_TOUCHSCREEN)		+= touchscreen.o
+obj-$(CONFIG_TOUCHSCREEN_FT6X06)	+= ft6x06_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CST716)	+= cst716_ts.o
+obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
+obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
+obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)	+= intel-mid-touch.o
+obj-$(CONFIG_TOUCHSCREEN_LPC32XX)	+= lpc32xx_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MAX11801)	+= max11801_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MC13783)	+= mc13783_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MCS5000)	+= mcs5000_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MIGOR)		+= migor_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MTOUCH)	+= mtouch.o
+obj-$(CONFIG_TOUCHSCREEN_MK712)		+= mk712.o
+obj-$(CONFIG_TOUCHSCREEN_HP600)		+= hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_HP7XX)		+= jornada720_ts.o
+obj-$(CONFIG_TOUCHSCREEN_HTCPEN)	+= htcpen.o
+obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)	+= usbtouchscreen.o
+obj-$(CONFIG_TOUCHSCREEN_PCAP)		+= pcap_ts.o
+obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= penmount.o
+obj-$(CONFIG_TOUCHSCREEN_PIXCIR)	+= pixcir_i2c_ts.o
+obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o
+obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC)	+= ti_tscadc.o
+obj-$(CONFIG_TOUCHSCREEN_TNETV107X)	+= tnetv107x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI)	+= synaptics_i2c_rmi.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o
+obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO)	+= tsc40.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2005)	+= tsc2005.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2007)	+= tsc2007.o
+obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)	+= wacom_w8001.o
+obj-$(CONFIG_TOUCHSCREEN_WM831X)	+= wm831x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX)	+= wm97xx-ts.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)	+= wm9705.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)	+= wm9712.o
+wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)	+= wm9713.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL)	+= atmel-wm97xx.o
+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
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7877.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7877.c
new file mode 100644
index 0000000..2c76921
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7877.c
@@ -0,0 +1,868 @@
+/*
+ * Copyright (C) 2006-2008 Michael Hennerich, Analog Devices Inc.
+ *
+ * Description:	AD7877 based touchscreen, sensor (ADCs), DAC and GPIO driver
+ * Based on:	ads7846.c
+ *
+ * Bugs:        Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * History:
+ * Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006 Nokia Corporation
+ * Various changes: Imre Deak <imre.deak@nokia.com>
+ *
+ * Using code from:
+ *  - corgi_ts.c
+ *	Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *	Copyright (C) 2002 MontaVista Software
+ *	Copyright (C) 2004 Texas Instruments
+ *	Copyright (C) 2005 Dirk Behme
+ */
+
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ad7877.h>
+#include <linux/module.h>
+#include <asm/irq.h>
+
+#define	TS_PEN_UP_TIMEOUT	msecs_to_jiffies(100)
+
+#define MAX_SPI_FREQ_HZ			20000000
+#define	MAX_12BIT			((1<<12)-1)
+
+#define AD7877_REG_ZEROS			0
+#define AD7877_REG_CTRL1			1
+#define AD7877_REG_CTRL2			2
+#define AD7877_REG_ALERT			3
+#define AD7877_REG_AUX1HIGH			4
+#define AD7877_REG_AUX1LOW			5
+#define AD7877_REG_BAT1HIGH			6
+#define AD7877_REG_BAT1LOW			7
+#define AD7877_REG_BAT2HIGH			8
+#define AD7877_REG_BAT2LOW			9
+#define AD7877_REG_TEMP1HIGH			10
+#define AD7877_REG_TEMP1LOW			11
+#define AD7877_REG_SEQ0				12
+#define AD7877_REG_SEQ1				13
+#define AD7877_REG_DAC				14
+#define AD7877_REG_NONE1			15
+#define AD7877_REG_EXTWRITE			15
+#define AD7877_REG_XPLUS			16
+#define AD7877_REG_YPLUS			17
+#define AD7877_REG_Z2				18
+#define AD7877_REG_aux1				19
+#define AD7877_REG_aux2				20
+#define AD7877_REG_aux3				21
+#define AD7877_REG_bat1				22
+#define AD7877_REG_bat2				23
+#define AD7877_REG_temp1			24
+#define AD7877_REG_temp2			25
+#define AD7877_REG_Z1				26
+#define AD7877_REG_GPIOCTRL1			27
+#define AD7877_REG_GPIOCTRL2			28
+#define AD7877_REG_GPIODATA			29
+#define AD7877_REG_NONE2			30
+#define AD7877_REG_NONE3			31
+
+#define AD7877_SEQ_YPLUS_BIT			(1<<11)
+#define AD7877_SEQ_XPLUS_BIT			(1<<10)
+#define AD7877_SEQ_Z2_BIT			(1<<9)
+#define AD7877_SEQ_AUX1_BIT			(1<<8)
+#define AD7877_SEQ_AUX2_BIT			(1<<7)
+#define AD7877_SEQ_AUX3_BIT			(1<<6)
+#define AD7877_SEQ_BAT1_BIT			(1<<5)
+#define AD7877_SEQ_BAT2_BIT			(1<<4)
+#define AD7877_SEQ_TEMP1_BIT			(1<<3)
+#define AD7877_SEQ_TEMP2_BIT			(1<<2)
+#define AD7877_SEQ_Z1_BIT			(1<<1)
+
+enum {
+	AD7877_SEQ_YPOS  = 0,
+	AD7877_SEQ_XPOS  = 1,
+	AD7877_SEQ_Z2    = 2,
+	AD7877_SEQ_AUX1  = 3,
+	AD7877_SEQ_AUX2  = 4,
+	AD7877_SEQ_AUX3  = 5,
+	AD7877_SEQ_BAT1  = 6,
+	AD7877_SEQ_BAT2  = 7,
+	AD7877_SEQ_TEMP1 = 8,
+	AD7877_SEQ_TEMP2 = 9,
+	AD7877_SEQ_Z1    = 10,
+	AD7877_NR_SENSE  = 11,
+};
+
+/* DAC Register Default RANGE 0 to Vcc, Volatge Mode, DAC On */
+#define AD7877_DAC_CONF			0x1
+
+/* If gpio3 is set AUX3/GPIO3 acts as GPIO Output */
+#define AD7877_EXTW_GPIO_3_CONF		0x1C4
+#define AD7877_EXTW_GPIO_DATA		0x200
+
+/* Control REG 2 */
+#define AD7877_TMR(x)			((x & 0x3) << 0)
+#define AD7877_REF(x)			((x & 0x1) << 2)
+#define AD7877_POL(x)			((x & 0x1) << 3)
+#define AD7877_FCD(x)			((x & 0x3) << 4)
+#define AD7877_PM(x)			((x & 0x3) << 6)
+#define AD7877_ACQ(x)			((x & 0x3) << 8)
+#define AD7877_AVG(x)			((x & 0x3) << 10)
+
+/* Control REG 1 */
+#define	AD7877_SER			(1 << 11)	/* non-differential */
+#define	AD7877_DFR			(0 << 11)	/* differential */
+
+#define AD7877_MODE_NOC  (0)	/* Do not convert */
+#define AD7877_MODE_SCC  (1)	/* Single channel conversion */
+#define AD7877_MODE_SEQ0 (2)	/* Sequence 0 in Slave Mode */
+#define AD7877_MODE_SEQ1 (3)	/* Sequence 1 in Master Mode */
+
+#define AD7877_CHANADD(x)		((x&0xF)<<7)
+#define AD7877_READADD(x)		((x)<<2)
+#define AD7877_WRITEADD(x)		((x)<<12)
+
+#define AD7877_READ_CHAN(x) (AD7877_WRITEADD(AD7877_REG_CTRL1) | AD7877_SER | \
+		AD7877_MODE_SCC | AD7877_CHANADD(AD7877_REG_ ## x) | \
+		AD7877_READADD(AD7877_REG_ ## x))
+
+#define AD7877_MM_SEQUENCE (AD7877_SEQ_YPLUS_BIT | AD7877_SEQ_XPLUS_BIT | \
+		AD7877_SEQ_Z2_BIT | AD7877_SEQ_Z1_BIT)
+
+/*
+ * Non-touchscreen sensors only use single-ended conversions.
+ */
+
+struct ser_req {
+	u16			reset;
+	u16			ref_on;
+	u16			command;
+	struct spi_message	msg;
+	struct spi_transfer	xfer[6];
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	u16 sample ____cacheline_aligned;
+};
+
+struct ad7877 {
+	struct input_dev	*input;
+	char			phys[32];
+
+	struct spi_device	*spi;
+	u16			model;
+	u16			vref_delay_usecs;
+	u16			x_plate_ohms;
+	u16			pressure_max;
+
+	u16			cmd_crtl1;
+	u16			cmd_crtl2;
+	u16			cmd_dummy;
+	u16			dac;
+
+	u8			stopacq_polarity;
+	u8			first_conversion_delay;
+	u8			acquisition_time;
+	u8			averaging;
+	u8			pen_down_acc_interval;
+
+	struct spi_transfer	xfer[AD7877_NR_SENSE + 2];
+	struct spi_message	msg;
+
+	struct mutex		mutex;
+	bool			disabled;	/* P: mutex */
+	bool			gpio3;		/* P: mutex */
+	bool			gpio4;		/* P: mutex */
+
+	spinlock_t		lock;
+	struct timer_list	timer;		/* P: lock */
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned;
+};
+
+static bool gpio3;
+module_param(gpio3, bool, 0);
+MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
+
+/*
+ * ad7877_read/write are only used for initial setup and for sysfs controls.
+ * The main traffic is done using spi_async() in the interrupt handler.
+ */
+
+static int ad7877_read(struct spi_device *spi, u16 reg)
+{
+	struct ser_req *req;
+	int status, ret;
+
+	req = kzalloc(sizeof *req, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	req->command = (u16) (AD7877_WRITEADD(AD7877_REG_CTRL1) |
+			AD7877_READADD(reg));
+	req->xfer[0].tx_buf = &req->command;
+	req->xfer[0].len = 2;
+	req->xfer[0].cs_change = 1;
+
+	req->xfer[1].rx_buf = &req->sample;
+	req->xfer[1].len = 2;
+
+	spi_message_add_tail(&req->xfer[0], &req->msg);
+	spi_message_add_tail(&req->xfer[1], &req->msg);
+
+	status = spi_sync(spi, &req->msg);
+	ret = status ? : req->sample;
+
+	kfree(req);
+
+	return ret;
+}
+
+static int ad7877_write(struct spi_device *spi, u16 reg, u16 val)
+{
+	struct ser_req *req;
+	int status;
+
+	req = kzalloc(sizeof *req, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	req->command = (u16) (AD7877_WRITEADD(reg) | (val & MAX_12BIT));
+	req->xfer[0].tx_buf = &req->command;
+	req->xfer[0].len = 2;
+
+	spi_message_add_tail(&req->xfer[0], &req->msg);
+
+	status = spi_sync(spi, &req->msg);
+
+	kfree(req);
+
+	return status;
+}
+
+static int ad7877_read_adc(struct spi_device *spi, unsigned command)
+{
+	struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+	struct ser_req *req;
+	int status;
+	int sample;
+	int i;
+
+	req = kzalloc(sizeof *req, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	/* activate reference, so it has time to settle; */
+	req->ref_on = AD7877_WRITEADD(AD7877_REG_CTRL2) |
+			 AD7877_POL(ts->stopacq_polarity) |
+			 AD7877_AVG(0) | AD7877_PM(2) | AD7877_TMR(0) |
+			 AD7877_ACQ(ts->acquisition_time) | AD7877_FCD(0);
+
+	req->reset = AD7877_WRITEADD(AD7877_REG_CTRL1) | AD7877_MODE_NOC;
+
+	req->command = (u16) command;
+
+	req->xfer[0].tx_buf = &req->reset;
+	req->xfer[0].len = 2;
+	req->xfer[0].cs_change = 1;
+
+	req->xfer[1].tx_buf = &req->ref_on;
+	req->xfer[1].len = 2;
+	req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+	req->xfer[1].cs_change = 1;
+
+	req->xfer[2].tx_buf = &req->command;
+	req->xfer[2].len = 2;
+	req->xfer[2].delay_usecs = ts->vref_delay_usecs;
+	req->xfer[2].cs_change = 1;
+
+	req->xfer[3].rx_buf = &req->sample;
+	req->xfer[3].len = 2;
+	req->xfer[3].cs_change = 1;
+
+	req->xfer[4].tx_buf = &ts->cmd_crtl2;	/*REF OFF*/
+	req->xfer[4].len = 2;
+	req->xfer[4].cs_change = 1;
+
+	req->xfer[5].tx_buf = &ts->cmd_crtl1;	/*DEFAULT*/
+	req->xfer[5].len = 2;
+
+	/* group all the transfers together, so we can't interfere with
+	 * reading touchscreen state; disable penirq while sampling
+	 */
+	for (i = 0; i < 6; i++)
+		spi_message_add_tail(&req->xfer[i], &req->msg);
+
+	status = spi_sync(spi, &req->msg);
+	sample = req->sample;
+
+	kfree(req);
+
+	return status ? : sample;
+}
+
+static int ad7877_process_data(struct ad7877 *ts)
+{
+	struct input_dev *input_dev = ts->input;
+	unsigned Rt;
+	u16 x, y, z1, z2;
+
+	x = ts->conversion_data[AD7877_SEQ_XPOS] & MAX_12BIT;
+	y = ts->conversion_data[AD7877_SEQ_YPOS] & MAX_12BIT;
+	z1 = ts->conversion_data[AD7877_SEQ_Z1] & MAX_12BIT;
+	z2 = ts->conversion_data[AD7877_SEQ_Z2] & MAX_12BIT;
+
+	/*
+	 * The samples processed here are already preprocessed by the AD7877.
+	 * The preprocessing function consists of an averaging filter.
+	 * The combination of 'first conversion delay' and averaging provides a robust solution,
+	 * discarding the spurious noise in the signal and keeping only the data of interest.
+	 * The size of the averaging filter is programmable. (dev.platform_data, see linux/spi/ad7877.h)
+	 * Other user-programmable conversion controls include variable acquisition time,
+	 * and first conversion delay. Up to 16 averages can be taken per conversion.
+	 */
+
+	if (likely(x && z1)) {
+		/* compute touch pressure resistance using equation #1 */
+		Rt = (z2 - z1) * x * ts->x_plate_ohms;
+		Rt /= z1;
+		Rt = (Rt + 2047) >> 12;
+
+		/*
+		 * Sample found inconsistent, pressure is beyond
+		 * the maximum. Don't report it to user space.
+		 */
+		if (Rt > ts->pressure_max)
+			return -EINVAL;
+
+		if (!timer_pending(&ts->timer))
+			input_report_key(input_dev, BTN_TOUCH, 1);
+
+		input_report_abs(input_dev, ABS_X, x);
+		input_report_abs(input_dev, ABS_Y, y);
+		input_report_abs(input_dev, ABS_PRESSURE, Rt);
+		input_sync(input_dev);
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static inline void ad7877_ts_event_release(struct ad7877 *ts)
+{
+	struct input_dev *input_dev = ts->input;
+
+	input_report_abs(input_dev, ABS_PRESSURE, 0);
+	input_report_key(input_dev, BTN_TOUCH, 0);
+	input_sync(input_dev);
+}
+
+static void ad7877_timer(unsigned long handle)
+{
+	struct ad7877 *ts = (void *)handle;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ts->lock, flags);
+	ad7877_ts_event_release(ts);
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static irqreturn_t ad7877_irq(int irq, void *handle)
+{
+	struct ad7877 *ts = handle;
+	unsigned long flags;
+	int error;
+
+	error = spi_sync(ts->spi, &ts->msg);
+	if (error) {
+		dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
+		goto out;
+	}
+
+	spin_lock_irqsave(&ts->lock, flags);
+	error = ad7877_process_data(ts);
+	if (!error)
+		mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+	spin_unlock_irqrestore(&ts->lock, flags);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static void ad7877_disable(struct ad7877 *ts)
+{
+	mutex_lock(&ts->mutex);
+
+	if (!ts->disabled) {
+		ts->disabled = true;
+		disable_irq(ts->spi->irq);
+
+		if (del_timer_sync(&ts->timer))
+			ad7877_ts_event_release(ts);
+	}
+
+	/*
+	 * We know the chip's in lowpower mode since we always
+	 * leave it that way after every request
+	 */
+
+	mutex_unlock(&ts->mutex);
+}
+
+static void ad7877_enable(struct ad7877 *ts)
+{
+	mutex_lock(&ts->mutex);
+
+	if (ts->disabled) {
+		ts->disabled = false;
+		enable_irq(ts->spi->irq);
+	}
+
+	mutex_unlock(&ts->mutex);
+}
+
+#define SHOW(name) static ssize_t \
+name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+	struct ad7877 *ts = dev_get_drvdata(dev); \
+	ssize_t v = ad7877_read_adc(ts->spi, \
+			AD7877_READ_CHAN(name)); \
+	if (v < 0) \
+		return v; \
+	return sprintf(buf, "%u\n", (unsigned) v); \
+} \
+static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
+
+SHOW(aux1)
+SHOW(aux2)
+SHOW(aux3)
+SHOW(bat1)
+SHOW(bat2)
+SHOW(temp1)
+SHOW(temp2)
+
+static ssize_t ad7877_disable_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t ad7877_disable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	error = kstrtouint(buf, 10, &val);
+	if (error)
+		return error;
+
+	if (val)
+		ad7877_disable(ts);
+	else
+		ad7877_enable(ts);
+
+	return count;
+}
+
+static DEVICE_ATTR(disable, 0664, ad7877_disable_show, ad7877_disable_store);
+
+static ssize_t ad7877_dac_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->dac);
+}
+
+static ssize_t ad7877_dac_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	error = kstrtouint(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ts->mutex);
+	ts->dac = val & 0xFF;
+	ad7877_write(ts->spi, AD7877_REG_DAC, (ts->dac << 4) | AD7877_DAC_CONF);
+	mutex_unlock(&ts->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(dac, 0664, ad7877_dac_show, ad7877_dac_store);
+
+static ssize_t ad7877_gpio3_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->gpio3);
+}
+
+static ssize_t ad7877_gpio3_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	error = kstrtouint(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ts->mutex);
+	ts->gpio3 = !!val;
+	ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA |
+		 (ts->gpio4 << 4) | (ts->gpio3 << 5));
+	mutex_unlock(&ts->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(gpio3, 0664, ad7877_gpio3_show, ad7877_gpio3_store);
+
+static ssize_t ad7877_gpio4_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->gpio4);
+}
+
+static ssize_t ad7877_gpio4_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	error = kstrtouint(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ts->mutex);
+	ts->gpio4 = !!val;
+	ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA |
+		     (ts->gpio4 << 4) | (ts->gpio3 << 5));
+	mutex_unlock(&ts->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(gpio4, 0664, ad7877_gpio4_show, ad7877_gpio4_store);
+
+static struct attribute *ad7877_attributes[] = {
+	&dev_attr_temp1.attr,
+	&dev_attr_temp2.attr,
+	&dev_attr_aux1.attr,
+	&dev_attr_aux2.attr,
+	&dev_attr_aux3.attr,
+	&dev_attr_bat1.attr,
+	&dev_attr_bat2.attr,
+	&dev_attr_disable.attr,
+	&dev_attr_dac.attr,
+	&dev_attr_gpio3.attr,
+	&dev_attr_gpio4.attr,
+	NULL
+};
+
+static umode_t ad7877_attr_is_visible(struct kobject *kobj,
+				     struct attribute *attr, int n)
+{
+	umode_t mode = attr->mode;
+
+	if (attr == &dev_attr_aux3.attr) {
+		if (gpio3)
+			mode = 0;
+	} else if (attr == &dev_attr_gpio3.attr) {
+		if (!gpio3)
+			mode = 0;
+	}
+
+	return mode;
+}
+
+static const struct attribute_group ad7877_attr_group = {
+	.is_visible	= ad7877_attr_is_visible,
+	.attrs		= ad7877_attributes,
+};
+
+static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
+{
+	struct spi_message *m;
+	int i;
+
+	ts->cmd_crtl2 = AD7877_WRITEADD(AD7877_REG_CTRL2) |
+			AD7877_POL(ts->stopacq_polarity) |
+			AD7877_AVG(ts->averaging) | AD7877_PM(1) |
+			AD7877_TMR(ts->pen_down_acc_interval) |
+			AD7877_ACQ(ts->acquisition_time) |
+			AD7877_FCD(ts->first_conversion_delay);
+
+	ad7877_write(spi, AD7877_REG_CTRL2, ts->cmd_crtl2);
+
+	ts->cmd_crtl1 = AD7877_WRITEADD(AD7877_REG_CTRL1) |
+			AD7877_READADD(AD7877_REG_XPLUS-1) |
+			AD7877_MODE_SEQ1 | AD7877_DFR;
+
+	ad7877_write(spi, AD7877_REG_CTRL1, ts->cmd_crtl1);
+
+	ts->cmd_dummy = 0;
+
+	m = &ts->msg;
+
+	spi_message_init(m);
+
+	m->context = ts;
+
+	ts->xfer[0].tx_buf = &ts->cmd_crtl1;
+	ts->xfer[0].len = 2;
+	ts->xfer[0].cs_change = 1;
+
+	spi_message_add_tail(&ts->xfer[0], m);
+
+	ts->xfer[1].tx_buf = &ts->cmd_dummy; /* Send ZERO */
+	ts->xfer[1].len = 2;
+	ts->xfer[1].cs_change = 1;
+
+	spi_message_add_tail(&ts->xfer[1], m);
+
+	for (i = 0; i < AD7877_NR_SENSE; i++) {
+		ts->xfer[i + 2].rx_buf = &ts->conversion_data[AD7877_SEQ_YPOS + i];
+		ts->xfer[i + 2].len = 2;
+		if (i < (AD7877_NR_SENSE - 1))
+			ts->xfer[i + 2].cs_change = 1;
+		spi_message_add_tail(&ts->xfer[i + 2], m);
+	}
+}
+
+static int __devinit ad7877_probe(struct spi_device *spi)
+{
+	struct ad7877			*ts;
+	struct input_dev		*input_dev;
+	struct ad7877_platform_data	*pdata = spi->dev.platform_data;
+	int				err;
+	u16				verify;
+
+	if (!spi->irq) {
+		dev_dbg(&spi->dev, "no IRQ?\n");
+		return -ENODEV;
+	}
+
+	if (!pdata) {
+		dev_dbg(&spi->dev, "no platform data?\n");
+		return -ENODEV;
+	}
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_dbg(&spi->dev, "SPI CLK %d Hz?\n",spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	spi->bits_per_word = 16;
+	err = spi_setup(spi);
+	if (err) {
+		dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
+		return err;
+	}
+
+	ts = kzalloc(sizeof(struct ad7877), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	dev_set_drvdata(&spi->dev, ts);
+	ts->spi = spi;
+	ts->input = input_dev;
+
+	setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts);
+	mutex_init(&ts->mutex);
+	spin_lock_init(&ts->lock);
+
+	ts->model = pdata->model ? : 7877;
+	ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
+	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+	ts->pressure_max = pdata->pressure_max ? : ~0;
+
+	ts->stopacq_polarity = pdata->stopacq_polarity;
+	ts->first_conversion_delay = pdata->first_conversion_delay;
+	ts->acquisition_time = pdata->acquisition_time;
+	ts->averaging = pdata->averaging;
+	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
+
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
+
+	input_dev->name = "AD7877 Touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->dev.parent = &spi->dev;
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(ABS_X, input_dev->absbit);
+	__set_bit(ABS_Y, input_dev->absbit);
+	__set_bit(ABS_PRESSURE, input_dev->absbit);
+
+	input_set_abs_params(input_dev, ABS_X,
+			pdata->x_min ? : 0,
+			pdata->x_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			pdata->y_min ? : 0,
+			pdata->y_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE,
+			pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+	ad7877_write(spi, AD7877_REG_SEQ1, AD7877_MM_SEQUENCE);
+
+	verify = ad7877_read(spi, AD7877_REG_SEQ1);
+
+	if (verify != AD7877_MM_SEQUENCE){
+		dev_err(&spi->dev, "%s: Failed to probe %s\n",
+			dev_name(&spi->dev), input_dev->name);
+		err = -ENODEV;
+		goto err_free_mem;
+	}
+
+	if (gpio3)
+		ad7877_write(spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_3_CONF);
+
+	ad7877_setup_ts_def_msg(spi, ts);
+
+	/* Request AD7877 /DAV GPIO interrupt */
+
+	err = request_threaded_irq(spi->irq, NULL, ad7877_irq,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   spi->dev.driver->name, ts);
+	if (err) {
+		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+		goto err_free_mem;
+	}
+
+	err = sysfs_create_group(&spi->dev.kobj, &ad7877_attr_group);
+	if (err)
+		goto err_free_irq;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_attr_group;
+
+	return 0;
+
+err_remove_attr_group:
+	sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
+err_free_irq:
+	free_irq(spi->irq, ts);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	dev_set_drvdata(&spi->dev, NULL);
+	return err;
+}
+
+static int __devexit ad7877_remove(struct spi_device *spi)
+{
+	struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+
+	sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
+
+	ad7877_disable(ts);
+	free_irq(ts->spi->irq, ts);
+
+	input_unregister_device(ts->input);
+	kfree(ts);
+
+	dev_dbg(&spi->dev, "unregistered touchscreen\n");
+	dev_set_drvdata(&spi->dev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ad7877_suspend(struct device *dev)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+
+	ad7877_disable(ts);
+
+	return 0;
+}
+
+static int ad7877_resume(struct device *dev)
+{
+	struct ad7877 *ts = dev_get_drvdata(dev);
+
+	ad7877_enable(ts);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
+
+static struct spi_driver ad7877_driver = {
+	.driver = {
+		.name	= "ad7877",
+		.owner	= THIS_MODULE,
+		.pm	= &ad7877_pm,
+	},
+	.probe		= ad7877_probe,
+	.remove		= __devexit_p(ad7877_remove),
+};
+
+module_spi_driver(ad7877_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7877 touchscreen Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad7877");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879-i2c.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879-i2c.c
new file mode 100644
index 0000000..3054354
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879-i2c.c
@@ -0,0 +1,109 @@
+/*
+ * AD7879-1/AD7889-1 touchscreen (I2C bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pm.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID		0x79	/* AD7879-1/AD7889-1 */
+
+/* All registers are word-sized.
+ * AD7879 uses a high-byte first convention.
+ */
+static int ad7879_i2c_read(struct device *dev, u8 reg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int ad7879_i2c_multi_read(struct device *dev,
+				 u8 first_reg, u8 count, u16 *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	u8 idx;
+
+	i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf);
+
+	for (idx = 0; idx < count; ++idx)
+		buf[idx] = swab16(buf[idx]);
+
+	return 0;
+}
+
+static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_write_word_swapped(client, reg, val);
+}
+
+static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
+	.bustype	= BUS_I2C,
+	.read		= ad7879_i2c_read,
+	.multi_read	= ad7879_i2c_multi_read,
+	.write		= ad7879_i2c_write,
+};
+
+static int __devinit ad7879_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	struct ad7879 *ts;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+		return -EIO;
+	}
+
+	ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq,
+			  &ad7879_i2c_bus_ops);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+}
+
+static int __devexit ad7879_i2c_remove(struct i2c_client *client)
+{
+	struct ad7879 *ts = i2c_get_clientdata(client);
+
+	ad7879_remove(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id ad7879_id[] = {
+	{ "ad7879", 0 },
+	{ "ad7889", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad7879_id);
+
+static struct i2c_driver ad7879_i2c_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.owner	= THIS_MODULE,
+		.pm	= &ad7879_pm_ops,
+	},
+	.probe		= ad7879_i2c_probe,
+	.remove		= __devexit_p(ad7879_i2c_remove),
+	.id_table	= ad7879_id,
+};
+
+module_i2c_driver(ad7879_i2c_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879-spi.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879-spi.c
new file mode 100644
index 0000000..db49abf
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879-spi.c
@@ -0,0 +1,165 @@
+/*
+ * AD7879/AD7889 touchscreen (SPI bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_SPI */
+#include <linux/pm.h>
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID		0x7A	/* AD7879/AD7889 */
+
+#define MAX_SPI_FREQ_HZ      5000000
+#define AD7879_CMD_MAGIC     0xE000
+#define AD7879_CMD_READ      (1 << 10)
+#define AD7879_CMD(reg)      (AD7879_CMD_MAGIC | ((reg) & 0xF))
+#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
+#define AD7879_READCMD(reg)  (AD7879_CMD(reg) | AD7879_CMD_READ)
+
+/*
+ * ad7879_read/write are only used for initial setup and for sysfs controls.
+ * The main traffic is done in ad7879_collect().
+ */
+
+static int ad7879_spi_xfer(struct spi_device *spi,
+			   u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf)
+{
+	struct spi_message msg;
+	struct spi_transfer *xfers;
+	void *spi_data;
+	u16 *command;
+	u16 *_rx_buf = _rx_buf; /* shut gcc up */
+	u8 idx;
+	int ret;
+
+	xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL);
+	if (!spi_data)
+		return -ENOMEM;
+
+	spi_message_init(&msg);
+
+	command = spi_data;
+	command[0] = cmd;
+	if (count == 1) {
+		/* ad7879_spi_{read,write} gave us buf on stack */
+		command[1] = *tx_buf;
+		tx_buf = &command[1];
+		_rx_buf = rx_buf;
+		rx_buf = &command[2];
+	}
+
+	++xfers;
+	xfers[0].tx_buf = command;
+	xfers[0].len = 2;
+	spi_message_add_tail(&xfers[0], &msg);
+	++xfers;
+
+	for (idx = 0; idx < count; ++idx) {
+		if (rx_buf)
+			xfers[idx].rx_buf = &rx_buf[idx];
+		if (tx_buf)
+			xfers[idx].tx_buf = &tx_buf[idx];
+		xfers[idx].len = 2;
+		spi_message_add_tail(&xfers[idx], &msg);
+	}
+
+	ret = spi_sync(spi, &msg);
+
+	if (count == 1)
+		_rx_buf[0] = command[2];
+
+	kfree(spi_data);
+
+	return ret;
+}
+
+static int ad7879_spi_multi_read(struct device *dev,
+				 u8 first_reg, u8 count, u16 *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf);
+}
+
+static int ad7879_spi_read(struct device *dev, u8 reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u16 ret, dummy;
+
+	return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret;
+}
+
+static int ad7879_spi_write(struct device *dev, u8 reg, u16 val)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u16 dummy;
+
+	return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy);
+}
+
+static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
+	.bustype	= BUS_SPI,
+	.read		= ad7879_spi_read,
+	.multi_read	= ad7879_spi_multi_read,
+	.write		= ad7879_spi_write,
+};
+
+static int __devinit ad7879_spi_probe(struct spi_device *spi)
+{
+	struct ad7879 *ts;
+	int err;
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	spi->bits_per_word = 16;
+	err = spi_setup(spi);
+	if (err) {
+	        dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
+	        return err;
+	}
+
+	ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	spi_set_drvdata(spi, ts);
+
+	return 0;
+}
+
+static int __devexit ad7879_spi_remove(struct spi_device *spi)
+{
+	struct ad7879 *ts = spi_get_drvdata(spi);
+
+	ad7879_remove(ts);
+	spi_set_drvdata(spi, NULL);
+
+	return 0;
+}
+
+static struct spi_driver ad7879_spi_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.owner	= THIS_MODULE,
+		.pm	= &ad7879_pm_ops,
+	},
+	.probe		= ad7879_spi_probe,
+	.remove		= __devexit_p(ad7879_spi_remove),
+};
+
+module_spi_driver(ad7879_spi_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad7879");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879.c
new file mode 100644
index 0000000..e2482b4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879.c
@@ -0,0 +1,649 @@
+/*
+ * AD7879/AD7889 based touchscreen and GPIO driver
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * History:
+ * Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006 Nokia Corporation
+ * Various changes: Imre Deak <imre.deak@nokia.com>
+ *
+ * Using code from:
+ *  - corgi_ts.c
+ *	Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *	Copyright (C) 2002 MontaVista Software
+ *	Copyright (C) 2004 Texas Instruments
+ *	Copyright (C) 2005 Dirk Behme
+ *  - ad7877.c
+ *	Copyright (C) 2006-2008 Analog Devices Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#include <linux/spi/ad7879.h>
+#include <linux/module.h>
+#include "ad7879.h"
+
+#define AD7879_REG_ZEROS		0
+#define AD7879_REG_CTRL1		1
+#define AD7879_REG_CTRL2		2
+#define AD7879_REG_CTRL3		3
+#define AD7879_REG_AUX1HIGH		4
+#define AD7879_REG_AUX1LOW		5
+#define AD7879_REG_TEMP1HIGH		6
+#define AD7879_REG_TEMP1LOW		7
+#define AD7879_REG_XPLUS		8
+#define AD7879_REG_YPLUS		9
+#define AD7879_REG_Z1			10
+#define AD7879_REG_Z2			11
+#define AD7879_REG_AUXVBAT		12
+#define AD7879_REG_TEMP			13
+#define AD7879_REG_REVID		14
+
+/* Control REG 1 */
+#define AD7879_TMR(x)			((x & 0xFF) << 0)
+#define AD7879_ACQ(x)			((x & 0x3) << 8)
+#define AD7879_MODE_NOC			(0 << 10)	/* Do not convert */
+#define AD7879_MODE_SCC			(1 << 10)	/* Single channel conversion */
+#define AD7879_MODE_SEQ0		(2 << 10)	/* Sequence 0 in Slave Mode */
+#define AD7879_MODE_SEQ1		(3 << 10)	/* Sequence 1 in Master Mode */
+#define AD7879_MODE_INT			(1 << 15)	/* PENIRQ disabled INT enabled */
+
+/* Control REG 2 */
+#define AD7879_FCD(x)			((x & 0x3) << 0)
+#define AD7879_RESET			(1 << 4)
+#define AD7879_MFS(x)			((x & 0x3) << 5)
+#define AD7879_AVG(x)			((x & 0x3) << 7)
+#define	AD7879_SER			(1 << 9)	/* non-differential */
+#define	AD7879_DFR			(0 << 9)	/* differential */
+#define AD7879_GPIOPOL			(1 << 10)
+#define AD7879_GPIODIR			(1 << 11)
+#define AD7879_GPIO_DATA		(1 << 12)
+#define AD7879_GPIO_EN			(1 << 13)
+#define AD7879_PM(x)			((x & 0x3) << 14)
+#define AD7879_PM_SHUTDOWN		(0)
+#define AD7879_PM_DYN			(1)
+#define AD7879_PM_FULLON		(2)
+
+/* Control REG 3 */
+#define AD7879_TEMPMASK_BIT		(1<<15)
+#define AD7879_AUXVBATMASK_BIT		(1<<14)
+#define AD7879_INTMODE_BIT		(1<<13)
+#define AD7879_GPIOALERTMASK_BIT	(1<<12)
+#define AD7879_AUXLOW_BIT		(1<<11)
+#define AD7879_AUXHIGH_BIT		(1<<10)
+#define AD7879_TEMPLOW_BIT		(1<<9)
+#define AD7879_TEMPHIGH_BIT		(1<<8)
+#define AD7879_YPLUS_BIT		(1<<7)
+#define AD7879_XPLUS_BIT		(1<<6)
+#define AD7879_Z1_BIT			(1<<5)
+#define AD7879_Z2_BIT			(1<<4)
+#define AD7879_AUX_BIT			(1<<3)
+#define AD7879_VBAT_BIT			(1<<2)
+#define AD7879_TEMP_BIT			(1<<1)
+
+enum {
+	AD7879_SEQ_XPOS  = 0,
+	AD7879_SEQ_YPOS  = 1,
+	AD7879_SEQ_Z1    = 2,
+	AD7879_SEQ_Z2    = 3,
+	AD7879_NR_SENSE  = 4,
+};
+
+#define	MAX_12BIT			((1<<12)-1)
+#define	TS_PEN_UP_TIMEOUT		msecs_to_jiffies(50)
+
+struct ad7879 {
+	const struct ad7879_bus_ops *bops;
+
+	struct device		*dev;
+	struct input_dev	*input;
+	struct timer_list	timer;
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip	gc;
+	struct mutex		mutex;
+#endif
+	unsigned int		irq;
+	bool			disabled;	/* P: input->mutex */
+	bool			suspended;	/* P: input->mutex */
+	u16			conversion_data[AD7879_NR_SENSE];
+	char			phys[32];
+	u8			first_conversion_delay;
+	u8			acquisition_time;
+	u8			averaging;
+	u8			pen_down_acc_interval;
+	u8			median;
+	u16			x_plate_ohms;
+	u16			pressure_max;
+	u16			cmd_crtl1;
+	u16			cmd_crtl2;
+	u16			cmd_crtl3;
+	int			x;
+	int			y;
+	int			Rt;
+};
+
+static int ad7879_read(struct ad7879 *ts, u8 reg)
+{
+	return ts->bops->read(ts->dev, reg);
+}
+
+static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf)
+{
+	return ts->bops->multi_read(ts->dev, first_reg, count, buf);
+}
+
+static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
+{
+	return ts->bops->write(ts->dev, reg, val);
+}
+
+static int ad7879_report(struct ad7879 *ts)
+{
+	struct input_dev *input_dev = ts->input;
+	unsigned Rt;
+	u16 x, y, z1, z2;
+
+	x = ts->conversion_data[AD7879_SEQ_XPOS] & MAX_12BIT;
+	y = ts->conversion_data[AD7879_SEQ_YPOS] & MAX_12BIT;
+	z1 = ts->conversion_data[AD7879_SEQ_Z1] & MAX_12BIT;
+	z2 = ts->conversion_data[AD7879_SEQ_Z2] & MAX_12BIT;
+
+	/*
+	 * The samples processed here are already preprocessed by the AD7879.
+	 * The preprocessing function consists of a median and an averaging
+	 * filter.  The combination of these two techniques provides a robust
+	 * solution, discarding the spurious noise in the signal and keeping
+	 * only the data of interest.  The size of both filters is
+	 * programmable. (dev.platform_data, see linux/spi/ad7879.h) Other
+	 * user-programmable conversion controls include variable acquisition
+	 * time, and first conversion delay. Up to 16 averages can be taken
+	 * per conversion.
+	 */
+
+	if (likely(x && z1)) {
+		/* compute touch pressure resistance using equation #1 */
+		Rt = (z2 - z1) * x * ts->x_plate_ohms;
+		Rt /= z1;
+		Rt = (Rt + 2047) >> 12;
+
+		/*
+		 * Sample found inconsistent, pressure is beyond
+		 * the maximum. Don't report it to user space.
+		 */
+		if (Rt > ts->pressure_max)
+			return -EINVAL;
+
+		/*
+		 * Note that we delay reporting events by one sample.
+		 * This is done to avoid reporting last sample of the
+		 * touch sequence, which may be incomplete if finger
+		 * leaves the surface before last reading is taken.
+		 */
+		if (timer_pending(&ts->timer)) {
+			/* Touch continues */
+			input_report_key(input_dev, BTN_TOUCH, 1);
+			input_report_abs(input_dev, ABS_X, ts->x);
+			input_report_abs(input_dev, ABS_Y, ts->y);
+			input_report_abs(input_dev, ABS_PRESSURE, ts->Rt);
+			input_sync(input_dev);
+		}
+
+		ts->x = x;
+		ts->y = y;
+		ts->Rt = Rt;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static void ad7879_ts_event_release(struct ad7879 *ts)
+{
+	struct input_dev *input_dev = ts->input;
+
+	input_report_abs(input_dev, ABS_PRESSURE, 0);
+	input_report_key(input_dev, BTN_TOUCH, 0);
+	input_sync(input_dev);
+}
+
+static void ad7879_timer(unsigned long handle)
+{
+	struct ad7879 *ts = (void *)handle;
+
+	ad7879_ts_event_release(ts);
+}
+
+static irqreturn_t ad7879_irq(int irq, void *handle)
+{
+	struct ad7879 *ts = handle;
+
+	ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data);
+
+	if (!ad7879_report(ts))
+		mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+
+	return IRQ_HANDLED;
+}
+
+static void __ad7879_enable(struct ad7879 *ts)
+{
+	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(ts, AD7879_REG_CTRL3, ts->cmd_crtl3);
+	ad7879_write(ts, AD7879_REG_CTRL1, ts->cmd_crtl1);
+
+	enable_irq(ts->irq);
+}
+
+static void __ad7879_disable(struct ad7879 *ts)
+{
+	u16 reg = (ts->cmd_crtl2 & ~AD7879_PM(-1)) |
+		AD7879_PM(AD7879_PM_SHUTDOWN);
+	disable_irq(ts->irq);
+
+	if (del_timer_sync(&ts->timer))
+		ad7879_ts_event_release(ts);
+
+	ad7879_write(ts, AD7879_REG_CTRL2, reg);
+}
+
+
+static int ad7879_open(struct input_dev *input)
+{
+	struct ad7879 *ts = input_get_drvdata(input);
+
+	/* protected by input->mutex */
+	if (!ts->disabled && !ts->suspended)
+		__ad7879_enable(ts);
+
+	return 0;
+}
+
+static void ad7879_close(struct input_dev* input)
+{
+	struct ad7879 *ts = input_get_drvdata(input);
+
+	/* protected by input->mutex */
+	if (!ts->disabled && !ts->suspended)
+		__ad7879_disable(ts);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ad7879_suspend(struct device *dev)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->input->mutex);
+
+	if (!ts->suspended && !ts->disabled && ts->input->users)
+		__ad7879_disable(ts);
+
+	ts->suspended = true;
+
+	mutex_unlock(&ts->input->mutex);
+
+	return 0;
+}
+
+static int ad7879_resume(struct device *dev)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->input->mutex);
+
+	if (ts->suspended && !ts->disabled && ts->input->users)
+		__ad7879_enable(ts);
+
+	ts->suspended = false;
+
+	mutex_unlock(&ts->input->mutex);
+
+	return 0;
+}
+#endif
+
+SIMPLE_DEV_PM_OPS(ad7879_pm_ops, ad7879_suspend, ad7879_resume);
+EXPORT_SYMBOL(ad7879_pm_ops);
+
+static void ad7879_toggle(struct ad7879 *ts, bool disable)
+{
+	mutex_lock(&ts->input->mutex);
+
+	if (!ts->suspended && ts->input->users != 0) {
+
+		if (disable) {
+			if (ts->disabled)
+				__ad7879_enable(ts);
+		} else {
+			if (!ts->disabled)
+				__ad7879_disable(ts);
+		}
+	}
+
+	ts->disabled = disable;
+
+	mutex_unlock(&ts->input->mutex);
+}
+
+static ssize_t ad7879_disable_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t ad7879_disable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ad7879 *ts = dev_get_drvdata(dev);
+	unsigned int val;
+	int error;
+
+	error = kstrtouint(buf, 10, &val);
+	if (error)
+		return error;
+
+	ad7879_toggle(ts, val);
+
+	return count;
+}
+
+static DEVICE_ATTR(disable, 0664, ad7879_disable_show, ad7879_disable_store);
+
+static struct attribute *ad7879_attributes[] = {
+	&dev_attr_disable.attr,
+	NULL
+};
+
+static const struct attribute_group ad7879_attr_group = {
+	.attrs = ad7879_attributes,
+};
+
+#ifdef CONFIG_GPIOLIB
+static int ad7879_gpio_direction_input(struct gpio_chip *chip,
+					unsigned gpio)
+{
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	int err;
+
+	mutex_lock(&ts->mutex);
+	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
+	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	mutex_unlock(&ts->mutex);
+
+	return err;
+}
+
+static int ad7879_gpio_direction_output(struct gpio_chip *chip,
+					unsigned gpio, int level)
+{
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	int err;
+
+	mutex_lock(&ts->mutex);
+	ts->cmd_crtl2 &= ~AD7879_GPIODIR;
+	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIOPOL;
+	if (level)
+		ts->cmd_crtl2 |= AD7879_GPIO_DATA;
+	else
+		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
+
+	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	mutex_unlock(&ts->mutex);
+
+	return err;
+}
+
+static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+	u16 val;
+
+	mutex_lock(&ts->mutex);
+	val = ad7879_read(ts, AD7879_REG_CTRL2);
+	mutex_unlock(&ts->mutex);
+
+	return !!(val & AD7879_GPIO_DATA);
+}
+
+static void ad7879_gpio_set_value(struct gpio_chip *chip,
+				  unsigned gpio, int value)
+{
+	struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+
+	mutex_lock(&ts->mutex);
+	if (value)
+		ts->cmd_crtl2 |= AD7879_GPIO_DATA;
+	else
+		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
+
+	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	mutex_unlock(&ts->mutex);
+}
+
+static int ad7879_gpio_add(struct ad7879 *ts,
+			   const struct ad7879_platform_data *pdata)
+{
+	int ret = 0;
+
+	mutex_init(&ts->mutex);
+
+	if (pdata->gpio_export) {
+		ts->gc.direction_input = ad7879_gpio_direction_input;
+		ts->gc.direction_output = ad7879_gpio_direction_output;
+		ts->gc.get = ad7879_gpio_get_value;
+		ts->gc.set = ad7879_gpio_set_value;
+		ts->gc.can_sleep = 1;
+		ts->gc.base = pdata->gpio_base;
+		ts->gc.ngpio = 1;
+		ts->gc.label = "AD7879-GPIO";
+		ts->gc.owner = THIS_MODULE;
+		ts->gc.dev = ts->dev;
+
+		ret = gpiochip_add(&ts->gc);
+		if (ret)
+			dev_err(ts->dev, "failed to register gpio %d\n",
+				ts->gc.base);
+	}
+
+	return ret;
+}
+
+static void ad7879_gpio_remove(struct ad7879 *ts)
+{
+	const struct ad7879_platform_data *pdata = ts->dev->platform_data;
+	int ret;
+
+	if (pdata->gpio_export) {
+		ret = gpiochip_remove(&ts->gc);
+		if (ret)
+			dev_err(ts->dev, "failed to remove gpio %d\n",
+				ts->gc.base);
+	}
+}
+#else
+static inline int ad7879_gpio_add(struct ad7879 *ts,
+				  const struct ad7879_platform_data *pdata)
+{
+	return 0;
+}
+
+static inline void ad7879_gpio_remove(struct ad7879 *ts)
+{
+}
+#endif
+
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
+			    const struct ad7879_bus_ops *bops)
+{
+	struct ad7879_platform_data *pdata = dev->platform_data;
+	struct ad7879 *ts;
+	struct input_dev *input_dev;
+	int err;
+	u16 revid;
+
+	if (!irq) {
+		dev_err(dev, "no IRQ?\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+
+	if (!pdata) {
+		dev_err(dev, "no platform data?\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->bops = bops;
+	ts->dev = dev;
+	ts->input = input_dev;
+	ts->irq = irq;
+
+	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
+
+	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+	ts->pressure_max = pdata->pressure_max ? : ~0;
+
+	ts->first_conversion_delay = pdata->first_conversion_delay;
+	ts->acquisition_time = pdata->acquisition_time;
+	ts->averaging = pdata->averaging;
+	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
+	ts->median = pdata->median;
+
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
+
+	input_dev->name = "AD7879 Touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->dev.parent = dev;
+	input_dev->id.bustype = bops->bustype;
+
+	input_dev->open = ad7879_open;
+	input_dev->close = ad7879_close;
+
+	input_set_drvdata(input_dev, ts);
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(ABS_X, input_dev->absbit);
+	__set_bit(ABS_Y, input_dev->absbit);
+	__set_bit(ABS_PRESSURE, input_dev->absbit);
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	input_set_abs_params(input_dev, ABS_X,
+			pdata->x_min ? : 0,
+			pdata->x_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			pdata->y_min ? : 0,
+			pdata->y_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE,
+			pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+	err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
+	if (err < 0) {
+		dev_err(dev, "Failed to write %s\n", input_dev->name);
+		goto err_free_mem;
+	}
+
+	revid = ad7879_read(ts, AD7879_REG_REVID);
+	input_dev->id.product = (revid & 0xff);
+	input_dev->id.version = revid >> 8;
+	if (input_dev->id.product != devid) {
+		dev_err(dev, "Failed to probe %s (%x vs %x)\n",
+			input_dev->name, devid, revid);
+		err = -ENODEV;
+		goto err_free_mem;
+	}
+
+	ts->cmd_crtl3 = AD7879_YPLUS_BIT |
+			AD7879_XPLUS_BIT |
+			AD7879_Z2_BIT |
+			AD7879_Z1_BIT |
+			AD7879_TEMPMASK_BIT |
+			AD7879_AUXVBATMASK_BIT |
+			AD7879_GPIOALERTMASK_BIT;
+
+	ts->cmd_crtl2 = AD7879_PM(AD7879_PM_DYN) | AD7879_DFR |
+			AD7879_AVG(ts->averaging) |
+			AD7879_MFS(ts->median) |
+			AD7879_FCD(ts->first_conversion_delay);
+
+	ts->cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
+			AD7879_ACQ(ts->acquisition_time) |
+			AD7879_TMR(ts->pen_down_acc_interval);
+
+	err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
+				   IRQF_TRIGGER_FALLING,
+				   dev_name(dev), ts);
+	if (err) {
+		dev_err(dev, "irq %d busy?\n", ts->irq);
+		goto err_free_mem;
+	}
+
+	__ad7879_disable(ts);
+
+	err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
+	if (err)
+		goto err_free_irq;
+
+	err = ad7879_gpio_add(ts, pdata);
+	if (err)
+		goto err_remove_attr;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_gpio;
+
+	return ts;
+
+err_remove_gpio:
+	ad7879_gpio_remove(ts);
+err_remove_attr:
+	sysfs_remove_group(&dev->kobj, &ad7879_attr_group);
+err_free_irq:
+	free_irq(ts->irq, ts);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+err_out:
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL(ad7879_probe);
+
+void ad7879_remove(struct ad7879 *ts)
+{
+	ad7879_gpio_remove(ts);
+	sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
+	free_irq(ts->irq, ts);
+	input_unregister_device(ts->input);
+	kfree(ts);
+}
+EXPORT_SYMBOL(ad7879_remove);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879.h b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879.h
new file mode 100644
index 0000000..6fd13c4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ad7879.h
@@ -0,0 +1,30 @@
+/*
+ * AD7879/AD7889 touchscreen (bus interfaces)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD7879_H_
+#define _AD7879_H_
+
+#include <linux/types.h>
+
+struct ad7879;
+struct device;
+
+struct ad7879_bus_ops {
+	u16 bustype;
+	int (*read)(struct device *dev, u8 reg);
+	int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
+	int (*write)(struct device *dev, u8 reg, u16 val);
+};
+
+extern const struct dev_pm_ops ad7879_pm_ops;
+
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
+			    const struct ad7879_bus_ops *bops);
+void ad7879_remove(struct ad7879 *);
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ads7846.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ads7846.c
new file mode 100644
index 0000000..f02028e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ads7846.c
@@ -0,0 +1,1440 @@
+/*
+ * ADS7846 based touchscreen and sensor driver
+ *
+ * Copyright (c) 2005 David Brownell
+ * Copyright (c) 2006 Nokia Corporation
+ * Various changes: Imre Deak <imre.deak@nokia.com>
+ *
+ * Using code from:
+ *  - corgi_ts.c
+ *	Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *	Copyright (C) 2002 MontaVista Software
+ *	Copyright (C) 2004 Texas Instruments
+ *	Copyright (C) 2005 Dirk Behme
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/hwmon.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+#include <asm/irq.h>
+
+/*
+ * This code has been heavily tested on a Nokia 770, and lightly
+ * tested on other ads7846 devices (OSK/Mistral, Lubbock, Spitz).
+ * TSC2046 is just newer ads7846 silicon.
+ * Support for ads7843 tested on Atmel at91sam926x-EK.
+ * Support for ads7845 has only been stubbed in.
+ * Support for Analog Devices AD7873 and AD7843 tested.
+ *
+ * IRQ handling needs a workaround because of a shortcoming in handling
+ * edge triggered IRQs on some platforms like the OMAP1/2. These
+ * platforms don't handle the ARM lazy IRQ disabling properly, thus we
+ * have to maintain our own SW IRQ disabled status. This should be
+ * removed as soon as the affected platform's IRQ handling is fixed.
+ *
+ * App note sbaa036 talks in more detail about accurate sampling...
+ * that ought to help in situations like LCDs inducing noise (which
+ * can also be helped by using synch signals) and more generally.
+ * This driver tries to utilize the measures described in the app
+ * note. The strength of filtering can be set in the board-* specific
+ * files.
+ */
+
+#define TS_POLL_DELAY	1	/* ms delay before the first sample */
+#define TS_POLL_PERIOD	5	/* ms delay between samples */
+
+/* this driver doesn't aim at the peak continuous sample rate */
+#define	SAMPLE_BITS	(8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
+
+struct ts_event {
+	/*
+	 * For portability, we can't read 12 bit values using SPI (which
+	 * would make the controller deliver them as native byte order u16
+	 * with msbs zeroed).  Instead, we read them as two 8-bit values,
+	 * *** WHICH NEED BYTESWAPPING *** and range adjustment.
+	 */
+	u16	x;
+	u16	y;
+	u16	z1, z2;
+	bool	ignore;
+	u8	x_buf[3];
+	u8	y_buf[3];
+};
+
+/*
+ * We allocate this separately to avoid cache line sharing issues when
+ * driver is used with DMA-based SPI controllers (like atmel_spi) on
+ * systems where main memory is not DMA-coherent (most non-x86 boards).
+ */
+struct ads7846_packet {
+	u8			read_x, read_y, read_z1, read_z2, pwrdown;
+	u16			dummy;		/* for the pwrdown read */
+	struct ts_event		tc;
+	/* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
+	u8			read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
+};
+
+struct ads7846 {
+	struct input_dev	*input;
+	char			phys[32];
+	char			name[32];
+
+	struct spi_device	*spi;
+	struct regulator	*reg;
+
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
+	struct attribute_group	*attr_group;
+	struct device		*hwmon;
+#endif
+
+	u16			model;
+	u16			vref_mv;
+	u16			vref_delay_usecs;
+	u16			x_plate_ohms;
+	u16			pressure_max;
+
+	bool			swap_xy;
+	bool			use_internal;
+
+	struct ads7846_packet	*packet;
+
+	struct spi_transfer	xfer[18];
+	struct spi_message	msg[5];
+	int			msg_count;
+	wait_queue_head_t	wait;
+
+	bool			pendown;
+
+	int			read_cnt;
+	int			read_rep;
+	int			last_read;
+
+	u16			debounce_max;
+	u16			debounce_tol;
+	u16			debounce_rep;
+
+	u16			penirq_recheck_delay_usecs;
+
+	struct mutex		lock;
+	bool			stopped;	/* P: lock */
+	bool			disabled;	/* P: lock */
+	bool			suspended;	/* P: lock */
+
+	int			(*filter)(void *data, int data_idx, int *val);
+	void			*filter_data;
+	void			(*filter_cleanup)(void *data);
+	int			(*get_pendown_state)(void);
+	int			gpio_pendown;
+
+	void			(*wait_for_sync)(void);
+};
+
+/* leave chip selected when we're done, for quicker re-select? */
+#if	0
+#define	CS_CHANGE(xfer)	((xfer).cs_change = 1)
+#else
+#define	CS_CHANGE(xfer)	((xfer).cs_change = 0)
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+/* The ADS7846 has touchscreen and other sensors.
+ * Earlier ads784x chips are somewhat compatible.
+ */
+#define	ADS_START		(1 << 7)
+#define	ADS_A2A1A0_d_y		(1 << 4)	/* differential */
+#define	ADS_A2A1A0_d_z1		(3 << 4)	/* differential */
+#define	ADS_A2A1A0_d_z2		(4 << 4)	/* differential */
+#define	ADS_A2A1A0_d_x		(5 << 4)	/* differential */
+#define	ADS_A2A1A0_temp0	(0 << 4)	/* non-differential */
+#define	ADS_A2A1A0_vbatt	(2 << 4)	/* non-differential */
+#define	ADS_A2A1A0_vaux		(6 << 4)	/* non-differential */
+#define	ADS_A2A1A0_temp1	(7 << 4)	/* non-differential */
+#define	ADS_8_BIT		(1 << 3)
+#define	ADS_12_BIT		(0 << 3)
+#define	ADS_SER			(1 << 2)	/* non-differential */
+#define	ADS_DFR			(0 << 2)	/* differential */
+#define	ADS_PD10_PDOWN		(0 << 0)	/* low power mode + penirq */
+#define	ADS_PD10_ADC_ON		(1 << 0)	/* ADC on */
+#define	ADS_PD10_REF_ON		(2 << 0)	/* vREF on + penirq */
+#define	ADS_PD10_ALL_ON		(3 << 0)	/* ADC + vREF on */
+
+#define	MAX_12BIT	((1<<12)-1)
+
+/* leave ADC powered up (disables penirq) between differential samples */
+#define	READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
+	| ADS_12_BIT | ADS_DFR | \
+	(adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
+
+#define	READ_Y(vref)	(READ_12BIT_DFR(y,  1, vref))
+#define	READ_Z1(vref)	(READ_12BIT_DFR(z1, 1, vref))
+#define	READ_Z2(vref)	(READ_12BIT_DFR(z2, 1, vref))
+
+#define	READ_X(vref)	(READ_12BIT_DFR(x,  1, vref))
+#define	PWRDOWN		(READ_12BIT_DFR(y,  0, 0))	/* LAST */
+
+/* single-ended samples need to first power up reference voltage;
+ * we leave both ADC and VREF powered
+ */
+#define	READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
+	| ADS_12_BIT | ADS_SER)
+
+#define	REF_ON	(READ_12BIT_DFR(x, 1, 1))
+#define	REF_OFF	(READ_12BIT_DFR(y, 0, 0))
+
+/* Must be called with ts->lock held */
+static void ads7846_stop(struct ads7846 *ts)
+{
+	if (!ts->disabled && !ts->suspended) {
+		/* Signal IRQ thread to stop polling and disable the handler. */
+		ts->stopped = true;
+		mb();
+		wake_up(&ts->wait);
+		disable_irq(ts->spi->irq);
+	}
+}
+
+/* Must be called with ts->lock held */
+static void ads7846_restart(struct ads7846 *ts)
+{
+	if (!ts->disabled && !ts->suspended) {
+		/* Tell IRQ thread that it may poll the device. */
+		ts->stopped = false;
+		mb();
+		enable_irq(ts->spi->irq);
+	}
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_disable(struct ads7846 *ts)
+{
+	ads7846_stop(ts);
+	regulator_disable(ts->reg);
+
+	/*
+	 * We know the chip's in low power mode since we always
+	 * leave it that way after every request
+	 */
+}
+
+/* Must be called with ts->lock held */
+static void __ads7846_enable(struct ads7846 *ts)
+{
+	regulator_enable(ts->reg);
+	ads7846_restart(ts);
+}
+
+static void ads7846_disable(struct ads7846 *ts)
+{
+	mutex_lock(&ts->lock);
+
+	if (!ts->disabled) {
+
+		if  (!ts->suspended)
+			__ads7846_disable(ts);
+
+		ts->disabled = true;
+	}
+
+	mutex_unlock(&ts->lock);
+}
+
+static void ads7846_enable(struct ads7846 *ts)
+{
+	mutex_lock(&ts->lock);
+
+	if (ts->disabled) {
+
+		ts->disabled = false;
+
+		if (!ts->suspended)
+			__ads7846_enable(ts);
+	}
+
+	mutex_unlock(&ts->lock);
+}
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Non-touchscreen sensors only use single-ended conversions.
+ * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
+ * ads7846 lets that pin be unconnected, to use internal vREF.
+ */
+
+struct ser_req {
+	u8			ref_on;
+	u8			command;
+	u8			ref_off;
+	u16			scratch;
+	struct spi_message	msg;
+	struct spi_transfer	xfer[6];
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	__be16 sample ____cacheline_aligned;
+};
+
+struct ads7845_ser_req {
+	u8			command[3];
+	struct spi_message	msg;
+	struct spi_transfer	xfer[2];
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	u8 sample[3] ____cacheline_aligned;
+};
+
+static int ads7846_read12_ser(struct device *dev, unsigned command)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct ads7846 *ts = dev_get_drvdata(dev);
+	struct ser_req *req;
+	int status;
+
+	req = kzalloc(sizeof *req, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	/* maybe turn on internal vREF, and let it settle */
+	if (ts->use_internal) {
+		req->ref_on = REF_ON;
+		req->xfer[0].tx_buf = &req->ref_on;
+		req->xfer[0].len = 1;
+		spi_message_add_tail(&req->xfer[0], &req->msg);
+
+		req->xfer[1].rx_buf = &req->scratch;
+		req->xfer[1].len = 2;
+
+		/* for 1uF, settle for 800 usec; no cap, 100 usec.  */
+		req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+		spi_message_add_tail(&req->xfer[1], &req->msg);
+
+		/* Enable reference voltage */
+		command |= ADS_PD10_REF_ON;
+	}
+
+	/* Enable ADC in every case */
+	command |= ADS_PD10_ADC_ON;
+
+	/* take sample */
+	req->command = (u8) command;
+	req->xfer[2].tx_buf = &req->command;
+	req->xfer[2].len = 1;
+	spi_message_add_tail(&req->xfer[2], &req->msg);
+
+	req->xfer[3].rx_buf = &req->sample;
+	req->xfer[3].len = 2;
+	spi_message_add_tail(&req->xfer[3], &req->msg);
+
+	/* REVISIT:  take a few more samples, and compare ... */
+
+	/* converter in low power mode & enable PENIRQ */
+	req->ref_off = PWRDOWN;
+	req->xfer[4].tx_buf = &req->ref_off;
+	req->xfer[4].len = 1;
+	spi_message_add_tail(&req->xfer[4], &req->msg);
+
+	req->xfer[5].rx_buf = &req->scratch;
+	req->xfer[5].len = 2;
+	CS_CHANGE(req->xfer[5]);
+	spi_message_add_tail(&req->xfer[5], &req->msg);
+
+	mutex_lock(&ts->lock);
+	ads7846_stop(ts);
+	status = spi_sync(spi, &req->msg);
+	ads7846_restart(ts);
+	mutex_unlock(&ts->lock);
+
+	if (status == 0) {
+		/* on-wire is a must-ignore bit, a BE12 value, then padding */
+		status = be16_to_cpu(req->sample);
+		status = status >> 3;
+		status &= 0x0fff;
+	}
+
+	kfree(req);
+	return status;
+}
+
+static int ads7845_read12_ser(struct device *dev, unsigned command)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct ads7846 *ts = dev_get_drvdata(dev);
+	struct ads7845_ser_req *req;
+	int status;
+
+	req = kzalloc(sizeof *req, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	req->command[0] = (u8) command;
+	req->xfer[0].tx_buf = req->command;
+	req->xfer[0].rx_buf = req->sample;
+	req->xfer[0].len = 3;
+	spi_message_add_tail(&req->xfer[0], &req->msg);
+
+	mutex_lock(&ts->lock);
+	ads7846_stop(ts);
+	status = spi_sync(spi, &req->msg);
+	ads7846_restart(ts);
+	mutex_unlock(&ts->lock);
+
+	if (status == 0) {
+		/* BE12 value, then padding */
+		status = be16_to_cpu(*((u16 *)&req->sample[1]));
+		status = status >> 3;
+		status &= 0x0fff;
+	}
+
+	kfree(req);
+	return status;
+}
+
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
+
+#define SHOW(name, var, adjust) static ssize_t \
+name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+	struct ads7846 *ts = dev_get_drvdata(dev); \
+	ssize_t v = ads7846_read12_ser(dev, \
+			READ_12BIT_SER(var)); \
+	if (v < 0) \
+		return v; \
+	return sprintf(buf, "%u\n", adjust(ts, v)); \
+} \
+static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
+
+
+/* Sysfs conventions report temperatures in millidegrees Celsius.
+ * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
+ * accuracy scheme without calibration data.  For now we won't try either;
+ * userspace sees raw sensor values, and must scale/calibrate appropriately.
+ */
+static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
+{
+	return v;
+}
+
+SHOW(temp0, temp0, null_adjust)		/* temp1_input */
+SHOW(temp1, temp1, null_adjust)		/* temp2_input */
+
+
+/* sysfs conventions report voltages in millivolts.  We can convert voltages
+ * if we know vREF.  userspace may need to scale vAUX to match the board's
+ * external resistors; we assume that vBATT only uses the internal ones.
+ */
+static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
+{
+	unsigned retval = v;
+
+	/* external resistors may scale vAUX into 0..vREF */
+	retval *= ts->vref_mv;
+	retval = retval >> 12;
+
+	return retval;
+}
+
+static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
+{
+	unsigned retval = vaux_adjust(ts, v);
+
+	/* ads7846 has a resistor ladder to scale this signal down */
+	if (ts->model == 7846)
+		retval *= 4;
+
+	return retval;
+}
+
+SHOW(in0_input, vaux, vaux_adjust)
+SHOW(in1_input, vbatt, vbatt_adjust)
+
+static struct attribute *ads7846_attributes[] = {
+	&dev_attr_temp0.attr,
+	&dev_attr_temp1.attr,
+	&dev_attr_in0_input.attr,
+	&dev_attr_in1_input.attr,
+	NULL,
+};
+
+static struct attribute_group ads7846_attr_group = {
+	.attrs = ads7846_attributes,
+};
+
+static struct attribute *ads7843_attributes[] = {
+	&dev_attr_in0_input.attr,
+	&dev_attr_in1_input.attr,
+	NULL,
+};
+
+static struct attribute_group ads7843_attr_group = {
+	.attrs = ads7843_attributes,
+};
+
+static struct attribute *ads7845_attributes[] = {
+	&dev_attr_in0_input.attr,
+	NULL,
+};
+
+static struct attribute_group ads7845_attr_group = {
+	.attrs = ads7845_attributes,
+};
+
+static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
+{
+	struct device *hwmon;
+	int err;
+
+	/* hwmon sensors need a reference voltage */
+	switch (ts->model) {
+	case 7846:
+		if (!ts->vref_mv) {
+			dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
+			ts->vref_mv = 2500;
+			ts->use_internal = true;
+		}
+		break;
+	case 7845:
+	case 7843:
+		if (!ts->vref_mv) {
+			dev_warn(&spi->dev,
+				"external vREF for ADS%d not specified\n",
+				ts->model);
+			return 0;
+		}
+		break;
+	}
+
+	/* different chips have different sensor groups */
+	switch (ts->model) {
+	case 7846:
+		ts->attr_group = &ads7846_attr_group;
+		break;
+	case 7845:
+		ts->attr_group = &ads7845_attr_group;
+		break;
+	case 7843:
+		ts->attr_group = &ads7843_attr_group;
+		break;
+	default:
+		dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model);
+		return 0;
+	}
+
+	err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+	if (err)
+		return err;
+
+	hwmon = hwmon_device_register(&spi->dev);
+	if (IS_ERR(hwmon)) {
+		sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+		return PTR_ERR(hwmon);
+	}
+
+	ts->hwmon = hwmon;
+	return 0;
+}
+
+static void ads784x_hwmon_unregister(struct spi_device *spi,
+				     struct ads7846 *ts)
+{
+	if (ts->hwmon) {
+		sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+		hwmon_device_unregister(ts->hwmon);
+	}
+}
+
+#else
+static inline int ads784x_hwmon_register(struct spi_device *spi,
+					 struct ads7846 *ts)
+{
+	return 0;
+}
+
+static inline void ads784x_hwmon_unregister(struct spi_device *spi,
+					    struct ads7846 *ts)
+{
+}
+#endif
+
+static ssize_t ads7846_pen_down_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ads7846 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->pendown);
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL);
+
+static ssize_t ads7846_disable_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct ads7846 *ts = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t ads7846_disable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ads7846 *ts = dev_get_drvdata(dev);
+	unsigned int i;
+	int err;
+
+	err = kstrtouint(buf, 10, &i);
+	if (err)
+		return err;
+
+	if (i)
+		ads7846_disable(ts);
+	else
+		ads7846_enable(ts);
+
+	return count;
+}
+
+static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
+
+static struct attribute *ads784x_attributes[] = {
+	&dev_attr_pen_down.attr,
+	&dev_attr_disable.attr,
+	NULL,
+};
+
+static struct attribute_group ads784x_attr_group = {
+	.attrs = ads784x_attributes,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int get_pendown_state(struct ads7846 *ts)
+{
+	if (ts->get_pendown_state)
+		return ts->get_pendown_state();
+
+	return !gpio_get_value(ts->gpio_pendown);
+}
+
+static void null_wait_for_sync(void)
+{
+}
+
+static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
+{
+	struct ads7846 *ts = ads;
+
+	if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+		/* Start over collecting consistent readings. */
+		ts->read_rep = 0;
+		/*
+		 * Repeat it, if this was the first read or the read
+		 * wasn't consistent enough.
+		 */
+		if (ts->read_cnt < ts->debounce_max) {
+			ts->last_read = *val;
+			ts->read_cnt++;
+			return ADS7846_FILTER_REPEAT;
+		} else {
+			/*
+			 * Maximum number of debouncing reached and still
+			 * not enough number of consistent readings. Abort
+			 * the whole sample, repeat it in the next sampling
+			 * period.
+			 */
+			ts->read_cnt = 0;
+			return ADS7846_FILTER_IGNORE;
+		}
+	} else {
+		if (++ts->read_rep > ts->debounce_rep) {
+			/*
+			 * Got a good reading for this coordinate,
+			 * go for the next one.
+			 */
+			ts->read_cnt = 0;
+			ts->read_rep = 0;
+			return ADS7846_FILTER_OK;
+		} else {
+			/* Read more values that are consistent. */
+			ts->read_cnt++;
+			return ADS7846_FILTER_REPEAT;
+		}
+	}
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+	return ADS7846_FILTER_OK;
+}
+
+static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
+{
+	struct spi_transfer *t =
+		list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+	if (ts->model == 7845) {
+		return be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+	} else {
+		/*
+		 * adjust:  on-wire is a must-ignore bit, a BE12 value, then
+		 * padding; built from two 8 bit values written msb-first.
+		 */
+		return be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+	}
+}
+
+static void ads7846_update_value(struct spi_message *m, int val)
+{
+	struct spi_transfer *t =
+		list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+
+	*(u16 *)t->rx_buf = val;
+}
+
+static void ads7846_read_state(struct ads7846 *ts)
+{
+	struct ads7846_packet *packet = ts->packet;
+	struct spi_message *m;
+	int msg_idx = 0;
+	int val;
+	int action;
+	int error;
+
+	while (msg_idx < ts->msg_count) {
+
+		ts->wait_for_sync();
+
+		m = &ts->msg[msg_idx];
+		error = spi_sync(ts->spi, m);
+		if (error) {
+			dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
+			packet->tc.ignore = true;
+			return;
+		}
+
+		/*
+		 * Last message is power down request, no need to convert
+		 * or filter the value.
+		 */
+		if (msg_idx < ts->msg_count - 1) {
+
+			val = ads7846_get_value(ts, m);
+
+			action = ts->filter(ts->filter_data, msg_idx, &val);
+			switch (action) {
+			case ADS7846_FILTER_REPEAT:
+				continue;
+
+			case ADS7846_FILTER_IGNORE:
+				packet->tc.ignore = true;
+				msg_idx = ts->msg_count - 1;
+				continue;
+
+			case ADS7846_FILTER_OK:
+				ads7846_update_value(m, val);
+				packet->tc.ignore = false;
+				msg_idx++;
+				break;
+
+			default:
+				BUG();
+			}
+		} else {
+			msg_idx++;
+		}
+	}
+}
+
+static void ads7846_report_state(struct ads7846 *ts)
+{
+	struct ads7846_packet *packet = ts->packet;
+	unsigned int Rt;
+	u16 x, y, z1, z2;
+
+	/*
+	 * ads7846_get_value() does in-place conversion (including byte swap)
+	 * from on-the-wire format as part of debouncing to get stable
+	 * readings.
+	 */
+	if (ts->model == 7845) {
+		x = *(u16 *)packet->tc.x_buf;
+		y = *(u16 *)packet->tc.y_buf;
+		z1 = 0;
+		z2 = 0;
+	} else {
+		x = packet->tc.x;
+		y = packet->tc.y;
+		z1 = packet->tc.z1;
+		z2 = packet->tc.z2;
+	}
+
+	/* range filtering */
+	if (x == MAX_12BIT)
+		x = 0;
+
+	if (ts->model == 7843) {
+		Rt = ts->pressure_max / 2;
+	} else if (ts->model == 7845) {
+		if (get_pendown_state(ts))
+			Rt = ts->pressure_max / 2;
+		else
+			Rt = 0;
+		dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
+	} else if (likely(x && z1)) {
+		/* compute touch pressure resistance using equation #2 */
+		Rt = z2;
+		Rt -= z1;
+		Rt *= x;
+		Rt *= ts->x_plate_ohms;
+		Rt /= z1;
+		Rt = (Rt + 2047) >> 12;
+	} else {
+		Rt = 0;
+	}
+
+	/*
+	 * Sample found inconsistent by debouncing or pressure is beyond
+	 * the maximum. Don't report it to user space, repeat at least
+	 * once more the measurement
+	 */
+	if (packet->tc.ignore || Rt > ts->pressure_max) {
+		dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
+			 packet->tc.ignore, Rt);
+		return;
+	}
+
+	/*
+	 * Maybe check the pendown state before reporting. This discards
+	 * false readings when the pen is lifted.
+	 */
+	if (ts->penirq_recheck_delay_usecs) {
+		udelay(ts->penirq_recheck_delay_usecs);
+		if (!get_pendown_state(ts))
+			Rt = 0;
+	}
+
+	/*
+	 * NOTE: We can't rely on the pressure to determine the pen down
+	 * state, even this controller has a pressure sensor. The pressure
+	 * value can fluctuate for quite a while after lifting the pen and
+	 * in some cases may not even settle at the expected value.
+	 *
+	 * The only safe way to check for the pen up condition is in the
+	 * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
+	 */
+	if (Rt) {
+		struct input_dev *input = ts->input;
+
+		if (ts->swap_xy)
+			swap(x, y);
+
+		if (!ts->pendown) {
+			input_report_key(input, BTN_TOUCH, 1);
+			ts->pendown = true;
+			dev_vdbg(&ts->spi->dev, "DOWN\n");
+		}
+
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+		input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
+
+		input_sync(input);
+		dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
+	}
+}
+
+static irqreturn_t ads7846_hard_irq(int irq, void *handle)
+{
+	struct ads7846 *ts = handle;
+
+	return get_pendown_state(ts) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+
+static irqreturn_t ads7846_irq(int irq, void *handle)
+{
+	struct ads7846 *ts = handle;
+
+	/* Start with a small delay before checking pendown state */
+	msleep(TS_POLL_DELAY);
+
+	while (!ts->stopped && get_pendown_state(ts)) {
+
+		/* pen is down, continue with the measurement */
+		ads7846_read_state(ts);
+
+		if (!ts->stopped)
+			ads7846_report_state(ts);
+
+		wait_event_timeout(ts->wait, ts->stopped,
+				   msecs_to_jiffies(TS_POLL_PERIOD));
+	}
+
+	if (ts->pendown) {
+		struct input_dev *input = ts->input;
+
+		input_report_key(input, BTN_TOUCH, 0);
+		input_report_abs(input, ABS_PRESSURE, 0);
+		input_sync(input);
+
+		ts->pendown = false;
+		dev_vdbg(&ts->spi->dev, "UP\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ads7846_suspend(struct device *dev)
+{
+	struct ads7846 *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->lock);
+
+	if (!ts->suspended) {
+
+		if (!ts->disabled)
+			__ads7846_disable(ts);
+
+		if (device_may_wakeup(&ts->spi->dev))
+			enable_irq_wake(ts->spi->irq);
+
+		ts->suspended = true;
+	}
+
+	mutex_unlock(&ts->lock);
+
+	return 0;
+}
+
+static int ads7846_resume(struct device *dev)
+{
+	struct ads7846 *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->lock);
+
+	if (ts->suspended) {
+
+		ts->suspended = false;
+
+		if (device_may_wakeup(&ts->spi->dev))
+			disable_irq_wake(ts->spi->irq);
+
+		if (!ts->disabled)
+			__ads7846_enable(ts);
+	}
+
+	mutex_unlock(&ts->lock);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
+
+static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts)
+{
+	struct ads7846_platform_data *pdata = spi->dev.platform_data;
+	int err;
+
+	/*
+	 * REVISIT when the irq can be triggered active-low, or if for some
+	 * reason the touchscreen isn't hooked up, we don't need to access
+	 * the pendown state.
+	 */
+
+	if (pdata->get_pendown_state) {
+		ts->get_pendown_state = pdata->get_pendown_state;
+	} else if (gpio_is_valid(pdata->gpio_pendown)) {
+
+		err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN,
+				       "ads7846_pendown");
+		if (err) {
+			dev_err(&spi->dev,
+				"failed to request/setup pendown GPIO%d: %d\n",
+				pdata->gpio_pendown, err);
+			return err;
+		}
+
+		ts->gpio_pendown = pdata->gpio_pendown;
+
+	} else {
+		dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Set up the transfers to read touchscreen state; this assumes we
+ * use formula #2 for pressure, not #3.
+ */
+static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts,
+				const struct ads7846_platform_data *pdata)
+{
+	struct spi_message *m = &ts->msg[0];
+	struct spi_transfer *x = ts->xfer;
+	struct ads7846_packet *packet = ts->packet;
+	int vref = pdata->keep_vref_on;
+
+	if (ts->model == 7873) {
+		/*
+		 * The AD7873 is almost identical to the ADS7846
+		 * keep VREF off during differential/ratiometric
+		 * conversion modes.
+		 */
+		ts->model = 7846;
+		vref = 0;
+	}
+
+	ts->msg_count = 1;
+	spi_message_init(m);
+	m->context = ts;
+
+	if (ts->model == 7845) {
+		packet->read_y_cmd[0] = READ_Y(vref);
+		packet->read_y_cmd[1] = 0;
+		packet->read_y_cmd[2] = 0;
+		x->tx_buf = &packet->read_y_cmd[0];
+		x->rx_buf = &packet->tc.y_buf[0];
+		x->len = 3;
+		spi_message_add_tail(x, m);
+	} else {
+		/* y- still on; turn on only y+ (and ADC) */
+		packet->read_y = READ_Y(vref);
+		x->tx_buf = &packet->read_y;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->tc.y;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
+
+	/*
+	 * The first sample after switching drivers can be low quality;
+	 * optionally discard it, using a second one after the signals
+	 * have had enough time to stabilize.
+	 */
+	if (pdata->settle_delay_usecs) {
+		x->delay_usecs = pdata->settle_delay_usecs;
+
+		x++;
+		x->tx_buf = &packet->read_y;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->tc.y;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
+
+	ts->msg_count++;
+	m++;
+	spi_message_init(m);
+	m->context = ts;
+
+	if (ts->model == 7845) {
+		x++;
+		packet->read_x_cmd[0] = READ_X(vref);
+		packet->read_x_cmd[1] = 0;
+		packet->read_x_cmd[2] = 0;
+		x->tx_buf = &packet->read_x_cmd[0];
+		x->rx_buf = &packet->tc.x_buf[0];
+		x->len = 3;
+		spi_message_add_tail(x, m);
+	} else {
+		/* turn y- off, x+ on, then leave in lowpower */
+		x++;
+		packet->read_x = READ_X(vref);
+		x->tx_buf = &packet->read_x;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->tc.x;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
+
+	/* ... maybe discard first sample ... */
+	if (pdata->settle_delay_usecs) {
+		x->delay_usecs = pdata->settle_delay_usecs;
+
+		x++;
+		x->tx_buf = &packet->read_x;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->tc.x;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
+
+	/* turn y+ off, x- on; we'll use formula #2 */
+	if (ts->model == 7846) {
+		ts->msg_count++;
+		m++;
+		spi_message_init(m);
+		m->context = ts;
+
+		x++;
+		packet->read_z1 = READ_Z1(vref);
+		x->tx_buf = &packet->read_z1;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->tc.z1;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+
+		/* ... maybe discard first sample ... */
+		if (pdata->settle_delay_usecs) {
+			x->delay_usecs = pdata->settle_delay_usecs;
+
+			x++;
+			x->tx_buf = &packet->read_z1;
+			x->len = 1;
+			spi_message_add_tail(x, m);
+
+			x++;
+			x->rx_buf = &packet->tc.z1;
+			x->len = 2;
+			spi_message_add_tail(x, m);
+		}
+
+		ts->msg_count++;
+		m++;
+		spi_message_init(m);
+		m->context = ts;
+
+		x++;
+		packet->read_z2 = READ_Z2(vref);
+		x->tx_buf = &packet->read_z2;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->tc.z2;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+
+		/* ... maybe discard first sample ... */
+		if (pdata->settle_delay_usecs) {
+			x->delay_usecs = pdata->settle_delay_usecs;
+
+			x++;
+			x->tx_buf = &packet->read_z2;
+			x->len = 1;
+			spi_message_add_tail(x, m);
+
+			x++;
+			x->rx_buf = &packet->tc.z2;
+			x->len = 2;
+			spi_message_add_tail(x, m);
+		}
+	}
+
+	/* power down */
+	ts->msg_count++;
+	m++;
+	spi_message_init(m);
+	m->context = ts;
+
+	if (ts->model == 7845) {
+		x++;
+		packet->pwrdown_cmd[0] = PWRDOWN;
+		packet->pwrdown_cmd[1] = 0;
+		packet->pwrdown_cmd[2] = 0;
+		x->tx_buf = &packet->pwrdown_cmd[0];
+		x->len = 3;
+	} else {
+		x++;
+		packet->pwrdown = PWRDOWN;
+		x->tx_buf = &packet->pwrdown;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->dummy;
+		x->len = 2;
+	}
+
+	CS_CHANGE(*x);
+	spi_message_add_tail(x, m);
+}
+
+static int __devinit ads7846_probe(struct spi_device *spi)
+{
+	struct ads7846 *ts;
+	struct ads7846_packet *packet;
+	struct input_dev *input_dev;
+	struct ads7846_platform_data *pdata = spi->dev.platform_data;
+	unsigned long irq_flags;
+	int err;
+
+	if (!spi->irq) {
+		dev_dbg(&spi->dev, "no IRQ?\n");
+		return -ENODEV;
+	}
+
+	if (!pdata) {
+		dev_dbg(&spi->dev, "no platform data?\n");
+		return -ENODEV;
+	}
+
+	/* don't exceed max specified sample rate */
+	if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
+		dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+				(spi->max_speed_hz/SAMPLE_BITS)/1000);
+		return -EINVAL;
+	}
+
+	/* We'd set TX word size 8 bits and RX word size to 13 bits ... except
+	 * that even if the hardware can do that, the SPI controller driver
+	 * may not.  So we stick to very-portable 8 bit words, both RX and TX.
+	 */
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+	err = spi_setup(spi);
+	if (err < 0)
+		return err;
+
+	ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
+	packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !packet || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	dev_set_drvdata(&spi->dev, ts);
+
+	ts->packet = packet;
+	ts->spi = spi;
+	ts->input = input_dev;
+	ts->vref_mv = pdata->vref_mv;
+	ts->swap_xy = pdata->swap_xy;
+
+	mutex_init(&ts->lock);
+	init_waitqueue_head(&ts->wait);
+
+	ts->model = pdata->model ? : 7846;
+	ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
+	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+	ts->pressure_max = pdata->pressure_max ? : ~0;
+
+	if (pdata->filter != NULL) {
+		if (pdata->filter_init != NULL) {
+			err = pdata->filter_init(pdata, &ts->filter_data);
+			if (err < 0)
+				goto err_free_mem;
+		}
+		ts->filter = pdata->filter;
+		ts->filter_cleanup = pdata->filter_cleanup;
+	} else if (pdata->debounce_max) {
+		ts->debounce_max = pdata->debounce_max;
+		if (ts->debounce_max < 2)
+			ts->debounce_max = 2;
+		ts->debounce_tol = pdata->debounce_tol;
+		ts->debounce_rep = pdata->debounce_rep;
+		ts->filter = ads7846_debounce_filter;
+		ts->filter_data = ts;
+	} else {
+		ts->filter = ads7846_no_filter;
+	}
+
+	err = ads7846_setup_pendown(spi, ts);
+	if (err)
+		goto err_cleanup_filter;
+
+	if (pdata->penirq_recheck_delay_usecs)
+		ts->penirq_recheck_delay_usecs =
+				pdata->penirq_recheck_delay_usecs;
+
+	ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
+	snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
+
+	input_dev->name = ts->name;
+	input_dev->phys = ts->phys;
+	input_dev->dev.parent = &spi->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(input_dev, ABS_X,
+			pdata->x_min ? : 0,
+			pdata->x_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			pdata->y_min ? : 0,
+			pdata->y_max ? : MAX_12BIT,
+			0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE,
+			pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+	ads7846_setup_spi_msg(ts, pdata);
+
+	ts->reg = regulator_get(&spi->dev, "vcc");
+	if (IS_ERR(ts->reg)) {
+		err = PTR_ERR(ts->reg);
+		dev_err(&spi->dev, "unable to get regulator: %d\n", err);
+		goto err_free_gpio;
+	}
+
+	err = regulator_enable(ts->reg);
+	if (err) {
+		dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
+		goto err_put_regulator;
+	}
+
+	irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+	irq_flags |= IRQF_ONESHOT;
+
+	err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq,
+				   irq_flags, spi->dev.driver->name, ts);
+	if (err && !pdata->irq_flags) {
+		dev_info(&spi->dev,
+			"trying pin change workaround on irq %d\n", spi->irq);
+		irq_flags |= IRQF_TRIGGER_RISING;
+		err = request_threaded_irq(spi->irq,
+				  ads7846_hard_irq, ads7846_irq,
+				  irq_flags, spi->dev.driver->name, ts);
+	}
+
+	if (err) {
+		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+		goto err_disable_regulator;
+	}
+
+	err = ads784x_hwmon_register(spi, ts);
+	if (err)
+		goto err_free_irq;
+
+	dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
+
+	/*
+	 * Take a first sample, leaving nPENIRQ active and vREF off; avoid
+	 * the touchscreen, in case it's not connected.
+	 */
+	if (ts->model == 7845)
+		ads7845_read12_ser(&spi->dev, PWRDOWN);
+	else
+		(void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
+
+	err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
+	if (err)
+		goto err_remove_hwmon;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_attr_group;
+
+	device_init_wakeup(&spi->dev, pdata->wakeup);
+
+	return 0;
+
+ err_remove_attr_group:
+	sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ err_remove_hwmon:
+	ads784x_hwmon_unregister(spi, ts);
+ err_free_irq:
+	free_irq(spi->irq, ts);
+ err_disable_regulator:
+	regulator_disable(ts->reg);
+ err_put_regulator:
+	regulator_put(ts->reg);
+ err_free_gpio:
+	if (!ts->get_pendown_state)
+		gpio_free(ts->gpio_pendown);
+ err_cleanup_filter:
+	if (ts->filter_cleanup)
+		ts->filter_cleanup(ts->filter_data);
+ err_free_mem:
+	input_free_device(input_dev);
+	kfree(packet);
+	kfree(ts);
+	return err;
+}
+
+static int __devexit ads7846_remove(struct spi_device *spi)
+{
+	struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+
+	device_init_wakeup(&spi->dev, false);
+
+	sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+
+	ads7846_disable(ts);
+	free_irq(ts->spi->irq, ts);
+
+	input_unregister_device(ts->input);
+
+	ads784x_hwmon_unregister(spi, ts);
+
+	regulator_disable(ts->reg);
+	regulator_put(ts->reg);
+
+	if (!ts->get_pendown_state) {
+		/*
+		 * If we are not using specialized pendown method we must
+		 * have been relying on gpio we set up ourselves.
+		 */
+		gpio_free(ts->gpio_pendown);
+	}
+
+	if (ts->filter_cleanup)
+		ts->filter_cleanup(ts->filter_data);
+
+	kfree(ts->packet);
+	kfree(ts);
+
+	dev_dbg(&spi->dev, "unregistered touchscreen\n");
+
+	return 0;
+}
+
+static struct spi_driver ads7846_driver = {
+	.driver = {
+		.name	= "ads7846",
+		.owner	= THIS_MODULE,
+		.pm	= &ads7846_pm,
+	},
+	.probe		= ads7846_probe,
+	.remove		= __devexit_p(ads7846_remove),
+};
+
+module_spi_driver(ads7846_driver);
+
+MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ads7846");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel-wm97xx.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel-wm97xx.c
new file mode 100644
index 0000000..c5c2dbb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel-wm97xx.c
@@ -0,0 +1,449 @@
+/*
+ * Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97
+ * codecs.
+ *
+ * Copyright (C) 2008 - 2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/wm97xx.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define AC97C_ICA		0x10
+#define AC97C_CBRHR		0x30
+#define AC97C_CBSR		0x38
+#define AC97C_CBMR		0x3c
+#define AC97C_IER		0x54
+#define AC97C_IDR		0x58
+
+#define AC97C_RXRDY		(1 << 4)
+#define AC97C_OVRUN		(1 << 5)
+
+#define AC97C_CMR_SIZE_20	(0 << 16)
+#define AC97C_CMR_SIZE_18	(1 << 16)
+#define AC97C_CMR_SIZE_16	(2 << 16)
+#define AC97C_CMR_SIZE_10	(3 << 16)
+#define AC97C_CMR_CEM_LITTLE	(1 << 18)
+#define AC97C_CMR_CEM_BIG	(0 << 18)
+#define AC97C_CMR_CENA		(1 << 21)
+
+#define AC97C_INT_CBEVT		(1 << 4)
+
+#define AC97C_SR_CAEVT		(1 << 3)
+
+#define AC97C_CH_MASK(slot)						\
+	(0x7 << (3 * (slot - 3)))
+#define AC97C_CH_ASSIGN(slot, channel)					\
+	(AC97C_CHANNEL_##channel << (3 * (slot - 3)))
+#define AC97C_CHANNEL_NONE	0x0
+#define AC97C_CHANNEL_B		0x2
+
+#define ac97c_writel(chip, reg, val)			\
+	__raw_writel((val), (chip)->regs + AC97C_##reg)
+#define ac97c_readl(chip, reg)				\
+	__raw_readl((chip)->regs + AC97C_##reg)
+
+#ifdef CONFIG_CPU_AT32AP700X
+#define ATMEL_WM97XX_AC97C_IOMEM	(0xfff02800)
+#define ATMEL_WM97XX_AC97C_IRQ		(29)
+#define ATMEL_WM97XX_GPIO_DEFAULT	(32+16) /* Pin 16 on port B. */
+#else
+#error Unknown CPU, this driver only supports AT32AP700X CPUs.
+#endif
+
+struct continuous {
+	u16 id;    /* codec id */
+	u8 code;   /* continuous code */
+	u8 reads;  /* number of coord reads per read cycle */
+	u32 speed; /* number of coords per second */
+};
+
+#define WM_READS(sp) ((sp / HZ) + 1)
+
+static const struct continuous cinfo[] = {
+	{WM9705_ID2, 0, WM_READS(94), 94},
+	{WM9705_ID2, 1, WM_READS(188), 188},
+	{WM9705_ID2, 2, WM_READS(375), 375},
+	{WM9705_ID2, 3, WM_READS(750), 750},
+	{WM9712_ID2, 0, WM_READS(94), 94},
+	{WM9712_ID2, 1, WM_READS(188), 188},
+	{WM9712_ID2, 2, WM_READS(375), 375},
+	{WM9712_ID2, 3, WM_READS(750), 750},
+	{WM9713_ID2, 0, WM_READS(94), 94},
+	{WM9713_ID2, 1, WM_READS(120), 120},
+	{WM9713_ID2, 2, WM_READS(154), 154},
+	{WM9713_ID2, 3, WM_READS(188), 188},
+};
+
+/* Continuous speed index. */
+static int sp_idx;
+
+/*
+ * Pen sampling frequency (Hz) in continuous mode.
+ */
+static int cont_rate = 188;
+module_param(cont_rate, int, 0);
+MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
+
+/*
+ * Pen down detection.
+ *
+ * This driver can either poll or use an interrupt to indicate a pen down
+ * event. If the irq request fails then it will fall back to polling mode.
+ */
+static int pen_int = 1;
+module_param(pen_int, int, 0);
+MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
+
+/*
+ * Pressure readback.
+ *
+ * Set to 1 to read back pen down pressure.
+ */
+static int pressure;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
+
+/*
+ * AC97 touch data slot.
+ *
+ * Touch screen readback data ac97 slot.
+ */
+static int ac97_touch_slot = 5;
+module_param(ac97_touch_slot, int, 0);
+MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
+
+/*
+ * GPIO line number.
+ *
+ * Set to GPIO number where the signal from the WM97xx device is hooked up.
+ */
+static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT;
+module_param(atmel_gpio_line, int, 0);
+MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx");
+
+struct atmel_wm97xx {
+	struct wm97xx		*wm;
+	struct timer_list	pen_timer;
+	void __iomem		*regs;
+	unsigned long		ac97c_irq;
+	unsigned long		gpio_pen;
+	unsigned long		gpio_irq;
+	unsigned short		x;
+	unsigned short		y;
+};
+
+static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
+{
+	struct atmel_wm97xx *atmel_wm97xx = dev_id;
+	struct wm97xx *wm = atmel_wm97xx->wm;
+	int status = ac97c_readl(atmel_wm97xx, CBSR);
+	irqreturn_t retval = IRQ_NONE;
+
+	if (status & AC97C_OVRUN) {
+		dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n");
+		ac97c_readl(atmel_wm97xx, CBRHR);
+		retval = IRQ_HANDLED;
+	} else if (status & AC97C_RXRDY) {
+		u16 data;
+		u16 value;
+		u16 source;
+		u16 pen_down;
+
+		data = ac97c_readl(atmel_wm97xx, CBRHR);
+		value = data & 0x0fff;
+		source = data & WM97XX_ADCSEL_MASK;
+		pen_down = (data & WM97XX_PEN_DOWN) >> 8;
+
+		if (source == WM97XX_ADCSEL_X)
+			atmel_wm97xx->x = value;
+		if (source == WM97XX_ADCSEL_Y)
+			atmel_wm97xx->y = value;
+
+		if (!pressure && source == WM97XX_ADCSEL_Y) {
+			input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
+			input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
+			input_report_key(wm->input_dev, BTN_TOUCH, pen_down);
+			input_sync(wm->input_dev);
+		} else if (pressure && source == WM97XX_ADCSEL_PRES) {
+			input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
+			input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
+			input_report_abs(wm->input_dev, ABS_PRESSURE, value);
+			input_report_key(wm->input_dev, BTN_TOUCH, value);
+			input_sync(wm->input_dev);
+		}
+
+		retval = IRQ_HANDLED;
+	}
+
+	return retval;
+}
+
+static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
+	struct input_dev *input_dev = wm->input_dev;
+	int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen);
+
+	if (pen_down != 0) {
+		mod_timer(&atmel_wm97xx->pen_timer,
+			  jiffies + msecs_to_jiffies(1));
+	} else {
+		if (pressure)
+			input_report_abs(input_dev, ABS_PRESSURE, 0);
+		input_report_key(input_dev, BTN_TOUCH, 0);
+		input_sync(input_dev);
+	}
+}
+
+static void atmel_wm97xx_pen_timer(unsigned long data)
+{
+	atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
+}
+
+static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
+	int idx = 0;
+
+	if (wm->ac97 == NULL)
+		return -ENODEV;
+
+	for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
+		if (wm->id != cinfo[idx].id)
+			continue;
+
+		sp_idx = idx;
+
+		if (cont_rate <= cinfo[idx].speed)
+			break;
+	}
+
+	wm->acc_rate = cinfo[sp_idx].code;
+	wm->acc_slot = ac97_touch_slot;
+	dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, "
+			"%d samples/sec\n", cinfo[sp_idx].speed);
+
+	if (pen_int) {
+		unsigned long reg;
+
+		wm->pen_irq = atmel_wm97xx->gpio_irq;
+
+		switch (wm->id) {
+		case WM9712_ID2: /* Fall through. */
+		case WM9713_ID2:
+			/*
+			 * Use GPIO 13 (PEN_DOWN) to assert GPIO line 3
+			 * (PENDOWN).
+			 */
+			wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
+					WM97XX_GPIO_POL_HIGH,
+					WM97XX_GPIO_STICKY,
+					WM97XX_GPIO_WAKE);
+			wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT,
+					WM97XX_GPIO_POL_HIGH,
+					WM97XX_GPIO_NOTSTICKY,
+					WM97XX_GPIO_NOWAKE);
+		case WM9705_ID2: /* Fall through. */
+			/*
+			 * Enable touch data slot in AC97 controller channel B.
+			 */
+			reg = ac97c_readl(atmel_wm97xx, ICA);
+			reg &= ~AC97C_CH_MASK(wm->acc_slot);
+			reg |= AC97C_CH_ASSIGN(wm->acc_slot, B);
+			ac97c_writel(atmel_wm97xx, ICA, reg);
+
+			/*
+			 * Enable channel and interrupt for RXRDY and OVERRUN.
+			 */
+			ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA
+					| AC97C_CMR_CEM_BIG
+					| AC97C_CMR_SIZE_16
+					| AC97C_OVRUN
+					| AC97C_RXRDY);
+			/* Dummy read to empty RXRHR. */
+			ac97c_readl(atmel_wm97xx, CBRHR);
+			/*
+			 * Enable interrupt for channel B in the AC97
+			 * controller.
+			 */
+			ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
+			break;
+		default:
+			dev_err(&wm->touch_dev->dev, "pen down irq not "
+					"supported on this device\n");
+			pen_int = 0;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm)
+{
+	if (pen_int) {
+		struct atmel_wm97xx *atmel_wm97xx =
+			platform_get_drvdata(wm->touch_dev);
+		unsigned long ica;
+
+		switch (wm->id & 0xffff) {
+		case WM9705_ID2: /* Fall through. */
+		case WM9712_ID2: /* Fall through. */
+		case WM9713_ID2:
+			/* Disable slot and turn off channel B interrupts. */
+			ica = ac97c_readl(atmel_wm97xx, ICA);
+			ica &= ~AC97C_CH_MASK(wm->acc_slot);
+			ac97c_writel(atmel_wm97xx, ICA, ica);
+			ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
+			ac97c_writel(atmel_wm97xx, CBMR, 0);
+			wm->pen_irq = 0;
+			break;
+		default:
+			dev_err(&wm->touch_dev->dev, "unknown codec\n");
+			break;
+		}
+	}
+}
+
+static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable)
+{
+	/* Intentionally left empty. */
+}
+
+static struct wm97xx_mach_ops atmel_mach_ops = {
+	.acc_enabled	= 1,
+	.acc_pen_up	= atmel_wm97xx_acc_pen_up,
+	.acc_startup	= atmel_wm97xx_acc_startup,
+	.acc_shutdown	= atmel_wm97xx_acc_shutdown,
+	.irq_enable	= atmel_wm97xx_irq_enable,
+	.irq_gpio	= WM97XX_GPIO_3,
+};
+
+static int __init atmel_wm97xx_probe(struct platform_device *pdev)
+{
+	struct wm97xx *wm = platform_get_drvdata(pdev);
+	struct atmel_wm97xx *atmel_wm97xx;
+	int ret;
+
+	atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL);
+	if (!atmel_wm97xx) {
+		dev_dbg(&pdev->dev, "out of memory\n");
+		return -ENOMEM;
+	}
+
+	atmel_wm97xx->wm	= wm;
+	atmel_wm97xx->regs	= (void *)ATMEL_WM97XX_AC97C_IOMEM;
+	atmel_wm97xx->ac97c_irq	= ATMEL_WM97XX_AC97C_IRQ;
+	atmel_wm97xx->gpio_pen	= atmel_gpio_line;
+	atmel_wm97xx->gpio_irq	= gpio_to_irq(atmel_wm97xx->gpio_pen);
+
+	setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
+			(unsigned long)wm);
+
+	ret = request_irq(atmel_wm97xx->ac97c_irq,
+			  atmel_wm97xx_channel_b_interrupt,
+			  IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx);
+	if (ret) {
+		dev_dbg(&pdev->dev, "could not request ac97c irq\n");
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, atmel_wm97xx);
+
+	ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops);
+	if (ret)
+		goto err_irq;
+
+	return ret;
+
+err_irq:
+	free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
+err:
+	platform_set_drvdata(pdev, NULL);
+	kfree(atmel_wm97xx);
+	return ret;
+}
+
+static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
+	struct wm97xx *wm = atmel_wm97xx->wm;
+
+	ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
+	free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
+	del_timer_sync(&atmel_wm97xx->pen_timer);
+	wm97xx_unregister_mach_ops(wm);
+	platform_set_drvdata(pdev, NULL);
+	kfree(atmel_wm97xx);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int atmel_wm97xx_suspend(struct *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
+
+	ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
+	disable_irq(atmel_wm97xx->gpio_irq);
+	del_timer_sync(&atmel_wm97xx->pen_timer);
+
+	return 0;
+}
+
+static int atmel_wm97xx_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
+	struct wm97xx *wm = atmel_wm97xx->wm;
+
+	if (wm->input_dev->users) {
+		enable_irq(atmel_wm97xx->gpio_irq);
+		ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
+	}
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops,
+			 atmel_wm97xx_suspend, atmel_wm97xx_resume);
+
+static struct platform_driver atmel_wm97xx_driver = {
+	.remove		= __exit_p(atmel_wm97xx_remove),
+	.driver		= {
+		.name	= "wm97xx-touch",
+		.owner	= THIS_MODULE,
+		.pm	= &atmel_wm97xx_pm_ops,
+	},
+};
+
+static int __init atmel_wm97xx_init(void)
+{
+	return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
+}
+module_init(atmel_wm97xx_init);
+
+static void __exit atmel_wm97xx_exit(void)
+{
+	platform_driver_unregister(&atmel_wm97xx_driver);
+}
+module_exit(atmel_wm97xx_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
+MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel_mxt_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel_mxt_ts.c
new file mode 100644
index 0000000..19d4ea6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -0,0 +1,1275 @@
+/*
+ * Atmel maXTouch Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Version */
+#define MXT_VER_20		20
+#define MXT_VER_21		21
+#define MXT_VER_22		22
+
+/* Slave addresses */
+#define MXT_APP_LOW		0x4a
+#define MXT_APP_HIGH		0x4b
+#define MXT_BOOT_LOW		0x24
+#define MXT_BOOT_HIGH		0x25
+
+/* Firmware */
+#define MXT_FW_NAME		"maxtouch.fw"
+
+/* Registers */
+#define MXT_FAMILY_ID		0x00
+#define MXT_VARIANT_ID		0x01
+#define MXT_VERSION		0x02
+#define MXT_BUILD		0x03
+#define MXT_MATRIX_X_SIZE	0x04
+#define MXT_MATRIX_Y_SIZE	0x05
+#define MXT_OBJECT_NUM		0x06
+#define MXT_OBJECT_START	0x07
+
+#define MXT_OBJECT_SIZE		6
+
+/* Object types */
+#define MXT_DEBUG_DIAGNOSTIC_T37	37
+#define MXT_GEN_MESSAGE_T5		5
+#define MXT_GEN_COMMAND_T6		6
+#define MXT_GEN_POWER_T7		7
+#define MXT_GEN_ACQUIRE_T8		8
+#define MXT_GEN_DATASOURCE_T53		53
+#define MXT_TOUCH_MULTI_T9		9
+#define MXT_TOUCH_KEYARRAY_T15		15
+#define MXT_TOUCH_PROXIMITY_T23		23
+#define MXT_TOUCH_PROXKEY_T52		52
+#define MXT_PROCI_GRIPFACE_T20		20
+#define MXT_PROCG_NOISE_T22		22
+#define MXT_PROCI_ONETOUCH_T24		24
+#define MXT_PROCI_TWOTOUCH_T27		27
+#define MXT_PROCI_GRIP_T40		40
+#define MXT_PROCI_PALM_T41		41
+#define MXT_PROCI_TOUCHSUPPRESSION_T42	42
+#define MXT_PROCI_STYLUS_T47		47
+#define MXT_PROCG_NOISESUPPRESSION_T48	48
+#define MXT_SPT_COMMSCONFIG_T18		18
+#define MXT_SPT_GPIOPWM_T19		19
+#define MXT_SPT_SELFTEST_T25		25
+#define MXT_SPT_CTECONFIG_T28		28
+#define MXT_SPT_USERDATA_T38		38
+#define MXT_SPT_DIGITIZER_T43		43
+#define MXT_SPT_MESSAGECOUNT_T44	44
+#define MXT_SPT_CTECONFIG_T46		46
+
+/* MXT_GEN_COMMAND_T6 field */
+#define MXT_COMMAND_RESET	0
+#define MXT_COMMAND_BACKUPNV	1
+#define MXT_COMMAND_CALIBRATE	2
+#define MXT_COMMAND_REPORTALL	3
+#define MXT_COMMAND_DIAGNOSTIC	5
+
+/* MXT_GEN_POWER_T7 field */
+#define MXT_POWER_IDLEACQINT	0
+#define MXT_POWER_ACTVACQINT	1
+#define MXT_POWER_ACTV2IDLETO	2
+
+/* MXT_GEN_ACQUIRE_T8 field */
+#define MXT_ACQUIRE_CHRGTIME	0
+#define MXT_ACQUIRE_TCHDRIFT	2
+#define MXT_ACQUIRE_DRIFTST	3
+#define MXT_ACQUIRE_TCHAUTOCAL	4
+#define MXT_ACQUIRE_SYNC	5
+#define MXT_ACQUIRE_ATCHCALST	6
+#define MXT_ACQUIRE_ATCHCALSTHR	7
+
+/* MXT_TOUCH_MULTI_T9 field */
+#define MXT_TOUCH_CTRL		0
+#define MXT_TOUCH_XORIGIN	1
+#define MXT_TOUCH_YORIGIN	2
+#define MXT_TOUCH_XSIZE		3
+#define MXT_TOUCH_YSIZE		4
+#define MXT_TOUCH_BLEN		6
+#define MXT_TOUCH_TCHTHR	7
+#define MXT_TOUCH_TCHDI		8
+#define MXT_TOUCH_ORIENT	9
+#define MXT_TOUCH_MOVHYSTI	11
+#define MXT_TOUCH_MOVHYSTN	12
+#define MXT_TOUCH_NUMTOUCH	14
+#define MXT_TOUCH_MRGHYST	15
+#define MXT_TOUCH_MRGTHR	16
+#define MXT_TOUCH_AMPHYST	17
+#define MXT_TOUCH_XRANGE_LSB	18
+#define MXT_TOUCH_XRANGE_MSB	19
+#define MXT_TOUCH_YRANGE_LSB	20
+#define MXT_TOUCH_YRANGE_MSB	21
+#define MXT_TOUCH_XLOCLIP	22
+#define MXT_TOUCH_XHICLIP	23
+#define MXT_TOUCH_YLOCLIP	24
+#define MXT_TOUCH_YHICLIP	25
+#define MXT_TOUCH_XEDGECTRL	26
+#define MXT_TOUCH_XEDGEDIST	27
+#define MXT_TOUCH_YEDGECTRL	28
+#define MXT_TOUCH_YEDGEDIST	29
+#define MXT_TOUCH_JUMPLIMIT	30
+
+/* MXT_PROCI_GRIPFACE_T20 field */
+#define MXT_GRIPFACE_CTRL	0
+#define MXT_GRIPFACE_XLOGRIP	1
+#define MXT_GRIPFACE_XHIGRIP	2
+#define MXT_GRIPFACE_YLOGRIP	3
+#define MXT_GRIPFACE_YHIGRIP	4
+#define MXT_GRIPFACE_MAXTCHS	5
+#define MXT_GRIPFACE_SZTHR1	7
+#define MXT_GRIPFACE_SZTHR2	8
+#define MXT_GRIPFACE_SHPTHR1	9
+#define MXT_GRIPFACE_SHPTHR2	10
+#define MXT_GRIPFACE_SUPEXTTO	11
+
+/* MXT_PROCI_NOISE field */
+#define MXT_NOISE_CTRL		0
+#define MXT_NOISE_OUTFLEN	1
+#define MXT_NOISE_GCAFUL_LSB	3
+#define MXT_NOISE_GCAFUL_MSB	4
+#define MXT_NOISE_GCAFLL_LSB	5
+#define MXT_NOISE_GCAFLL_MSB	6
+#define MXT_NOISE_ACTVGCAFVALID	7
+#define MXT_NOISE_NOISETHR	8
+#define MXT_NOISE_FREQHOPSCALE	10
+#define MXT_NOISE_FREQ0		11
+#define MXT_NOISE_FREQ1		12
+#define MXT_NOISE_FREQ2		13
+#define MXT_NOISE_FREQ3		14
+#define MXT_NOISE_FREQ4		15
+#define MXT_NOISE_IDLEGCAFVALID	16
+
+/* MXT_SPT_COMMSCONFIG_T18 */
+#define MXT_COMMS_CTRL		0
+#define MXT_COMMS_CMD		1
+
+/* MXT_SPT_CTECONFIG_T28 field */
+#define MXT_CTE_CTRL		0
+#define MXT_CTE_CMD		1
+#define MXT_CTE_MODE		2
+#define MXT_CTE_IDLEGCAFDEPTH	3
+#define MXT_CTE_ACTVGCAFDEPTH	4
+#define MXT_CTE_VOLTAGE		5
+
+#define MXT_VOLTAGE_DEFAULT	2700000
+#define MXT_VOLTAGE_STEP	10000
+
+/* Define for MXT_GEN_COMMAND_T6 */
+#define MXT_BOOT_VALUE		0xa5
+#define MXT_BACKUP_VALUE	0x55
+#define MXT_BACKUP_TIME		25	/* msec */
+#define MXT_RESET_TIME		65	/* msec */
+
+#define MXT_FWRESET_TIME	175	/* msec */
+
+/* Command to unlock bootloader */
+#define MXT_UNLOCK_CMD_MSB	0xaa
+#define MXT_UNLOCK_CMD_LSB	0xdc
+
+/* Bootloader mode status */
+#define MXT_WAITING_BOOTLOAD_CMD	0xc0	/* valid 7 6 bit only */
+#define MXT_WAITING_FRAME_DATA	0x80	/* valid 7 6 bit only */
+#define MXT_FRAME_CRC_CHECK	0x02
+#define MXT_FRAME_CRC_FAIL	0x03
+#define MXT_FRAME_CRC_PASS	0x04
+#define MXT_APP_CRC_FAIL	0x40	/* valid 7 8 bit only */
+#define MXT_BOOT_STATUS_MASK	0x3f
+
+/* Touch status */
+#define MXT_SUPPRESS		(1 << 1)
+#define MXT_AMP			(1 << 2)
+#define MXT_VECTOR		(1 << 3)
+#define MXT_MOVE		(1 << 4)
+#define MXT_RELEASE		(1 << 5)
+#define MXT_PRESS		(1 << 6)
+#define MXT_DETECT		(1 << 7)
+
+/* Touch orient bits */
+#define MXT_XY_SWITCH		(1 << 0)
+#define MXT_X_INVERT		(1 << 1)
+#define MXT_Y_INVERT		(1 << 2)
+
+/* Touchscreen absolute values */
+#define MXT_MAX_AREA		0xff
+
+#define MXT_MAX_FINGER		10
+
+struct mxt_info {
+	u8 family_id;
+	u8 variant_id;
+	u8 version;
+	u8 build;
+	u8 matrix_xsize;
+	u8 matrix_ysize;
+	u8 object_num;
+};
+
+struct mxt_object {
+	u8 type;
+	u16 start_address;
+	u8 size;
+	u8 instances;
+	u8 num_report_ids;
+
+	/* to map object and message */
+	u8 max_reportid;
+};
+
+struct mxt_message {
+	u8 reportid;
+	u8 message[7];
+	u8 checksum;
+};
+
+struct mxt_finger {
+	int status;
+	int x;
+	int y;
+	int area;
+	int pressure;
+};
+
+/* Each client has this additional data */
+struct mxt_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	const struct mxt_platform_data *pdata;
+	struct mxt_object *object_table;
+	struct mxt_info info;
+	struct mxt_finger finger[MXT_MAX_FINGER];
+	unsigned int irq;
+	unsigned int max_x;
+	unsigned int max_y;
+};
+
+static bool mxt_object_readable(unsigned int type)
+{
+	switch (type) {
+	case MXT_GEN_MESSAGE_T5:
+	case MXT_GEN_COMMAND_T6:
+	case MXT_GEN_POWER_T7:
+	case MXT_GEN_ACQUIRE_T8:
+	case MXT_GEN_DATASOURCE_T53:
+	case MXT_TOUCH_MULTI_T9:
+	case MXT_TOUCH_KEYARRAY_T15:
+	case MXT_TOUCH_PROXIMITY_T23:
+	case MXT_TOUCH_PROXKEY_T52:
+	case MXT_PROCI_GRIPFACE_T20:
+	case MXT_PROCG_NOISE_T22:
+	case MXT_PROCI_ONETOUCH_T24:
+	case MXT_PROCI_TWOTOUCH_T27:
+	case MXT_PROCI_GRIP_T40:
+	case MXT_PROCI_PALM_T41:
+	case MXT_PROCI_TOUCHSUPPRESSION_T42:
+	case MXT_PROCI_STYLUS_T47:
+	case MXT_PROCG_NOISESUPPRESSION_T48:
+	case MXT_SPT_COMMSCONFIG_T18:
+	case MXT_SPT_GPIOPWM_T19:
+	case MXT_SPT_SELFTEST_T25:
+	case MXT_SPT_CTECONFIG_T28:
+	case MXT_SPT_USERDATA_T38:
+	case MXT_SPT_DIGITIZER_T43:
+	case MXT_SPT_CTECONFIG_T46:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool mxt_object_writable(unsigned int type)
+{
+	switch (type) {
+	case MXT_GEN_COMMAND_T6:
+	case MXT_GEN_POWER_T7:
+	case MXT_GEN_ACQUIRE_T8:
+	case MXT_TOUCH_MULTI_T9:
+	case MXT_TOUCH_KEYARRAY_T15:
+	case MXT_TOUCH_PROXIMITY_T23:
+	case MXT_TOUCH_PROXKEY_T52:
+	case MXT_PROCI_GRIPFACE_T20:
+	case MXT_PROCG_NOISE_T22:
+	case MXT_PROCI_ONETOUCH_T24:
+	case MXT_PROCI_TWOTOUCH_T27:
+	case MXT_PROCI_GRIP_T40:
+	case MXT_PROCI_PALM_T41:
+	case MXT_PROCI_TOUCHSUPPRESSION_T42:
+	case MXT_PROCI_STYLUS_T47:
+	case MXT_PROCG_NOISESUPPRESSION_T48:
+	case MXT_SPT_COMMSCONFIG_T18:
+	case MXT_SPT_GPIOPWM_T19:
+	case MXT_SPT_SELFTEST_T25:
+	case MXT_SPT_CTECONFIG_T28:
+	case MXT_SPT_DIGITIZER_T43:
+	case MXT_SPT_CTECONFIG_T46:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void mxt_dump_message(struct device *dev,
+				  struct mxt_message *message)
+{
+	dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
+	dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
+	dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
+	dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
+	dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
+	dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
+	dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
+	dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
+	dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
+}
+
+static int mxt_check_bootloader(struct i2c_client *client,
+				     unsigned int state)
+{
+	u8 val;
+
+recheck:
+	if (i2c_master_recv(client, &val, 1) != 1) {
+		dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+		return -EIO;
+	}
+
+	switch (state) {
+	case MXT_WAITING_BOOTLOAD_CMD:
+	case MXT_WAITING_FRAME_DATA:
+		val &= ~MXT_BOOT_STATUS_MASK;
+		break;
+	case MXT_FRAME_CRC_PASS:
+		if (val == MXT_FRAME_CRC_CHECK)
+			goto recheck;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (val != state) {
+		dev_err(&client->dev, "Unvalid bootloader mode state\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mxt_unlock_bootloader(struct i2c_client *client)
+{
+	u8 buf[2];
+
+	buf[0] = MXT_UNLOCK_CMD_LSB;
+	buf[1] = MXT_UNLOCK_CMD_MSB;
+
+	if (i2c_master_send(client, buf, 2) != 2) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mxt_fw_write(struct i2c_client *client,
+			     const u8 *data, unsigned int frame_size)
+{
+	if (i2c_master_send(client, data, frame_size) != frame_size) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int __mxt_read_reg(struct i2c_client *client,
+			       u16 reg, u16 len, void *val)
+{
+	struct i2c_msg xfer[2];
+	u8 buf[2];
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 2;
+	xfer[0].buf = buf;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = len;
+	xfer[1].buf = val;
+
+	if (i2c_transfer(client->adapter, xfer, 2) != 2) {
+		dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val)
+{
+	return __mxt_read_reg(client, reg, 1, val);
+}
+
+static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
+{
+	u8 buf[3];
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+	buf[2] = val;
+
+	if (i2c_master_send(client, buf, 3) != 3) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mxt_read_object_table(struct i2c_client *client,
+				      u16 reg, u8 *object_buf)
+{
+	return __mxt_read_reg(client, reg, MXT_OBJECT_SIZE,
+				   object_buf);
+}
+
+static struct mxt_object *
+mxt_get_object(struct mxt_data *data, u8 type)
+{
+	struct mxt_object *object;
+	int i;
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+		if (object->type == type)
+			return object;
+	}
+
+	dev_err(&data->client->dev, "Invalid object type\n");
+	return NULL;
+}
+
+static int mxt_read_message(struct mxt_data *data,
+				 struct mxt_message *message)
+{
+	struct mxt_object *object;
+	u16 reg;
+
+	object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return __mxt_read_reg(data->client, reg,
+			sizeof(struct mxt_message), message);
+}
+
+static int mxt_read_object(struct mxt_data *data,
+				u8 type, u8 offset, u8 *val)
+{
+	struct mxt_object *object;
+	u16 reg;
+
+	object = mxt_get_object(data, type);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return __mxt_read_reg(data->client, reg + offset, 1, val);
+}
+
+static int mxt_write_object(struct mxt_data *data,
+				 u8 type, u8 offset, u8 val)
+{
+	struct mxt_object *object;
+	u16 reg;
+
+	object = mxt_get_object(data, type);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return mxt_write_reg(data->client, reg + offset, val);
+}
+
+static void mxt_input_report(struct mxt_data *data, int single_id)
+{
+	struct mxt_finger *finger = data->finger;
+	struct input_dev *input_dev = data->input_dev;
+	int status = finger[single_id].status;
+	int finger_num = 0;
+	int id;
+
+	for (id = 0; id < MXT_MAX_FINGER; id++) {
+		if (!finger[id].status)
+			continue;
+
+		input_mt_slot(input_dev, id);
+		input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+				finger[id].status != MXT_RELEASE);
+
+		if (finger[id].status != MXT_RELEASE) {
+			finger_num++;
+			input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+					finger[id].area);
+			input_report_abs(input_dev, ABS_MT_POSITION_X,
+					finger[id].x);
+			input_report_abs(input_dev, ABS_MT_POSITION_Y,
+					finger[id].y);
+			input_report_abs(input_dev, ABS_MT_PRESSURE,
+					finger[id].pressure);
+		} else {
+			finger[id].status = 0;
+		}
+	}
+
+	input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
+
+	if (status != MXT_RELEASE) {
+		input_report_abs(input_dev, ABS_X, finger[single_id].x);
+		input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+		input_report_abs(input_dev,
+				 ABS_PRESSURE, finger[single_id].pressure);
+	}
+
+	input_sync(input_dev);
+}
+
+static void mxt_input_touchevent(struct mxt_data *data,
+				      struct mxt_message *message, int id)
+{
+	struct mxt_finger *finger = data->finger;
+	struct device *dev = &data->client->dev;
+	u8 status = message->message[0];
+	int x;
+	int y;
+	int area;
+	int pressure;
+
+	/* Check the touch is present on the screen */
+	if (!(status & MXT_DETECT)) {
+		if (status & MXT_RELEASE) {
+			dev_dbg(dev, "[%d] released\n", id);
+
+			finger[id].status = MXT_RELEASE;
+			mxt_input_report(data, id);
+		}
+		return;
+	}
+
+	/* Check only AMP detection */
+	if (!(status & (MXT_PRESS | MXT_MOVE)))
+		return;
+
+	x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
+	y = (message->message[2] << 4) | ((message->message[3] & 0xf));
+	if (data->max_x < 1024)
+		x = x >> 2;
+	if (data->max_y < 1024)
+		y = y >> 2;
+
+	area = message->message[4];
+	pressure = message->message[5];
+
+	dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
+		status & MXT_MOVE ? "moved" : "pressed",
+		x, y, area);
+
+	finger[id].status = status & MXT_MOVE ?
+				MXT_MOVE : MXT_PRESS;
+	finger[id].x = x;
+	finger[id].y = y;
+	finger[id].area = area;
+	finger[id].pressure = pressure;
+
+	mxt_input_report(data, id);
+}
+
+static irqreturn_t mxt_interrupt(int irq, void *dev_id)
+{
+	struct mxt_data *data = dev_id;
+	struct mxt_message message;
+	struct mxt_object *object;
+	struct device *dev = &data->client->dev;
+	int id;
+	u8 reportid;
+	u8 max_reportid;
+	u8 min_reportid;
+
+	do {
+		if (mxt_read_message(data, &message)) {
+			dev_err(dev, "Failed to read message\n");
+			goto end;
+		}
+
+		reportid = message.reportid;
+
+		/* whether reportid is thing of MXT_TOUCH_MULTI_T9 */
+		object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
+		if (!object)
+			goto end;
+
+		max_reportid = object->max_reportid;
+		min_reportid = max_reportid - object->num_report_ids + 1;
+		id = reportid - min_reportid;
+
+		if (reportid >= min_reportid && reportid <= max_reportid)
+			mxt_input_touchevent(data, &message, id);
+		else
+			mxt_dump_message(dev, &message);
+	} while (reportid != 0xff);
+
+end:
+	return IRQ_HANDLED;
+}
+
+static int mxt_check_reg_init(struct mxt_data *data)
+{
+	const struct mxt_platform_data *pdata = data->pdata;
+	struct mxt_object *object;
+	struct device *dev = &data->client->dev;
+	int index = 0;
+	int i, j, config_offset;
+
+	if (!pdata->config) {
+		dev_dbg(dev, "No cfg data defined, skipping reg init\n");
+		return 0;
+	}
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+
+		if (!mxt_object_writable(object->type))
+			continue;
+
+		for (j = 0;
+		     j < (object->size + 1) * (object->instances + 1);
+		     j++) {
+			config_offset = index + j;
+			if (config_offset > pdata->config_length) {
+				dev_err(dev, "Not enough config data!\n");
+				return -EINVAL;
+			}
+			mxt_write_object(data, object->type, j,
+					 pdata->config[config_offset]);
+		}
+		index += (object->size + 1) * (object->instances + 1);
+	}
+
+	return 0;
+}
+
+static int mxt_make_highchg(struct mxt_data *data)
+{
+	struct device *dev = &data->client->dev;
+	struct mxt_message message;
+	int count = 10;
+	int error;
+
+	/* Read dummy message to make high CHG pin */
+	do {
+		error = mxt_read_message(data, &message);
+		if (error)
+			return error;
+	} while (message.reportid != 0xff && --count);
+
+	if (!count) {
+		dev_err(dev, "CHG pin isn't cleared\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void mxt_handle_pdata(struct mxt_data *data)
+{
+	const struct mxt_platform_data *pdata = data->pdata;
+	u8 voltage;
+
+	/* Set touchscreen lines */
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE,
+			pdata->x_line);
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE,
+			pdata->y_line);
+
+	/* Set touchscreen orient */
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT,
+			pdata->orient);
+
+	/* Set touchscreen burst length */
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
+			MXT_TOUCH_BLEN, pdata->blen);
+
+	/* Set touchscreen threshold */
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
+			MXT_TOUCH_TCHTHR, pdata->threshold);
+
+	/* Set touchscreen resolution */
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
+			MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
+			MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
+			MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
+	mxt_write_object(data, MXT_TOUCH_MULTI_T9,
+			MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
+
+	/* Set touchscreen voltage */
+	if (pdata->voltage) {
+		if (pdata->voltage < MXT_VOLTAGE_DEFAULT) {
+			voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) /
+				MXT_VOLTAGE_STEP;
+			voltage = 0xff - voltage + 1;
+		} else
+			voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) /
+				MXT_VOLTAGE_STEP;
+
+		mxt_write_object(data, MXT_SPT_CTECONFIG_T28,
+				MXT_CTE_VOLTAGE, voltage);
+	}
+}
+
+static int mxt_get_info(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct mxt_info *info = &data->info;
+	int error;
+	u8 val;
+
+	error = mxt_read_reg(client, MXT_FAMILY_ID, &val);
+	if (error)
+		return error;
+	info->family_id = val;
+
+	error = mxt_read_reg(client, MXT_VARIANT_ID, &val);
+	if (error)
+		return error;
+	info->variant_id = val;
+
+	error = mxt_read_reg(client, MXT_VERSION, &val);
+	if (error)
+		return error;
+	info->version = val;
+
+	error = mxt_read_reg(client, MXT_BUILD, &val);
+	if (error)
+		return error;
+	info->build = val;
+
+	error = mxt_read_reg(client, MXT_OBJECT_NUM, &val);
+	if (error)
+		return error;
+	info->object_num = val;
+
+	return 0;
+}
+
+static int mxt_get_object_table(struct mxt_data *data)
+{
+	int error;
+	int i;
+	u16 reg;
+	u8 reportid = 0;
+	u8 buf[MXT_OBJECT_SIZE];
+
+	for (i = 0; i < data->info.object_num; i++) {
+		struct mxt_object *object = data->object_table + i;
+
+		reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i;
+		error = mxt_read_object_table(data->client, reg, buf);
+		if (error)
+			return error;
+
+		object->type = buf[0];
+		object->start_address = (buf[2] << 8) | buf[1];
+		object->size = buf[3];
+		object->instances = buf[4];
+		object->num_report_ids = buf[5];
+
+		if (object->num_report_ids) {
+			reportid += object->num_report_ids *
+					(object->instances + 1);
+			object->max_reportid = reportid;
+		}
+	}
+
+	return 0;
+}
+
+static int mxt_initialize(struct mxt_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct mxt_info *info = &data->info;
+	int error;
+	u8 val;
+
+	error = mxt_get_info(data);
+	if (error)
+		return error;
+
+	data->object_table = kcalloc(info->object_num,
+				     sizeof(struct mxt_object),
+				     GFP_KERNEL);
+	if (!data->object_table) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	/* Get object table information */
+	error = mxt_get_object_table(data);
+	if (error)
+		return error;
+
+	/* Check register init values */
+	error = mxt_check_reg_init(data);
+	if (error)
+		return error;
+
+	mxt_handle_pdata(data);
+
+	/* Backup to memory */
+	mxt_write_object(data, MXT_GEN_COMMAND_T6,
+			MXT_COMMAND_BACKUPNV,
+			MXT_BACKUP_VALUE);
+	msleep(MXT_BACKUP_TIME);
+
+	/* Soft reset */
+	mxt_write_object(data, MXT_GEN_COMMAND_T6,
+			MXT_COMMAND_RESET, 1);
+	msleep(MXT_RESET_TIME);
+
+	/* Update matrix size at info struct */
+	error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val);
+	if (error)
+		return error;
+	info->matrix_xsize = val;
+
+	error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val);
+	if (error)
+		return error;
+	info->matrix_ysize = val;
+
+	dev_info(&client->dev,
+			"Family ID: %d Variant ID: %d Version: %d Build: %d\n",
+			info->family_id, info->variant_id, info->version,
+			info->build);
+
+	dev_info(&client->dev,
+			"Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
+			info->matrix_xsize, info->matrix_ysize,
+			info->object_num);
+
+	return 0;
+}
+
+static void mxt_calc_resolution(struct mxt_data *data)
+{
+	unsigned int max_x = data->pdata->x_size - 1;
+	unsigned int max_y = data->pdata->y_size - 1;
+
+	if (data->pdata->orient & MXT_XY_SWITCH) {
+		data->max_x = max_y;
+		data->max_y = max_x;
+	} else {
+		data->max_x = max_x;
+		data->max_y = max_y;
+	}
+}
+
+static ssize_t mxt_object_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	struct mxt_object *object;
+	int count = 0;
+	int i, j;
+	int error;
+	u8 val;
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+
+		count += snprintf(buf + count, PAGE_SIZE - count,
+				"Object[%d] (Type %d)\n",
+				i + 1, object->type);
+		if (count >= PAGE_SIZE)
+			return PAGE_SIZE - 1;
+
+		if (!mxt_object_readable(object->type)) {
+			count += snprintf(buf + count, PAGE_SIZE - count,
+					"\n");
+			if (count >= PAGE_SIZE)
+				return PAGE_SIZE - 1;
+			continue;
+		}
+
+		for (j = 0; j < object->size + 1; j++) {
+			error = mxt_read_object(data,
+						object->type, j, &val);
+			if (error)
+				return error;
+
+			count += snprintf(buf + count, PAGE_SIZE - count,
+					"\t[%2d]: %02x (%d)\n", j, val, val);
+			if (count >= PAGE_SIZE)
+				return PAGE_SIZE - 1;
+		}
+
+		count += snprintf(buf + count, PAGE_SIZE - count, "\n");
+		if (count >= PAGE_SIZE)
+			return PAGE_SIZE - 1;
+	}
+
+	return count;
+}
+
+static int mxt_load_fw(struct device *dev, const char *fn)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	const struct firmware *fw = NULL;
+	unsigned int frame_size;
+	unsigned int pos = 0;
+	int ret;
+
+	ret = request_firmware(&fw, fn, dev);
+	if (ret) {
+		dev_err(dev, "Unable to open firmware %s\n", fn);
+		return ret;
+	}
+
+	/* Change to the bootloader mode */
+	mxt_write_object(data, MXT_GEN_COMMAND_T6,
+			MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+	msleep(MXT_RESET_TIME);
+
+	/* Change to slave address of bootloader */
+	if (client->addr == MXT_APP_LOW)
+		client->addr = MXT_BOOT_LOW;
+	else
+		client->addr = MXT_BOOT_HIGH;
+
+	ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
+	if (ret)
+		goto out;
+
+	/* Unlock bootloader */
+	mxt_unlock_bootloader(client);
+
+	while (pos < fw->size) {
+		ret = mxt_check_bootloader(client,
+						MXT_WAITING_FRAME_DATA);
+		if (ret)
+			goto out;
+
+		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+
+		/* We should add 2 at frame size as the the firmware data is not
+		 * included the CRC bytes.
+		 */
+		frame_size += 2;
+
+		/* Write one frame to device */
+		mxt_fw_write(client, fw->data + pos, frame_size);
+
+		ret = mxt_check_bootloader(client,
+						MXT_FRAME_CRC_PASS);
+		if (ret)
+			goto out;
+
+		pos += frame_size;
+
+		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+	}
+
+out:
+	release_firmware(fw);
+
+	/* Change to slave address of application */
+	if (client->addr == MXT_BOOT_LOW)
+		client->addr = MXT_APP_LOW;
+	else
+		client->addr = MXT_APP_HIGH;
+
+	return ret;
+}
+
+static ssize_t mxt_update_fw_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct mxt_data *data = dev_get_drvdata(dev);
+	int error;
+
+	disable_irq(data->irq);
+
+	error = mxt_load_fw(dev, MXT_FW_NAME);
+	if (error) {
+		dev_err(dev, "The firmware update failed(%d)\n", error);
+		count = error;
+	} else {
+		dev_dbg(dev, "The firmware update succeeded\n");
+
+		/* Wait for reset */
+		msleep(MXT_FWRESET_TIME);
+
+		kfree(data->object_table);
+		data->object_table = NULL;
+
+		mxt_initialize(data);
+	}
+
+	enable_irq(data->irq);
+
+	error = mxt_make_highchg(data);
+	if (error)
+		return error;
+
+	return count;
+}
+
+static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
+static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
+
+static struct attribute *mxt_attrs[] = {
+	&dev_attr_object.attr,
+	&dev_attr_update_fw.attr,
+	NULL
+};
+
+static const struct attribute_group mxt_attr_group = {
+	.attrs = mxt_attrs,
+};
+
+static void mxt_start(struct mxt_data *data)
+{
+	/* Touch enable */
+	mxt_write_object(data,
+			MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83);
+}
+
+static void mxt_stop(struct mxt_data *data)
+{
+	/* Touch disable */
+	mxt_write_object(data,
+			MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
+}
+
+static int mxt_input_open(struct input_dev *dev)
+{
+	struct mxt_data *data = input_get_drvdata(dev);
+
+	mxt_start(data);
+
+	return 0;
+}
+
+static void mxt_input_close(struct input_dev *dev)
+{
+	struct mxt_data *data = input_get_drvdata(dev);
+
+	mxt_stop(data);
+}
+
+static int __devinit mxt_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	const struct mxt_platform_data *pdata = client->dev.platform_data;
+	struct mxt_data *data;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!pdata)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	input_dev->name = "Atmel maXTouch Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+	input_dev->open = mxt_input_open;
+	input_dev->close = mxt_input_close;
+
+	data->client = client;
+	data->input_dev = input_dev;
+	data->pdata = pdata;
+	data->irq = client->irq;
+
+	mxt_calc_resolution(data);
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	/* For single touch */
+	input_set_abs_params(input_dev, ABS_X,
+			     0, data->max_x, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			     0, data->max_y, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE,
+			     0, 255, 0, 0);
+
+	/* For multi touch */
+	input_mt_init_slots(input_dev, MXT_MAX_FINGER);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+			     0, MXT_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+			     0, data->max_x, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+			     0, data->max_y, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+			     0, 255, 0, 0);
+
+	input_set_drvdata(input_dev, data);
+	i2c_set_clientdata(client, data);
+
+	error = mxt_initialize(data);
+	if (error)
+		goto err_free_object;
+
+	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
+			pdata->irqflags, client->dev.driver->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_object;
+	}
+
+	error = mxt_make_highchg(data);
+	if (error)
+		goto err_free_irq;
+
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_irq;
+
+	error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
+	if (error)
+		goto err_unregister_device;
+
+	return 0;
+
+err_unregister_device:
+	input_unregister_device(input_dev);
+	input_dev = NULL;
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_object:
+	kfree(data->object_table);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+	return error;
+}
+
+static int __devexit mxt_remove(struct i2c_client *client)
+{
+	struct mxt_data *data = i2c_get_clientdata(client);
+
+	sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
+	free_irq(data->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data->object_table);
+	kfree(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxt_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mxt_data *data = i2c_get_clientdata(client);
+	struct input_dev *input_dev = data->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		mxt_stop(data);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static int mxt_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mxt_data *data = i2c_get_clientdata(client);
+	struct input_dev *input_dev = data->input_dev;
+
+	/* Soft reset */
+	mxt_write_object(data, MXT_GEN_COMMAND_T6,
+			MXT_COMMAND_RESET, 1);
+
+	msleep(MXT_RESET_TIME);
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		mxt_start(data);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static const struct dev_pm_ops mxt_pm_ops = {
+	.suspend	= mxt_suspend,
+	.resume		= mxt_resume,
+};
+#endif
+
+static const struct i2c_device_id mxt_id[] = {
+	{ "qt602240_ts", 0 },
+	{ "atmel_mxt_ts", 0 },
+	{ "mXT224", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mxt_id);
+
+static struct i2c_driver mxt_driver = {
+	.driver = {
+		.name	= "atmel_mxt_ts",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &mxt_pm_ops,
+#endif
+	},
+	.probe		= mxt_probe,
+	.remove		= __devexit_p(mxt_remove),
+	.id_table	= mxt_id,
+};
+
+module_i2c_driver(mxt_driver);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel_tsadcc.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel_tsadcc.c
new file mode 100644
index 0000000..201b2d2
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/atmel_tsadcc.c
@@ -0,0 +1,359 @@
+/*
+ *  Atmel Touch Screen Driver
+ *
+ *  Copyright (c) 2008 ATMEL
+ *  Copyright (c) 2008 Dan Liang
+ *  Copyright (c) 2008 TimeSys Corporation
+ *  Copyright (c) 2008 Justin Waters
+ *
+ *  Based on touchscreen code from Atmel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/board.h>
+#include <mach/cpu.h>
+
+/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
+
+#define ATMEL_TSADCC_CR		0x00	/* Control register */
+#define   ATMEL_TSADCC_SWRST	(1 << 0)	/* Software Reset*/
+#define	  ATMEL_TSADCC_START	(1 << 1)	/* Start conversion */
+
+#define ATMEL_TSADCC_MR		0x04	/* Mode register */
+#define	  ATMEL_TSADCC_TSAMOD	(3    <<  0)	/* ADC mode */
+#define	    ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE	(0x0)	/* ADC Mode */
+#define	    ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE	(0x1)	/* Touch Screen Only Mode */
+#define	  ATMEL_TSADCC_LOWRES	(1    <<  4)	/* Resolution selection */
+#define	  ATMEL_TSADCC_SLEEP	(1    <<  5)	/* Sleep mode */
+#define	  ATMEL_TSADCC_PENDET	(1    <<  6)	/* Pen Detect selection */
+#define	  ATMEL_TSADCC_PRES	(1    <<  7)	/* Pressure Measurement Selection */
+#define	  ATMEL_TSADCC_PRESCAL	(0x3f <<  8)	/* Prescalar Rate Selection */
+#define	  ATMEL_TSADCC_EPRESCAL	(0xff <<  8)	/* Prescalar Rate Selection (Extended) */
+#define	  ATMEL_TSADCC_STARTUP	(0x7f << 16)	/* Start Up time */
+#define	  ATMEL_TSADCC_SHTIM	(0xf  << 24)	/* Sample & Hold time */
+#define	  ATMEL_TSADCC_PENDBC	(0xf  << 28)	/* Pen Detect debouncing time */
+
+#define ATMEL_TSADCC_TRGR	0x08	/* Trigger register */
+#define	  ATMEL_TSADCC_TRGMOD	(7      <<  0)	/* Trigger mode */
+#define	    ATMEL_TSADCC_TRGMOD_NONE		(0 << 0)
+#define     ATMEL_TSADCC_TRGMOD_EXT_RISING	(1 << 0)
+#define     ATMEL_TSADCC_TRGMOD_EXT_FALLING	(2 << 0)
+#define     ATMEL_TSADCC_TRGMOD_EXT_ANY		(3 << 0)
+#define     ATMEL_TSADCC_TRGMOD_PENDET		(4 << 0)
+#define     ATMEL_TSADCC_TRGMOD_PERIOD		(5 << 0)
+#define     ATMEL_TSADCC_TRGMOD_CONTINUOUS	(6 << 0)
+#define   ATMEL_TSADCC_TRGPER	(0xffff << 16)	/* Trigger period */
+
+#define ATMEL_TSADCC_TSR	0x0C	/* Touch Screen register */
+#define	  ATMEL_TSADCC_TSFREQ	(0xf <<  0)	/* TS Frequency in Interleaved mode */
+#define	  ATMEL_TSADCC_TSSHTIM	(0xf << 24)	/* Sample & Hold time */
+
+#define ATMEL_TSADCC_CHER	0x10	/* Channel Enable register */
+#define ATMEL_TSADCC_CHDR	0x14	/* Channel Disable register */
+#define ATMEL_TSADCC_CHSR	0x18	/* Channel Status register */
+#define	  ATMEL_TSADCC_CH(n)	(1 << (n))	/* Channel number */
+
+#define ATMEL_TSADCC_SR		0x1C	/* Status register */
+#define	  ATMEL_TSADCC_EOC(n)	(1 << ((n)+0))	/* End of conversion for channel N */
+#define	  ATMEL_TSADCC_OVRE(n)	(1 << ((n)+8))	/* Overrun error for channel N */
+#define	  ATMEL_TSADCC_DRDY	(1 << 16)	/* Data Ready */
+#define	  ATMEL_TSADCC_GOVRE	(1 << 17)	/* General Overrun Error */
+#define	  ATMEL_TSADCC_ENDRX	(1 << 18)	/* End of RX Buffer */
+#define	  ATMEL_TSADCC_RXBUFF	(1 << 19)	/* TX Buffer full */
+#define	  ATMEL_TSADCC_PENCNT	(1 << 20)	/* Pen contact */
+#define	  ATMEL_TSADCC_NOCNT	(1 << 21)	/* No contact */
+
+#define ATMEL_TSADCC_LCDR	0x20	/* Last Converted Data register */
+#define	  ATMEL_TSADCC_DATA	(0x3ff << 0)	/* Channel data */
+
+#define ATMEL_TSADCC_IER	0x24	/* Interrupt Enable register */
+#define ATMEL_TSADCC_IDR	0x28	/* Interrupt Disable register */
+#define ATMEL_TSADCC_IMR	0x2C	/* Interrupt Mask register */
+#define ATMEL_TSADCC_CDR0	0x30	/* Channel Data 0 */
+#define ATMEL_TSADCC_CDR1	0x34	/* Channel Data 1 */
+#define ATMEL_TSADCC_CDR2	0x38	/* Channel Data 2 */
+#define ATMEL_TSADCC_CDR3	0x3C	/* Channel Data 3 */
+#define ATMEL_TSADCC_CDR4	0x40	/* Channel Data 4 */
+#define ATMEL_TSADCC_CDR5	0x44	/* Channel Data 5 */
+
+#define ATMEL_TSADCC_XPOS	0x50
+#define ATMEL_TSADCC_Z1DAT	0x54
+#define ATMEL_TSADCC_Z2DAT	0x58
+
+#define PRESCALER_VAL(x)	((x) >> 8)
+
+#define ADC_DEFAULT_CLOCK	100000
+
+struct atmel_tsadcc {
+	struct input_dev	*input;
+	char			phys[32];
+	struct clk		*clk;
+	int			irq;
+	unsigned int		prev_absx;
+	unsigned int		prev_absy;
+	unsigned char		bufferedmeasure;
+};
+
+static void __iomem		*tsc_base;
+
+#define atmel_tsadcc_read(reg)		__raw_readl(tsc_base + (reg))
+#define atmel_tsadcc_write(reg, val)	__raw_writel((val), tsc_base + (reg))
+
+static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+{
+	struct atmel_tsadcc	*ts_dev = (struct atmel_tsadcc *)dev;
+	struct input_dev	*input_dev = ts_dev->input;
+
+	unsigned int status;
+	unsigned int reg;
+
+	status = atmel_tsadcc_read(ATMEL_TSADCC_SR);
+	status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR);
+
+	if (status & ATMEL_TSADCC_NOCNT) {
+		/* Contact lost */
+		reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
+
+		atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
+		atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
+		atmel_tsadcc_write(ATMEL_TSADCC_IDR,
+				   ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
+		atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
+		input_report_key(input_dev, BTN_TOUCH, 0);
+		ts_dev->bufferedmeasure = 0;
+		input_sync(input_dev);
+
+	} else if (status & ATMEL_TSADCC_PENCNT) {
+		/* Pen detected */
+		reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
+		reg &= ~ATMEL_TSADCC_PENDBC;
+
+		atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
+		atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
+		atmel_tsadcc_write(ATMEL_TSADCC_IER,
+				   ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
+		atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
+				   ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
+
+	} else if (status & ATMEL_TSADCC_EOC(3)) {
+		/* Conversion finished */
+
+		if (ts_dev->bufferedmeasure) {
+			/* Last measurement is always discarded, since it can
+			 * be erroneous.
+			 * Always report previous measurement */
+			input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+			input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+			input_report_key(input_dev, BTN_TOUCH, 1);
+			input_sync(input_dev);
+		} else
+			ts_dev->bufferedmeasure = 1;
+
+		/* Now make new measurement */
+		ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
+		ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
+
+		ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
+		ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+{
+	struct atmel_tsadcc	*ts_dev;
+	struct input_dev	*input_dev;
+	struct resource		*res;
+	struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
+	int		err = 0;
+	unsigned int	prsc;
+	unsigned int	reg;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no mmio resource defined.\n");
+		return -ENXIO;
+	}
+
+	/* Allocate memory for device */
+	ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL);
+	if (!ts_dev) {
+		dev_err(&pdev->dev, "failed to allocate memory.\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, ts_dev);
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(&pdev->dev, "failed to allocate input device.\n");
+		err = -EBUSY;
+		goto err_free_mem;
+	}
+
+	ts_dev->irq = platform_get_irq(pdev, 0);
+	if (ts_dev->irq < 0) {
+		dev_err(&pdev->dev, "no irq ID is designated.\n");
+		err = -ENODEV;
+		goto err_free_dev;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res),
+				"atmel tsadcc regs")) {
+		dev_err(&pdev->dev, "resources is unavailable.\n");
+		err = -EBUSY;
+		goto err_free_dev;
+	}
+
+	tsc_base = ioremap(res->start, resource_size(res));
+	if (!tsc_base) {
+		dev_err(&pdev->dev, "failed to map registers.\n");
+		err = -ENOMEM;
+		goto err_release_mem;
+	}
+
+	err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0,
+			pdev->dev.driver->name, ts_dev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to allocate irq.\n");
+		goto err_unmap_regs;
+	}
+
+	ts_dev->clk = clk_get(&pdev->dev, "tsc_clk");
+	if (IS_ERR(ts_dev->clk)) {
+		dev_err(&pdev->dev, "failed to get ts_clk\n");
+		err = PTR_ERR(ts_dev->clk);
+		goto err_free_irq;
+	}
+
+	ts_dev->input = input_dev;
+	ts_dev->bufferedmeasure = 0;
+
+	snprintf(ts_dev->phys, sizeof(ts_dev->phys),
+		 "%s/input0", dev_name(&pdev->dev));
+
+	input_dev->name = "atmel touch screen controller";
+	input_dev->phys = ts_dev->phys;
+	input_dev->dev.parent = &pdev->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);
+
+	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+
+	/* clk_enable() always returns 0, no need to check it */
+	clk_enable(ts_dev->clk);
+
+	prsc = clk_get_rate(ts_dev->clk);
+	dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
+
+	if (!pdata)
+		goto err_fail;
+
+	if (!pdata->adc_clock)
+		pdata->adc_clock = ADC_DEFAULT_CLOCK;
+
+	prsc = (prsc / (2 * pdata->adc_clock)) - 1;
+
+	/* saturate if this value is too high */
+	if (cpu_is_at91sam9rl()) {
+		if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL))
+			prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL);
+	} else {
+		if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL))
+			prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL);
+	}
+
+	dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
+
+	reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE		|
+		((0x00 << 5) & ATMEL_TSADCC_SLEEP)	|	/* Normal Mode */
+		((0x01 << 6) & ATMEL_TSADCC_PENDET)	|	/* Enable Pen Detect */
+		(prsc << 8)				|
+		((0x26 << 16) & ATMEL_TSADCC_STARTUP)	|
+		((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
+
+	atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
+	atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
+	atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
+	atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+		(pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
+
+	atmel_tsadcc_read(ATMEL_TSADCC_SR);
+	atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
+	/* All went ok, so register to the input system */
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_fail;
+
+	return 0;
+
+err_fail:
+	clk_disable(ts_dev->clk);
+	clk_put(ts_dev->clk);
+err_free_irq:
+	free_irq(ts_dev->irq, ts_dev);
+err_unmap_regs:
+	iounmap(tsc_base);
+err_release_mem:
+	release_mem_region(res->start, resource_size(res));
+err_free_dev:
+	input_free_device(input_dev);
+err_free_mem:
+	kfree(ts_dev);
+	return err;
+}
+
+static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
+{
+	struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev);
+	struct resource *res;
+
+	free_irq(ts_dev->irq, ts_dev);
+
+	input_unregister_device(ts_dev->input);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap(tsc_base);
+	release_mem_region(res->start, resource_size(res));
+
+	clk_disable(ts_dev->clk);
+	clk_put(ts_dev->clk);
+
+	kfree(ts_dev);
+
+	return 0;
+}
+
+static struct platform_driver atmel_tsadcc_driver = {
+	.probe		= atmel_tsadcc_probe,
+	.remove		= __devexit_p(atmel_tsadcc_remove),
+	.driver		= {
+		.name	= "atmel_tsadcc",
+	},
+};
+module_platform_driver(atmel_tsadcc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atmel TouchScreen Driver");
+MODULE_AUTHOR("Dan Liang <dan.liang@atmel.com>");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/auo-pixcir-ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/auo-pixcir-ts.c
new file mode 100644
index 0000000..c7047b6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -0,0 +1,642 @@
+/*
+ * Driver for AUO in-cell touchscreens
+ *
+ * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de>
+ *
+ * loosely based on auo_touch.c from Dell Streak vendor-kernel
+ *
+ * Copyright (c) 2008 QUALCOMM Incorporated.
+ * Copyright (c) 2008 QUALCOMM USA, INC.
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input/auo-pixcir-ts.h>
+
+/*
+ * Coordinate calculation:
+ * X1 = X1_LSB + X1_MSB*256
+ * Y1 = Y1_LSB + Y1_MSB*256
+ * X2 = X2_LSB + X2_MSB*256
+ * Y2 = Y2_LSB + Y2_MSB*256
+ */
+#define AUO_PIXCIR_REG_X1_LSB		0x00
+#define AUO_PIXCIR_REG_X1_MSB		0x01
+#define AUO_PIXCIR_REG_Y1_LSB		0x02
+#define AUO_PIXCIR_REG_Y1_MSB		0x03
+#define AUO_PIXCIR_REG_X2_LSB		0x04
+#define AUO_PIXCIR_REG_X2_MSB		0x05
+#define AUO_PIXCIR_REG_Y2_LSB		0x06
+#define AUO_PIXCIR_REG_Y2_MSB		0x07
+
+#define AUO_PIXCIR_REG_STRENGTH		0x0d
+#define AUO_PIXCIR_REG_STRENGTH_X1_LSB	0x0e
+#define AUO_PIXCIR_REG_STRENGTH_X1_MSB	0x0f
+
+#define AUO_PIXCIR_REG_RAW_DATA_X	0x2b
+#define AUO_PIXCIR_REG_RAW_DATA_Y	0x4f
+
+#define AUO_PIXCIR_REG_X_SENSITIVITY	0x6f
+#define AUO_PIXCIR_REG_Y_SENSITIVITY	0x70
+#define AUO_PIXCIR_REG_INT_SETTING	0x71
+#define AUO_PIXCIR_REG_INT_WIDTH	0x72
+#define AUO_PIXCIR_REG_POWER_MODE	0x73
+
+#define AUO_PIXCIR_REG_VERSION		0x77
+#define AUO_PIXCIR_REG_CALIBRATE	0x78
+
+#define AUO_PIXCIR_REG_TOUCHAREA_X1	0x1e
+#define AUO_PIXCIR_REG_TOUCHAREA_Y1	0x1f
+#define AUO_PIXCIR_REG_TOUCHAREA_X2	0x20
+#define AUO_PIXCIR_REG_TOUCHAREA_Y2	0x21
+
+#define AUO_PIXCIR_REG_EEPROM_CALIB_X	0x42
+#define AUO_PIXCIR_REG_EEPROM_CALIB_Y	0xad
+
+#define AUO_PIXCIR_INT_TPNUM_MASK	0xe0
+#define AUO_PIXCIR_INT_TPNUM_SHIFT	5
+#define AUO_PIXCIR_INT_RELEASE		(1 << 4)
+#define AUO_PIXCIR_INT_ENABLE		(1 << 3)
+#define AUO_PIXCIR_INT_POL_HIGH		(1 << 2)
+#define AUO_PIXCIR_INT_MODE_MASK	0x03
+
+/*
+ * Power modes:
+ * active:	scan speed 60Hz
+ * sleep:	scan speed 10Hz can be auto-activated, wakeup on 1st touch
+ * deep sleep:	scan speed 1Hz can only be entered or left manually.
+ */
+#define AUO_PIXCIR_POWER_ACTIVE		0x00
+#define AUO_PIXCIR_POWER_SLEEP		0x01
+#define AUO_PIXCIR_POWER_DEEP_SLEEP	0x02
+#define AUO_PIXCIR_POWER_MASK		0x03
+
+#define AUO_PIXCIR_POWER_ALLOW_SLEEP	(1 << 2)
+#define AUO_PIXCIR_POWER_IDLE_TIME(ms)	((ms & 0xf) << 4)
+
+#define AUO_PIXCIR_CALIBRATE		0x03
+
+#define AUO_PIXCIR_EEPROM_CALIB_X_LEN	62
+#define AUO_PIXCIR_EEPROM_CALIB_Y_LEN	36
+
+#define AUO_PIXCIR_RAW_DATA_X_LEN	18
+#define AUO_PIXCIR_RAW_DATA_Y_LEN	11
+
+#define AUO_PIXCIR_STRENGTH_ENABLE	(1 << 0)
+
+/* Touchscreen absolute values */
+#define AUO_PIXCIR_REPORT_POINTS	2
+#define AUO_PIXCIR_MAX_AREA		0xff
+#define AUO_PIXCIR_PENUP_TIMEOUT_MS	10
+
+struct auo_pixcir_ts {
+	struct i2c_client	*client;
+	struct input_dev	*input;
+	char			phys[32];
+
+	/* special handling for touch_indicate interupt mode */
+	bool			touch_ind_mode;
+
+	wait_queue_head_t	wait;
+	bool			stopped;
+};
+
+struct auo_point_t {
+	int	coord_x;
+	int	coord_y;
+	int	area_major;
+	int	area_minor;
+	int	orientation;
+};
+
+static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts,
+				   struct auo_point_t *point)
+{
+	struct i2c_client *client = ts->client;
+	const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	uint8_t raw_coord[8];
+	uint8_t raw_area[4];
+	int i, ret;
+
+	/* touch coordinates */
+	ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_X1_LSB,
+					    8, raw_coord);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to read coordinate, %d\n", ret);
+		return ret;
+	}
+
+	/* touch area */
+	ret = i2c_smbus_read_i2c_block_data(client, AUO_PIXCIR_REG_TOUCHAREA_X1,
+					    4, raw_area);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not read touch area, %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
+		point[i].coord_x =
+			raw_coord[4 * i + 1] << 8 | raw_coord[4 * i];
+		point[i].coord_y =
+			raw_coord[4 * i + 3] << 8 | raw_coord[4 * i + 2];
+
+		if (point[i].coord_x > pdata->x_max ||
+		    point[i].coord_y > pdata->y_max) {
+			dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
+				point[i].coord_x, point[i].coord_y);
+			point[i].coord_x = point[i].coord_y = 0;
+		}
+
+		/* determine touch major, minor and orientation */
+		point[i].area_major = max(raw_area[2 * i], raw_area[2 * i + 1]);
+		point[i].area_minor = min(raw_area[2 * i], raw_area[2 * i + 1]);
+		point[i].orientation = raw_area[2 * i] > raw_area[2 * i + 1];
+	}
+
+	return 0;
+}
+
+static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id)
+{
+	struct auo_pixcir_ts *ts = dev_id;
+	struct i2c_client *client = ts->client;
+	const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS];
+	int i;
+	int ret;
+	int fingers = 0;
+	int abs = -1;
+
+	while (!ts->stopped) {
+
+		/* check for up event in touch touch_ind_mode */
+		if (ts->touch_ind_mode) {
+			if (gpio_get_value(pdata->gpio_int) == 0) {
+				input_mt_sync(ts->input);
+				input_report_key(ts->input, BTN_TOUCH, 0);
+				input_sync(ts->input);
+				break;
+			}
+		}
+
+		ret = auo_pixcir_collect_data(ts, point);
+		if (ret < 0) {
+			/* we want to loop only in touch_ind_mode */
+			if (!ts->touch_ind_mode)
+				break;
+
+			wait_event_timeout(ts->wait, ts->stopped,
+				msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
+			continue;
+		}
+
+		for (i = 0; i < AUO_PIXCIR_REPORT_POINTS; i++) {
+			if (point[i].coord_x > 0 || point[i].coord_y > 0) {
+				input_report_abs(ts->input, ABS_MT_POSITION_X,
+						 point[i].coord_x);
+				input_report_abs(ts->input, ABS_MT_POSITION_Y,
+						 point[i].coord_y);
+				input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+						 point[i].area_major);
+				input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
+						 point[i].area_minor);
+				input_report_abs(ts->input, ABS_MT_ORIENTATION,
+						 point[i].orientation);
+				input_mt_sync(ts->input);
+
+				/* use first finger as source for singletouch */
+				if (fingers == 0)
+					abs = i;
+
+				/* number of touch points could also be queried
+				 * via i2c but would require an additional call
+				 */
+				fingers++;
+			}
+		}
+
+		input_report_key(ts->input, BTN_TOUCH, fingers > 0);
+
+		if (abs > -1) {
+			input_report_abs(ts->input, ABS_X, point[abs].coord_x);
+			input_report_abs(ts->input, ABS_Y, point[abs].coord_y);
+		}
+
+		input_sync(ts->input);
+
+		/* we want to loop only in touch_ind_mode */
+		if (!ts->touch_ind_mode)
+			break;
+
+		wait_event_timeout(ts->wait, ts->stopped,
+				 msecs_to_jiffies(AUO_PIXCIR_PENUP_TIMEOUT_MS));
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Set the power mode of the device.
+ * Valid modes are
+ * - AUO_PIXCIR_POWER_ACTIVE
+ * - AUO_PIXCIR_POWER_SLEEP - automatically left on first touch
+ * - AUO_PIXCIR_POWER_DEEP_SLEEP
+ */
+static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_POWER_MODE);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to read reg %Xh, %d\n",
+			AUO_PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	ret &= ~AUO_PIXCIR_POWER_MASK;
+	ret |= mode;
+
+	ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_POWER_MODE, ret);
+	if (ret) {
+		dev_err(&client->dev, "unable to write reg %Xh, %d\n",
+			AUO_PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static __devinit int auo_pixcir_int_config(struct auo_pixcir_ts *ts,
+					   int int_setting)
+{
+	struct i2c_client *client = ts->client;
+	struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to read reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		return ret;
+	}
+
+	ret &= ~AUO_PIXCIR_INT_MODE_MASK;
+	ret |= int_setting;
+	ret |= AUO_PIXCIR_INT_POL_HIGH; /* always use high for interrupts */
+
+	ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
+					ret);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to write reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		return ret;
+	}
+
+	ts->touch_ind_mode = pdata->int_setting == AUO_PIXCIR_INT_TOUCH_IND;
+
+	return 0;
+}
+
+/* control the generation of interrupts on the device side */
+static int auo_pixcir_int_toggle(struct auo_pixcir_ts *ts, bool enable)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to read reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		return ret;
+	}
+
+	if (enable)
+		ret |= AUO_PIXCIR_INT_ENABLE;
+	else
+		ret &= ~AUO_PIXCIR_INT_ENABLE;
+
+	ret = i2c_smbus_write_byte_data(client, AUO_PIXCIR_REG_INT_SETTING,
+					ret);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to write reg %Xh, %d\n",
+			AUO_PIXCIR_REG_INT_SETTING, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int auo_pixcir_start(struct auo_pixcir_ts *ts)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_ACTIVE);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not set power mode, %d\n",
+			ret);
+		return ret;
+	}
+
+	ts->stopped = false;
+	mb();
+	enable_irq(client->irq);
+
+	ret = auo_pixcir_int_toggle(ts, 1);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not enable interrupt, %d\n",
+			ret);
+		disable_irq(client->irq);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int auo_pixcir_stop(struct auo_pixcir_ts *ts)
+{
+	struct i2c_client *client = ts->client;
+	int ret;
+
+	ret = auo_pixcir_int_toggle(ts, 0);
+	if (ret < 0) {
+		dev_err(&client->dev, "could not disable interrupt, %d\n",
+			ret);
+		return ret;
+	}
+
+	/* disable receiving of interrupts */
+	disable_irq(client->irq);
+	ts->stopped = true;
+	mb();
+	wake_up(&ts->wait);
+
+	return auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_DEEP_SLEEP);
+}
+
+static int auo_pixcir_input_open(struct input_dev *dev)
+{
+	struct auo_pixcir_ts *ts = input_get_drvdata(dev);
+	int ret;
+
+	ret = auo_pixcir_start(ts);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void auo_pixcir_input_close(struct input_dev *dev)
+{
+	struct auo_pixcir_ts *ts = input_get_drvdata(dev);
+
+	auo_pixcir_stop(ts);
+
+	return;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int auo_pixcir_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+
+	/* when configured as wakeup source, device should always wake system
+	 * therefore start device if necessary
+	 */
+	if (device_may_wakeup(&client->dev)) {
+		/* need to start device if not open, to be wakeup source */
+		if (!input->users) {
+			ret = auo_pixcir_start(ts);
+			if (ret)
+				goto unlock;
+		}
+
+		enable_irq_wake(client->irq);
+		ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP);
+	} else if (input->users) {
+		ret = auo_pixcir_stop(ts);
+	}
+
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
+}
+
+static int auo_pixcir_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+
+	if (device_may_wakeup(&client->dev)) {
+		disable_irq_wake(client->irq);
+
+		/* need to stop device if it was not open on suspend */
+		if (!input->users) {
+			ret = auo_pixcir_stop(ts);
+			if (ret)
+				goto unlock;
+		}
+
+		/* device wakes automatically from SLEEP */
+	} else if (input->users) {
+		ret = auo_pixcir_start(ts);
+	}
+
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend,
+			 auo_pixcir_resume);
+
+static int __devinit auo_pixcir_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+	struct auo_pixcir_ts *ts;
+	struct input_dev *input_dev;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	ts = kzalloc(sizeof(struct auo_pixcir_ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	ret = gpio_request(pdata->gpio_int, "auo_pixcir_ts_int");
+	if (ret) {
+		dev_err(&client->dev, "request of gpio %d failed, %d\n",
+			pdata->gpio_int, ret);
+		goto err_gpio_int;
+	}
+
+	if (pdata->init_hw)
+		pdata->init_hw(client);
+
+	ts->client = client;
+	ts->touch_ind_mode = 0;
+	init_waitqueue_head(&ts->wait);
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input0", dev_name(&client->dev));
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(&client->dev, "could not allocate input device\n");
+		goto err_input_alloc;
+	}
+
+	ts->input = input_dev;
+
+	input_dev->name = "AUO-Pixcir touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	input_dev->open = auo_pixcir_input_open;
+	input_dev->close = auo_pixcir_input_close;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	/* For single touch */
+	input_set_abs_params(input_dev, ABS_X, 0, pdata->x_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, pdata->y_max, 0, 0);
+
+	/* For multi touch */
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+			     pdata->x_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+			     pdata->y_max, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
+			     AUO_PIXCIR_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
+			     AUO_PIXCIR_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+
+	ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION);
+	if (ret < 0)
+		goto err_fw_vers;
+	dev_info(&client->dev, "firmware version 0x%X\n", ret);
+
+	ret = auo_pixcir_int_config(ts, pdata->int_setting);
+	if (ret)
+		goto err_fw_vers;
+
+	input_set_drvdata(ts->input, ts);
+	ts->stopped = true;
+
+	ret = request_threaded_irq(client->irq, NULL, auo_pixcir_interrupt,
+				   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				   input_dev->name, ts);
+	if (ret) {
+		dev_err(&client->dev, "irq %d requested failed\n", client->irq);
+		goto err_fw_vers;
+	}
+
+	/* stop device and put it into deep sleep until it is opened */
+	ret = auo_pixcir_stop(ts);
+	if (ret < 0)
+		goto err_input_register;
+
+	ret = input_register_device(input_dev);
+	if (ret) {
+		dev_err(&client->dev, "could not register input device\n");
+		goto err_input_register;
+	}
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+
+err_input_register:
+	free_irq(client->irq, ts);
+err_fw_vers:
+	input_free_device(input_dev);
+err_input_alloc:
+	if (pdata->exit_hw)
+		pdata->exit_hw(client);
+	gpio_free(pdata->gpio_int);
+err_gpio_int:
+	kfree(ts);
+
+	return ret;
+}
+
+static int __devexit auo_pixcir_remove(struct i2c_client *client)
+{
+	struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
+	const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+
+	free_irq(client->irq, ts);
+
+	input_unregister_device(ts->input);
+
+	if (pdata->exit_hw)
+		pdata->exit_hw(client);
+
+	gpio_free(pdata->gpio_int);
+
+	kfree(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id auo_pixcir_idtable[] = {
+	{ "auo_pixcir_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
+
+static struct i2c_driver auo_pixcir_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "auo_pixcir_ts",
+		.pm	= &auo_pixcir_pm_ops,
+	},
+	.probe		= auo_pixcir_probe,
+	.remove		= __devexit_p(auo_pixcir_remove),
+	.id_table	= auo_pixcir_idtable,
+};
+
+module_i2c_driver(auo_pixcir_driver);
+
+MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/bu21013_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/bu21013_ts.c
new file mode 100644
index 0000000..f2d03c0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/bu21013_ts.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * License terms:GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/input.h>
+#include <linux/input/bu21013.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#define PEN_DOWN_INTR	0
+#define MAX_FINGERS	2
+#define RESET_DELAY	30
+#define PENUP_TIMEOUT	(10)
+#define DELTA_MIN	16
+#define MASK_BITS	0x03
+#define SHIFT_8		8
+#define SHIFT_2		2
+#define LENGTH_OF_BUFFER	11
+#define I2C_RETRY_COUNT	5
+
+#define BU21013_SENSORS_BTN_0_7_REG	0x70
+#define BU21013_SENSORS_BTN_8_15_REG	0x71
+#define BU21013_SENSORS_BTN_16_23_REG	0x72
+#define BU21013_X1_POS_MSB_REG		0x73
+#define BU21013_X1_POS_LSB_REG		0x74
+#define BU21013_Y1_POS_MSB_REG		0x75
+#define BU21013_Y1_POS_LSB_REG		0x76
+#define BU21013_X2_POS_MSB_REG		0x77
+#define BU21013_X2_POS_LSB_REG		0x78
+#define BU21013_Y2_POS_MSB_REG		0x79
+#define BU21013_Y2_POS_LSB_REG		0x7A
+#define BU21013_INT_CLR_REG		0xE8
+#define BU21013_INT_MODE_REG		0xE9
+#define BU21013_GAIN_REG		0xEA
+#define BU21013_OFFSET_MODE_REG		0xEB
+#define BU21013_XY_EDGE_REG		0xEC
+#define BU21013_RESET_REG		0xED
+#define BU21013_CALIB_REG		0xEE
+#define BU21013_DONE_REG		0xEF
+#define BU21013_SENSOR_0_7_REG		0xF0
+#define BU21013_SENSOR_8_15_REG		0xF1
+#define BU21013_SENSOR_16_23_REG	0xF2
+#define BU21013_POS_MODE1_REG		0xF3
+#define BU21013_POS_MODE2_REG		0xF4
+#define BU21013_CLK_MODE_REG		0xF5
+#define BU21013_IDLE_REG		0xFA
+#define BU21013_FILTER_REG		0xFB
+#define BU21013_TH_ON_REG		0xFC
+#define BU21013_TH_OFF_REG		0xFD
+
+
+#define BU21013_RESET_ENABLE		0x01
+
+#define BU21013_SENSORS_EN_0_7		0x3F
+#define BU21013_SENSORS_EN_8_15		0xFC
+#define BU21013_SENSORS_EN_16_23	0x1F
+
+#define BU21013_POS_MODE1_0		0x02
+#define BU21013_POS_MODE1_1		0x04
+#define BU21013_POS_MODE1_2		0x08
+
+#define BU21013_POS_MODE2_ZERO		0x01
+#define BU21013_POS_MODE2_AVG1		0x02
+#define BU21013_POS_MODE2_AVG2		0x04
+#define BU21013_POS_MODE2_EN_XY		0x08
+#define BU21013_POS_MODE2_EN_RAW	0x10
+#define BU21013_POS_MODE2_MULTI		0x80
+
+#define BU21013_CLK_MODE_DIV		0x01
+#define BU21013_CLK_MODE_EXT		0x02
+#define BU21013_CLK_MODE_CALIB		0x80
+
+#define BU21013_IDLET_0			0x01
+#define BU21013_IDLET_1			0x02
+#define BU21013_IDLET_2			0x04
+#define BU21013_IDLET_3			0x08
+#define BU21013_IDLE_INTERMIT_EN	0x10
+
+#define BU21013_DELTA_0_6	0x7F
+#define BU21013_FILTER_EN	0x80
+
+#define BU21013_INT_MODE_LEVEL	0x00
+#define BU21013_INT_MODE_EDGE	0x01
+
+#define BU21013_GAIN_0		0x01
+#define BU21013_GAIN_1		0x02
+#define BU21013_GAIN_2		0x04
+
+#define BU21013_OFFSET_MODE_DEFAULT	0x00
+#define BU21013_OFFSET_MODE_MOVE	0x01
+#define BU21013_OFFSET_MODE_DISABLE	0x02
+
+#define BU21013_TH_ON_0		0x01
+#define BU21013_TH_ON_1		0x02
+#define BU21013_TH_ON_2		0x04
+#define BU21013_TH_ON_3		0x08
+#define BU21013_TH_ON_4		0x10
+#define BU21013_TH_ON_5		0x20
+#define BU21013_TH_ON_6		0x40
+#define BU21013_TH_ON_7		0x80
+#define BU21013_TH_ON_MAX	0xFF
+
+#define BU21013_TH_OFF_0	0x01
+#define BU21013_TH_OFF_1	0x02
+#define BU21013_TH_OFF_2	0x04
+#define BU21013_TH_OFF_3	0x08
+#define BU21013_TH_OFF_4	0x10
+#define BU21013_TH_OFF_5	0x20
+#define BU21013_TH_OFF_6	0x40
+#define BU21013_TH_OFF_7	0x80
+#define BU21013_TH_OFF_MAX	0xFF
+
+#define BU21013_X_EDGE_0	0x01
+#define BU21013_X_EDGE_1	0x02
+#define BU21013_X_EDGE_2	0x04
+#define BU21013_X_EDGE_3	0x08
+#define BU21013_Y_EDGE_0	0x10
+#define BU21013_Y_EDGE_1	0x20
+#define BU21013_Y_EDGE_2	0x40
+#define BU21013_Y_EDGE_3	0x80
+
+#define BU21013_DONE	0x01
+#define BU21013_NUMBER_OF_X_SENSORS	(6)
+#define BU21013_NUMBER_OF_Y_SENSORS	(11)
+
+#define DRIVER_TP	"bu21013_tp"
+
+/**
+ * struct bu21013_ts_data - touch panel data structure
+ * @client: pointer to the i2c client
+ * @wait: variable to wait_queue_head_t structure
+ * @touch_stopped: touch stop flag
+ * @chip: pointer to the touch panel controller
+ * @in_dev: pointer to the input device structure
+ * @intr_pin: interrupt pin value
+ * @regulator: pointer to the Regulator used for touch screen
+ *
+ * Touch panel device data structure
+ */
+struct bu21013_ts_data {
+	struct i2c_client *client;
+	wait_queue_head_t wait;
+	bool touch_stopped;
+	const struct bu21013_platform_device *chip;
+	struct input_dev *in_dev;
+	unsigned int intr_pin;
+	struct regulator *regulator;
+};
+
+/**
+ * bu21013_read_block_data(): read the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ * @buf: byte pointer
+ *
+ * Read the touch co-ordinates using i2c read block into buffer
+ * and returns integer.
+ */
+static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
+{
+	int ret, i;
+
+	for (i = 0; i < I2C_RETRY_COUNT; i++) {
+		ret = i2c_smbus_read_i2c_block_data
+			(data->client, BU21013_SENSORS_BTN_0_7_REG,
+				LENGTH_OF_BUFFER, buf);
+		if (ret == LENGTH_OF_BUFFER)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+/**
+ * bu21013_do_touch_report(): Get the touch co-ordinates
+ * @data: bu21013_ts_data structure pointer
+ *
+ * Get the touch co-ordinates from touch sensor registers and writes
+ * into device structure and returns integer.
+ */
+static int bu21013_do_touch_report(struct bu21013_ts_data *data)
+{
+	u8	buf[LENGTH_OF_BUFFER];
+	unsigned int pos_x[2], pos_y[2];
+	bool	has_x_sensors, has_y_sensors;
+	int	finger_down_count = 0;
+	int	i;
+
+	if (data == NULL)
+		return -EINVAL;
+
+	if (bu21013_read_block_data(data, buf) < 0)
+		return -EINVAL;
+
+	has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
+	has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
+		((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
+	if (!has_x_sensors || !has_y_sensors)
+		return 0;
+
+	for (i = 0; i < MAX_FINGERS; i++) {
+		const u8 *p = &buf[4 * i + 3];
+		unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);
+		unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);
+		if (x == 0 || y == 0)
+			continue;
+		pos_x[finger_down_count] = x;
+		pos_y[finger_down_count] = y;
+		finger_down_count++;
+	}
+
+	if (finger_down_count) {
+		if (finger_down_count == 2 &&
+		    (abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||
+		     abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {
+			return 0;
+		}
+
+		for (i = 0; i < finger_down_count; i++) {
+			if (data->chip->x_flip)
+				pos_x[i] = data->chip->touch_x_max - pos_x[i];
+			if (data->chip->y_flip)
+				pos_y[i] = data->chip->touch_y_max - pos_y[i];
+
+			input_report_abs(data->in_dev,
+					 ABS_MT_POSITION_X, pos_x[i]);
+			input_report_abs(data->in_dev,
+					 ABS_MT_POSITION_Y, pos_y[i]);
+			input_mt_sync(data->in_dev);
+		}
+	} else
+		input_mt_sync(data->in_dev);
+
+	input_sync(data->in_dev);
+
+	return 0;
+}
+/**
+ * bu21013_gpio_irq() - gpio thread function for touch interrupt
+ * @irq: irq value
+ * @device_data: void pointer
+ *
+ * This gpio thread function for touch interrupt
+ * and returns irqreturn_t.
+ */
+static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
+{
+	struct bu21013_ts_data *data = device_data;
+	struct i2c_client *i2c = data->client;
+	int retval;
+
+	do {
+		retval = bu21013_do_touch_report(data);
+		if (retval < 0) {
+			dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");
+			return IRQ_NONE;
+		}
+
+		data->intr_pin = data->chip->irq_read_val();
+		if (data->intr_pin == PEN_DOWN_INTR)
+			wait_event_timeout(data->wait, data->touch_stopped,
+					   msecs_to_jiffies(2));
+	} while (!data->intr_pin && !data->touch_stopped);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * bu21013_init_chip() - power on sequence for the bu21013 controller
+ * @data: device structure pointer
+ *
+ * This function is used to power on
+ * the bu21013 controller and returns integer.
+ */
+static int bu21013_init_chip(struct bu21013_ts_data *data)
+{
+	int retval;
+	struct i2c_client *i2c = data->client;
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET_REG,
+					BU21013_RESET_ENABLE);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
+		return retval;
+	}
+	msleep(RESET_DELAY);
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
+					BU21013_SENSORS_EN_0_7);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
+						BU21013_SENSORS_EN_8_15);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
+						BU21013_SENSORS_EN_16_23);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
+				(BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
+			(BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 |
+			BU21013_POS_MODE2_AVG2 | BU21013_POS_MODE2_EN_RAW |
+			BU21013_POS_MODE2_MULTI));
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_POS_MODE2 reg write failed\n");
+		return retval;
+	}
+
+	if (data->chip->ext_clk)
+		retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+			(BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
+	else
+		retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
+			(BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
+				(BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
+						BU21013_INT_MODE_LEVEL);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
+						(BU21013_DELTA_0_6 |
+							BU21013_FILTER_EN));
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
+					BU21013_TH_ON_5);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
+				BU21013_TH_OFF_4 | BU21013_TH_OFF_3);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
+					(BU21013_GAIN_0 | BU21013_GAIN_1));
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
+					BU21013_OFFSET_MODE_DEFAULT);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
+				(BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
+				BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
+		return retval;
+	}
+
+	retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
+							BU21013_DONE);
+	if (retval < 0) {
+		dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
+		return retval;
+	}
+
+	return 0;
+}
+
+/**
+ * bu21013_free_irq() - frees IRQ registered for touchscreen
+ * @bu21013_data: device structure pointer
+ *
+ * This function signals interrupt thread to stop processing and
+ * frees interrupt.
+ */
+static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
+{
+	bu21013_data->touch_stopped = true;
+	wake_up(&bu21013_data->wait);
+	free_irq(bu21013_data->chip->irq, bu21013_data);
+}
+
+/**
+ * bu21013_probe() - initializes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ * @id: i2c device id pointer
+ *
+ * This function used to initializes the i2c-client touchscreen
+ * driver and returns integer.
+ */
+static int __devinit bu21013_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct bu21013_ts_data *bu21013_data;
+	struct input_dev *in_dev;
+	const struct bu21013_platform_device *pdata =
+					client->dev.platform_data;
+	int error;
+
+	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 (!pdata) {
+		dev_err(&client->dev, "platform data not defined\n");
+		return -EINVAL;
+	}
+
+	bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
+	in_dev = input_allocate_device();
+	if (!bu21013_data || !in_dev) {
+		dev_err(&client->dev, "device memory alloc failed\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	bu21013_data->in_dev = in_dev;
+	bu21013_data->chip = pdata;
+	bu21013_data->client = client;
+
+	bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH");
+	if (IS_ERR(bu21013_data->regulator)) {
+		dev_err(&client->dev, "regulator_get failed\n");
+		error = PTR_ERR(bu21013_data->regulator);
+		goto err_free_mem;
+	}
+
+	error = regulator_enable(bu21013_data->regulator);
+	if (error < 0) {
+		dev_err(&client->dev, "regulator enable failed\n");
+		goto err_put_regulator;
+	}
+
+	bu21013_data->touch_stopped = false;
+	init_waitqueue_head(&bu21013_data->wait);
+
+	/* configure the gpio pins */
+	if (pdata->cs_en) {
+		error = pdata->cs_en(pdata->cs_pin);
+		if (error < 0) {
+			dev_err(&client->dev, "chip init failed\n");
+			goto err_disable_regulator;
+		}
+	}
+
+	/* configure the touch panel controller */
+	error = bu21013_init_chip(bu21013_data);
+	if (error) {
+		dev_err(&client->dev, "error in bu21013 config\n");
+		goto err_cs_disable;
+	}
+
+	/* register the device to input subsystem */
+	in_dev->name = DRIVER_TP;
+	in_dev->id.bustype = BUS_I2C;
+	in_dev->dev.parent = &client->dev;
+
+	__set_bit(EV_SYN, in_dev->evbit);
+	__set_bit(EV_KEY, in_dev->evbit);
+	__set_bit(EV_ABS, in_dev->evbit);
+
+	input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
+						pdata->touch_x_max, 0, 0);
+	input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
+						pdata->touch_y_max, 0, 0);
+	input_set_drvdata(in_dev, bu21013_data);
+
+	error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
+				     IRQF_TRIGGER_FALLING | IRQF_SHARED,
+				     DRIVER_TP, bu21013_data);
+	if (error) {
+		dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
+		goto err_cs_disable;
+	}
+
+	error = input_register_device(in_dev);
+	if (error) {
+		dev_err(&client->dev, "failed to register input device\n");
+		goto err_free_irq;
+	}
+
+	device_init_wakeup(&client->dev, pdata->wakeup);
+	i2c_set_clientdata(client, bu21013_data);
+
+	return 0;
+
+err_free_irq:
+	bu21013_free_irq(bu21013_data);
+err_cs_disable:
+	pdata->cs_dis(pdata->cs_pin);
+err_disable_regulator:
+	regulator_disable(bu21013_data->regulator);
+err_put_regulator:
+	regulator_put(bu21013_data->regulator);
+err_free_mem:
+	input_free_device(in_dev);
+	kfree(bu21013_data);
+
+	return error;
+}
+/**
+ * bu21013_remove() - removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This function uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit bu21013_remove(struct i2c_client *client)
+{
+	struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+	bu21013_free_irq(bu21013_data);
+
+	bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
+
+	input_unregister_device(bu21013_data->in_dev);
+
+	regulator_disable(bu21013_data->regulator);
+	regulator_put(bu21013_data->regulator);
+
+	kfree(bu21013_data);
+
+	device_init_wakeup(&client->dev, false);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * bu21013_suspend() - suspend the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int bu21013_suspend(struct device *dev)
+{
+	struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+	struct i2c_client *client = bu21013_data->client;
+
+	bu21013_data->touch_stopped = true;
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(bu21013_data->chip->irq);
+	else
+		disable_irq(bu21013_data->chip->irq);
+
+	regulator_disable(bu21013_data->regulator);
+
+	return 0;
+}
+
+/**
+ * bu21013_resume() - resume the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This function is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int bu21013_resume(struct device *dev)
+{
+	struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
+	struct i2c_client *client = bu21013_data->client;
+	int retval;
+
+	retval = regulator_enable(bu21013_data->regulator);
+	if (retval < 0) {
+		dev_err(&client->dev, "bu21013 regulator enable failed\n");
+		return retval;
+	}
+
+	retval = bu21013_init_chip(bu21013_data);
+	if (retval < 0) {
+		dev_err(&client->dev, "bu21013 controller config failed\n");
+		return retval;
+	}
+
+	bu21013_data->touch_stopped = false;
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(bu21013_data->chip->irq);
+	else
+		enable_irq(bu21013_data->chip->irq);
+
+	return 0;
+}
+
+static const struct dev_pm_ops bu21013_dev_pm_ops = {
+	.suspend = bu21013_suspend,
+	.resume  = bu21013_resume,
+};
+#endif
+
+static const struct i2c_device_id bu21013_id[] = {
+	{ DRIVER_TP, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, bu21013_id);
+
+static struct i2c_driver bu21013_driver = {
+	.driver	= {
+		.name	=	DRIVER_TP,
+		.owner	=	THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	=	&bu21013_dev_pm_ops,
+#endif
+	},
+	.probe		=	bu21013_probe,
+	.remove		=	__devexit_p(bu21013_remove),
+	.id_table	=	bu21013_id,
+};
+
+module_i2c_driver(bu21013_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
+MODULE_DESCRIPTION("bu21013 touch screen controller driver");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cst716_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cst716_ts.c
new file mode 100644
index 0000000..caf7c29
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cst716_ts.c
@@ -0,0 +1,144 @@
+/* drivers/input/touchscreen/cst716_ts.c 

+* 

+* TouchScreen driver. 

+* 

+* Copyright (c) 

+* 

+* This software is licensed under the terms of the GNU General Public 

+* License version 2, as published by the Free Software Foundation, and 

+* may be copied, distributed, and modified under those terms. 

+* 

+* This program is distributed in the hope that it will be useful, 

+* but WITHOUT ANY WARRANTY; without even the implied warranty of 

+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

+* GNU General Public License for more details. 

+* 

+*/ 

+#include <linux/i2c.h> 

+#include <linux/input.h> 

+#include <linux/delay.h> 

+#include <linux/slab.h> 

+#include <linux/interrupt.h> 

+#include <mach/irqs.h> 

+#include <linux/kernel.h> 

+#include <linux/semaphore.h> 

+#include <linux/mutex.h> 

+#include <linux/platform_device.h>

+#include <linux/module.h> 

+#include <linux/gpio.h> 

+#include <linux/syscalls.h> 

+#include <linux/unistd.h> 

+#include <linux/uaccess.h> 

+#include <linux/fs.h> 

+#include <linux/string.h> 

+#include <linux/timer.h> 

+#include <linux/of.h> 

+#include <linux/of_gpio.h> 

+#include <linux/irq.h>

+#include <linux/input/touchscreen.h> 

+#include <linux/input/cst716_ts.h> 

+

+extern enum touchscreen_type touchscreen_detected_type;

+	  

+int cst716_read_touchdata(struct ts_data *data) 

+{ 

+	struct ts_event *event = data->events; 

+	u8 readbuf[POINT_READ_BUF] = { 0 };

+	int ret = -1; 

+	int i; 

+

+	ret = tp_i2c_read(data->client, readbuf, 1, readbuf, POINT_READ_BUF);

+	if (ret < 0) { 

+		dev_err(&data->client->dev, "%s read touchdata failed.\n", 

+		__func__); 

+		return ret; 

+	} 

+

+	data->touch_points = readbuf[HYN_TOUCH_POINT_NUM] & 0x0F;

+

+	if (data->touch_points > CFG_MAX_TOUCH_POINTS) { 

+		dev_err(&data->input_dev->dev, 

+		"touchscreen reports %d points, %d are supported\n", 

+		data->touch_points, CFG_MAX_TOUCH_POINTS); 

+		data->touch_points = CFG_MAX_TOUCH_POINTS; 

+	}

+

+	for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) { 

+		event[i].x =

+		(s16) (readbuf[HYN_TOUCH_X_H_POS + HYN_TOUCH_STEP * i] & 0x0F) <<

+		8 | (s16) readbuf[HYN_TOUCH_X_L_POS + HYN_TOUCH_STEP * i];

+		event[i].y =

+		(s16) (readbuf[HYN_TOUCH_Y_H_POS + HYN_TOUCH_STEP * i] & 0x0F) <<

+		8 | (s16) readbuf[HYN_TOUCH_Y_L_POS + HYN_TOUCH_STEP * i];

+		event[i].event =

+		readbuf[HYN_TOUCH_EVENT_POS + HYN_TOUCH_STEP * i] >> 6;

+		event[i].id =

+		(readbuf[HYN_TOUCH_ID_POS + HYN_TOUCH_STEP * i]) >> 4;

+

+		event[i].pressure =

+		(readbuf[HYN_TOUCH_XY_POS + HYN_TOUCH_STEP * i]);

+

+		if ((event[i].event == 0 || event[i].event == 2) && (data->touch_points == 0))

+		break;

+	} 

+

+	return 0; 

+} 

+

+static struct touchscreen_operations cst716_operations =

+{

+	cst716_read_touchdata,

+};

+

+int cst716_id_detect(struct i2c_client *client)

+{

+	int ret = 0 ;

+	u8 chip_vendor_id = 0;

+	u8 ctpm_vendor_id = 0;

+	

+	/* allow touch panel controller to boot, before querying it */ 

+	msleep(150); 

+	client->addr = CST716_I2C_SLAVE_ADDR;

+	ret = tp_read(client, TP_REG_CHIP_VENDOR_ID, 1, &chip_vendor_id);

+

+	if(ret < 0)

+	{

+      		printk("[TP] cst716 TP_REG_CHIP_VENDOR_ID 0x%x failed\n",client->addr);

+     		return -EINVAL;

+	}

+	

+	ret = tp_read(client, TP_REG_CTPM_VENDOR_ID, 1, &ctpm_vendor_id);

+

+	if(ret < 0)

+	{

+      		printk("[TP] cst716 TP_REG_CTPM_VENDOR_ID 0x%x failed\n",client->addr);

+     		return -EINVAL;

+	}

+

+	if((chip_vendor_id == 0x36) &&(ctpm_vendor_id == 0x01))

+	{

+		touchscreen_detected_type = TOUCHSCREEN_CST716; 

+	}

+	else

+	{

+		return -EINVAL;

+	}

+

+	touchscreen_set_operations(TOUCHSCREEN_CST716, &cst716_operations);

+  

+	return 0;

+}

+

+static struct touchscreen_register cst716_id_register = 

+{

+	cst716_id_detect

+};

+

+static int cst716_ts_driver_init()

+{

+	touchscreen_register(TOUCHSCREEN_CST716, &cst716_id_register);

+	return 0;

+}

+

+subsys_initcall(cst716_ts_driver_init);

+

diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cy8ctmg110_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cy8ctmg110_ts.c
new file mode 100644
index 0000000..237753a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -0,0 +1,357 @@
+/*
+ * Driver for cypress touch screen controller
+ *
+ * Copyright (c) 2009 Aava Mobile
+ *
+ * Some cleanups by Alan Cox <alan@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/input/cy8ctmg110_pdata.h>
+
+#define CY8CTMG110_DRIVER_NAME      "cy8ctmg110"
+
+/* Touch coordinates */
+#define CY8CTMG110_X_MIN		0
+#define CY8CTMG110_Y_MIN		0
+#define CY8CTMG110_X_MAX		759
+#define CY8CTMG110_Y_MAX		465
+
+
+/* cy8ctmg110 register definitions */
+#define CY8CTMG110_TOUCH_WAKEUP_TIME	0
+#define CY8CTMG110_TOUCH_SLEEP_TIME	2
+#define CY8CTMG110_TOUCH_X1		3
+#define CY8CTMG110_TOUCH_Y1		5
+#define CY8CTMG110_TOUCH_X2		7
+#define CY8CTMG110_TOUCH_Y2		9
+#define CY8CTMG110_FINGERS		11
+#define CY8CTMG110_GESTURE		12
+#define CY8CTMG110_REG_MAX		13
+
+
+/*
+ * The touch driver structure.
+ */
+struct cy8ctmg110 {
+	struct input_dev *input;
+	char phys[32];
+	struct i2c_client *client;
+	int reset_pin;
+	int irq_pin;
+};
+
+/*
+ * cy8ctmg110_power is the routine that is called when touch hardware
+ * will powered off or on.
+ */
+static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
+{
+	if (ts->reset_pin)
+		gpio_direction_output(ts->reset_pin, 1 - poweron);
+}
+
+static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
+		unsigned char len, unsigned char *value)
+{
+	struct i2c_client *client = tsc->client;
+	int ret;
+	unsigned char i2c_data[6];
+
+	BUG_ON(len > 5);
+
+	i2c_data[0] = reg;
+	memcpy(i2c_data + 1, value, len);
+
+	ret = i2c_master_send(client, i2c_data, len + 1);
+	if (ret != len + 1) {
+		dev_err(&client->dev, "i2c write data cmd failed\n");
+		return ret < 0 ? ret : -EIO;
+	}
+
+	return 0;
+}
+
+static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
+		unsigned char *data, unsigned char len, unsigned char cmd)
+{
+	struct i2c_client *client = tsc->client;
+	int ret;
+	struct i2c_msg msg[2] = {
+		/* first write slave position to i2c devices */
+		{ client->addr, 0, 1, &cmd },
+		/* Second read data from position */
+		{ client->addr, I2C_M_RD, len, data }
+	};
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
+{
+	struct input_dev *input = tsc->input;
+	unsigned char reg_p[CY8CTMG110_REG_MAX];
+	int x, y;
+
+	memset(reg_p, 0, CY8CTMG110_REG_MAX);
+
+	/* Reading coordinates */
+	if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
+		return -EIO;
+
+	y = reg_p[2] << 8 | reg_p[3];
+	x = reg_p[0] << 8 | reg_p[1];
+
+	/* Number of touch */
+	if (reg_p[8] == 0) {
+		input_report_key(input, BTN_TOUCH, 0);
+	} else  {
+		input_report_key(input, BTN_TOUCH, 1);
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+	}
+
+	input_sync(input);
+
+	return 0;
+}
+
+static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
+{
+	unsigned char reg_p[3];
+
+	if (sleep) {
+		reg_p[0] = 0x00;
+		reg_p[1] = 0xff;
+		reg_p[2] = 5;
+	} else {
+		reg_p[0] = 0x10;
+		reg_p[1] = 0xff;
+		reg_p[2] = 0;
+	}
+
+	return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
+}
+
+static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
+{
+	struct cy8ctmg110 *tsc = dev_id;
+
+	cy8ctmg110_touch_pos(tsc);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit cy8ctmg110_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	const struct cy8ctmg110_pdata *pdata = client->dev.platform_data;
+	struct cy8ctmg110 *ts;
+	struct input_dev *input_dev;
+	int err;
+
+	/* No pdata no way forward */
+	if (pdata == NULL) {
+		dev_err(&client->dev, "no pdata\n");
+		return -ENODEV;
+	}
+
+	if (!i2c_check_functionality(client->adapter,
+					I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EIO;
+
+	ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->client = client;
+	ts->input = input_dev;
+	ts->reset_pin = pdata->reset_pin;
+	ts->irq_pin = pdata->irq_pin;
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input0", dev_name(&client->dev));
+
+	input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X,
+			CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 4, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 4, 0);
+
+	if (ts->reset_pin) {
+		err = gpio_request(ts->reset_pin, NULL);
+		if (err) {
+			dev_err(&client->dev,
+				"Unable to request GPIO pin %d.\n",
+				ts->reset_pin);
+			goto err_free_mem;
+		}
+	}
+
+	cy8ctmg110_power(ts, true);
+	cy8ctmg110_set_sleepmode(ts, false);
+
+	err = gpio_request(ts->irq_pin, "touch_irq_key");
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to request GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_shutoff_device;
+	}
+
+	err = gpio_direction_input(ts->irq_pin);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to configure input direction for GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_free_irq_gpio;
+	}
+
+	client->irq = gpio_to_irq(ts->irq_pin);
+	if (client->irq < 0) {
+		err = client->irq;
+		dev_err(&client->dev,
+			"Unable to get irq number for GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_free_irq_gpio;
+	}
+
+	err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
+				   IRQF_TRIGGER_RISING, "touch_reset_key", ts);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"irq %d busy? error %d\n", client->irq, err);
+		goto err_free_irq_gpio;
+	}
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, ts);
+	device_init_wakeup(&client->dev, 1);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, ts);
+err_free_irq_gpio:
+	gpio_free(ts->irq_pin);
+err_shutoff_device:
+	cy8ctmg110_set_sleepmode(ts, true);
+	cy8ctmg110_power(ts, false);
+	if (ts->reset_pin)
+		gpio_free(ts->reset_pin);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	return err;
+}
+
+#ifdef CONFIG_PM
+static int cy8ctmg110_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(client->irq);
+	else {
+		cy8ctmg110_set_sleepmode(ts, true);
+		cy8ctmg110_power(ts, false);
+	}
+	return 0;
+}
+
+static int cy8ctmg110_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(client->irq);
+	else {
+		cy8ctmg110_power(ts, true);
+		cy8ctmg110_set_sleepmode(ts, false);
+	}
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
+#endif
+
+static int __devexit cy8ctmg110_remove(struct i2c_client *client)
+{
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	cy8ctmg110_set_sleepmode(ts, true);
+	cy8ctmg110_power(ts, false);
+
+	free_irq(client->irq, ts);
+	input_unregister_device(ts->input);
+	gpio_free(ts->irq_pin);
+	if (ts->reset_pin)
+		gpio_free(ts->reset_pin);
+	kfree(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id cy8ctmg110_idtable[] = {
+	{ CY8CTMG110_DRIVER_NAME, 1 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
+
+static struct i2c_driver cy8ctmg110_driver = {
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= CY8CTMG110_DRIVER_NAME,
+#ifdef CONFIG_PM
+		.pm	= &cy8ctmg110_pm,
+#endif
+	},
+	.id_table	= cy8ctmg110_idtable,
+	.probe		= cy8ctmg110_probe,
+	.remove		= __devexit_p(cy8ctmg110_remove),
+};
+
+module_i2c_driver(cy8ctmg110_driver);
+
+MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
+MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_core.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 0000000..3f505d5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,625 @@
+/*
+ * Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include "cyttsp_core.h"
+
+/* Bootloader number of command keys */
+#define CY_NUM_BL_KEYS		8
+
+/* helpers */
+#define GET_NUM_TOUCHES(x)		((x) & 0x0F)
+#define IS_LARGE_AREA(x)		(((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x)			((x) & 0x20)
+#define IS_VALID_APP(x)			((x) & 0x01)
+#define IS_OPERATIONAL_ERR(x)		((x) & 0x3F)
+#define GET_HSTMODE(reg)		(((reg) & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)		(((reg) & 0x10) >> 4)
+
+#define CY_REG_BASE			0x00
+#define CY_REG_ACT_DIST			0x1E
+#define CY_REG_ACT_INTRVL		0x1D
+#define CY_REG_TCH_TMOUT		(CY_REG_ACT_INTRVL + 1)
+#define CY_REG_LP_INTRVL		(CY_REG_TCH_TMOUT + 1)
+#define CY_MAXZ				255
+#define CY_DELAY_DFLT			20 /* ms */
+#define CY_DELAY_MAX			500
+#define CY_ACT_DIST_DFLT		0xF8
+#define CY_HNDSHK_BIT			0x80
+/* device mode bits */
+#define CY_OPERATE_MODE			0x00
+#define CY_SYSINFO_MODE			0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE		0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE		0x02
+#define CY_LOW_POWER_MODE		0x04
+
+/* Slots management */
+#define CY_MAX_FINGER			4
+#define CY_MAX_ID			16
+
+static const u8 bl_command[] = {
+	0x00,			/* file offset */
+	0xFF,			/* command */
+	0xA5,			/* exit bootloader command */
+	0, 1, 2, 3, 4, 5, 6, 7	/* default keys */
+};
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+				u8 length, void *buf)
+{
+	int error;
+	int tries;
+
+	for (tries = 0; tries < CY_NUM_RETRY; tries++) {
+		error = ts->bus_ops->read(ts, command, length, buf);
+		if (!error)
+			return 0;
+
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return -EIO;
+}
+
+static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
+				 u8 length, void *buf)
+{
+	int error;
+	int tries;
+
+	for (tries = 0; tries < CY_NUM_RETRY; tries++) {
+		error = ts->bus_ops->write(ts, command, length, buf);
+		if (!error)
+			return 0;
+
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return -EIO;
+}
+
+static int ttsp_send_command(struct cyttsp *ts, u8 cmd)
+{
+	return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+}
+
+static int cyttsp_load_bl_regs(struct cyttsp *ts)
+{
+	memset(&ts->bl_data, 0, sizeof(ts->bl_data));
+	ts->bl_data.bl_status = 0x10;
+
+	return ttsp_read_block_data(ts, CY_REG_BASE,
+				    sizeof(ts->bl_data), &ts->bl_data);
+}
+
+static int cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+	int error;
+	u8 bl_cmd[sizeof(bl_command)];
+
+	memcpy(bl_cmd, bl_command, sizeof(bl_command));
+	if (ts->pdata->bl_keys)
+		memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
+			ts->pdata->bl_keys, CY_NUM_BL_KEYS);
+
+	error = ttsp_write_block_data(ts, CY_REG_BASE,
+				      sizeof(bl_cmd), bl_cmd);
+	if (error)
+		return error;
+
+	/* wait for TTSP Device to complete the operation */
+	msleep(CY_DELAY_DFLT);
+
+	error = cyttsp_load_bl_regs(ts);
+	if (error)
+		return error;
+
+	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
+		return -EIO;
+
+	return 0;
+}
+
+static int cyttsp_set_operational_mode(struct cyttsp *ts)
+{
+	int error;
+
+	error = ttsp_send_command(ts, CY_OPERATE_MODE);
+	if (error)
+		return error;
+
+	/* wait for TTSP Device to complete switch to Operational mode */
+	error = ttsp_read_block_data(ts, CY_REG_BASE,
+				     sizeof(ts->xy_data), &ts->xy_data);
+	if (error)
+		return error;
+
+	return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0;
+}
+
+static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+	int error;
+
+	memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data));
+
+	/* switch to sysinfo mode */
+	error = ttsp_send_command(ts, CY_SYSINFO_MODE);
+	if (error)
+		return error;
+
+	/* read sysinfo registers */
+	msleep(CY_DELAY_DFLT);
+	error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data),
+				      &ts->sysinfo_data);
+	if (error)
+		return error;
+
+	if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl)
+		return -EIO;
+
+	return 0;
+}
+
+static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	if (ts->pdata->act_intrvl != CY_ACT_INTRVL_DFLT ||
+	    ts->pdata->tch_tmout != CY_TCH_TMOUT_DFLT ||
+	    ts->pdata->lp_intrvl != CY_LP_INTRVL_DFLT) {
+
+		u8 intrvl_ray[] = {
+			ts->pdata->act_intrvl,
+			ts->pdata->tch_tmout,
+			ts->pdata->lp_intrvl
+		};
+
+		/* set intrvl registers */
+		retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL,
+					sizeof(intrvl_ray), intrvl_ray);
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return retval;
+}
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+	unsigned long timeout;
+	int retval;
+
+	/* wait for interrupt to set ready completion */
+	INIT_COMPLETION(ts->bl_ready);
+	ts->state = CY_BL_STATE;
+
+	enable_irq(ts->irq);
+
+	retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE);
+	if (retval)
+		goto out;
+
+	timeout = wait_for_completion_timeout(&ts->bl_ready,
+			msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
+	retval = timeout ? 0 : -EIO;
+
+out:
+	ts->state = CY_IDLE_STATE;
+	disable_irq(ts->irq);
+	return retval;
+}
+
+static int cyttsp_act_dist_setup(struct cyttsp *ts)
+{
+	u8 act_dist_setup = ts->pdata->act_dist;
+
+	/* Init gesture; active distance setup */
+	return ttsp_write_block_data(ts, CY_REG_ACT_DIST,
+				sizeof(act_dist_setup), &act_dist_setup);
+}
+
+static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids)
+{
+	ids[0] = xy_data->touch12_id >> 4;
+	ids[1] = xy_data->touch12_id & 0xF;
+	ids[2] = xy_data->touch34_id >> 4;
+	ids[3] = xy_data->touch34_id & 0xF;
+}
+
+static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data,
+					       int idx)
+{
+	switch (idx) {
+	case 0:
+		return &xy_data->tch1;
+	case 1:
+		return &xy_data->tch2;
+	case 2:
+		return &xy_data->tch3;
+	case 3:
+		return &xy_data->tch4;
+	default:
+		return NULL;
+	}
+}
+
+static void cyttsp_report_tchdata(struct cyttsp *ts)
+{
+	struct cyttsp_xydata *xy_data = &ts->xy_data;
+	struct input_dev *input = ts->input;
+	int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat);
+	const struct cyttsp_tch *tch;
+	int ids[CY_MAX_ID];
+	int i;
+	DECLARE_BITMAP(used, CY_MAX_ID);
+
+	if (IS_LARGE_AREA(xy_data->tt_stat) == 1) {
+		/* terminate all active tracks */
+		num_tch = 0;
+		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
+	} else if (num_tch > CY_MAX_FINGER) {
+		/* terminate all active tracks */
+		num_tch = 0;
+		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
+	} else if (IS_BAD_PKT(xy_data->tt_mode)) {
+		/* terminate all active tracks */
+		num_tch = 0;
+		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
+	}
+
+	cyttsp_extract_track_ids(xy_data, ids);
+
+	bitmap_zero(used, CY_MAX_ID);
+
+	for (i = 0; i < num_tch; i++) {
+		tch = cyttsp_get_tch(xy_data, i);
+
+		input_mt_slot(input, ids[i]);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+		input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x));
+		input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y));
+		input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z);
+
+		__set_bit(ids[i], used);
+	}
+
+	for (i = 0; i < CY_MAX_ID; i++) {
+		if (test_bit(i, used))
+			continue;
+
+		input_mt_slot(input, i);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
+	}
+
+	input_sync(input);
+}
+
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = handle;
+	int error;
+
+	if (unlikely(ts->state == CY_BL_STATE)) {
+		complete(&ts->bl_ready);
+		goto out;
+	}
+
+	/* Get touch data from CYTTSP device */
+	error = ttsp_read_block_data(ts, CY_REG_BASE,
+				 sizeof(struct cyttsp_xydata), &ts->xy_data);
+	if (error)
+		goto out;
+
+	/* provide flow control handshake */
+	if (ts->pdata->use_hndshk) {
+		error = ttsp_send_command(ts,
+				ts->xy_data.hst_mode ^ CY_HNDSHK_BIT);
+		if (error)
+			goto out;
+	}
+
+	if (unlikely(ts->state == CY_IDLE_STATE))
+		goto out;
+
+	if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
+		/*
+		 * TTSP device has reset back to bootloader mode.
+		 * Restore to operational mode.
+		 */
+		error = cyttsp_exit_bl_mode(ts);
+		if (error) {
+			dev_err(ts->dev,
+				"Could not return to operational mode, err: %d\n",
+				error);
+			ts->state = CY_IDLE_STATE;
+		}
+	} else {
+		cyttsp_report_tchdata(ts);
+	}
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+	int error;
+
+	error = cyttsp_soft_reset(ts);
+	if (error)
+		return error;
+
+	error = cyttsp_load_bl_regs(ts);
+	if (error)
+		return error;
+
+	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
+	    IS_VALID_APP(ts->bl_data.bl_status)) {
+		error = cyttsp_exit_bl_mode(ts);
+		if (error)
+			return error;
+	}
+
+	if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE ||
+	    IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) {
+		return -ENODEV;
+	}
+
+	error = cyttsp_set_sysinfo_mode(ts);
+	if (error)
+		return error;
+
+	error = cyttsp_set_sysinfo_regs(ts);
+	if (error)
+		return error;
+
+	error = cyttsp_set_operational_mode(ts);
+	if (error)
+		return error;
+
+	/* init active distance */
+	error = cyttsp_act_dist_setup(ts);
+	if (error)
+		return error;
+
+	ts->state = CY_ACTIVE_STATE;
+
+	return 0;
+}
+
+static int cyttsp_enable(struct cyttsp *ts)
+{
+	int error;
+
+	/*
+	 * The device firmware can wake on an I2C or SPI memory slave
+	 * address match. So just reading a register is sufficient to
+	 * wake up the device. The first read attempt will fail but it
+	 * will wake it up making the second read attempt successful.
+	 */
+	error = ttsp_read_block_data(ts, CY_REG_BASE,
+				     sizeof(ts->xy_data), &ts->xy_data);
+	if (error)
+		return error;
+
+	if (GET_HSTMODE(ts->xy_data.hst_mode))
+		return -EIO;
+
+	enable_irq(ts->irq);
+
+	return 0;
+}
+
+static int cyttsp_disable(struct cyttsp *ts)
+{
+	int error;
+
+	error = ttsp_send_command(ts, CY_LOW_POWER_MODE);
+	if (error)
+		return error;
+
+	disable_irq(ts->irq);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cyttsp_suspend(struct device *dev)
+{
+	struct cyttsp *ts = dev_get_drvdata(dev);
+	int retval = 0;
+
+	mutex_lock(&ts->input->mutex);
+
+	if (ts->input->users) {
+		retval = cyttsp_disable(ts);
+		if (retval == 0)
+			ts->suspended = true;
+	}
+
+	mutex_unlock(&ts->input->mutex);
+
+	return retval;
+}
+
+static int cyttsp_resume(struct device *dev)
+{
+	struct cyttsp *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->input->mutex);
+
+	if (ts->input->users)
+		cyttsp_enable(ts);
+
+	ts->suspended = false;
+
+	mutex_unlock(&ts->input->mutex);
+
+	return 0;
+}
+
+#endif
+
+SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
+EXPORT_SYMBOL_GPL(cyttsp_pm_ops);
+
+static int cyttsp_open(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+	int retval = 0;
+
+	if (!ts->suspended)
+		retval = cyttsp_enable(ts);
+
+	return retval;
+}
+
+static void cyttsp_close(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	if (!ts->suspended)
+		cyttsp_disable(ts);
+}
+
+struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
+			    struct device *dev, int irq, size_t xfer_buf_size)
+{
+	const struct cyttsp_platform_data *pdata = dev->platform_data;
+	struct cyttsp *ts;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!pdata || !pdata->name || irq <= 0) {
+		error = -EINVAL;
+		goto err_out;
+	}
+
+	ts = kzalloc(sizeof(*ts) + xfer_buf_size, GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->dev = dev;
+	ts->input = input_dev;
+	ts->pdata = dev->platform_data;
+	ts->bus_ops = bus_ops;
+	ts->irq = irq;
+
+	init_completion(&ts->bl_ready);
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
+
+	if (pdata->init) {
+		error = pdata->init();
+		if (error) {
+			dev_err(ts->dev, "platform init failed, err: %d\n",
+				error);
+			goto err_free_mem;
+		}
+	}
+
+	input_dev->name = pdata->name;
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = bus_ops->bustype;
+	input_dev->dev.parent = ts->dev;
+
+	input_dev->open = cyttsp_open;
+	input_dev->close = cyttsp_close;
+
+	input_set_drvdata(input_dev, ts);
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+			     0, pdata->maxx, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+			     0, pdata->maxy, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+			     0, CY_MAXZ, 0, 0);
+
+	input_mt_init_slots(input_dev, CY_MAX_ID);
+
+	error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				     pdata->name, ts);
+	if (error) {
+		dev_err(ts->dev, "failed to request IRQ %d, err: %d\n",
+			ts->irq, error);
+		goto err_platform_exit;
+	}
+
+	disable_irq(ts->irq);
+
+	error = cyttsp_power_on(ts);
+	if (error)
+		goto err_free_irq;
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(ts->dev, "failed to register input device: %d\n",
+			error);
+		goto err_free_irq;
+	}
+
+	return ts;
+
+err_free_irq:
+	free_irq(ts->irq, ts);
+err_platform_exit:
+	if (pdata->exit)
+		pdata->exit();
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+err_out:
+	return ERR_PTR(error);
+}
+EXPORT_SYMBOL_GPL(cyttsp_probe);
+
+void cyttsp_remove(struct cyttsp *ts)
+{
+	free_irq(ts->irq, ts);
+	input_unregister_device(ts->input);
+	if (ts->pdata->exit)
+		ts->pdata->exit();
+	kfree(ts);
+}
+EXPORT_SYMBOL_GPL(cyttsp_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
+MODULE_AUTHOR("Cypress");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_core.h b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_core.h
new file mode 100644
index 0000000..1aa3c69
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_core.h
@@ -0,0 +1,149 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+
+#ifndef __CYTTSP_CORE_H__
+#define __CYTTSP_CORE_H__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/input/cyttsp.h>
+
+#define CY_NUM_RETRY		16 /* max number of retries for read ops */
+
+struct cyttsp_tch {
+	__be16 x, y;
+	u8 z;
+} __packed;
+
+/* TrueTouch Standard Product Gen3 interface definition */
+struct cyttsp_xydata {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	struct cyttsp_tch tch1;
+	u8 touch12_id;
+	struct cyttsp_tch tch2;
+	u8 gest_cnt;
+	u8 gest_id;
+	struct cyttsp_tch tch3;
+	u8 touch34_id;
+	struct cyttsp_tch tch4;
+	u8 tt_undef[3];
+	u8 act_dist;
+	u8 tt_reserved;
+} __packed;
+
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[5];
+	u8 scn_typ;
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+struct cyttsp;
+
+struct cyttsp_bus_ops {
+	u16 bustype;
+	int (*write)(struct cyttsp *ts,
+		     u8 addr, u8 length, const void *values);
+	int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values);
+};
+
+enum cyttsp_state {
+	CY_IDLE_STATE,
+	CY_ACTIVE_STATE,
+	CY_BL_STATE,
+};
+
+struct cyttsp {
+	struct device *dev;
+	int irq;
+	struct input_dev *input;
+	char phys[32];
+	const struct cyttsp_platform_data *pdata;
+	const struct cyttsp_bus_ops *bus_ops;
+	struct cyttsp_bootloader_data bl_data;
+	struct cyttsp_sysinfo_data sysinfo_data;
+	struct cyttsp_xydata xy_data;
+	struct completion bl_ready;
+	enum cyttsp_state state;
+	bool suspended;
+
+	u8 xfer_buf[] ____cacheline_aligned;
+};
+
+struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
+			    struct device *dev, int irq, size_t xfer_buf_size);
+void cyttsp_remove(struct cyttsp *ts);
+
+extern const struct dev_pm_ops cyttsp_pm_ops;
+
+#endif /* __CYTTSP_CORE_H__ */
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_i2c.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100644
index 0000000..2af1d0c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_i2c.c
@@ -0,0 +1,136 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+
+#define CY_I2C_DATA_SIZE	128
+
+static int cyttsp_i2c_read_block_data(struct cyttsp *ts,
+				      u8 addr, u8 length, void *values)
+{
+	struct i2c_client *client = to_i2c_client(ts->dev);
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &addr,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = values,
+		},
+	};
+	int retval;
+
+	retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (retval < 0)
+		return retval;
+
+	return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+
+static int cyttsp_i2c_write_block_data(struct cyttsp *ts,
+				       u8 addr, u8 length, const void *values)
+{
+	struct i2c_client *client = to_i2c_client(ts->dev);
+	int retval;
+
+	ts->xfer_buf[0] = addr;
+	memcpy(&ts->xfer_buf[1], values, length);
+
+	retval = i2c_master_send(client, ts->xfer_buf, length + 1);
+
+	return retval < 0 ? retval : 0;
+}
+
+static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
+	.bustype	= BUS_I2C,
+	.write		= cyttsp_i2c_write_block_data,
+	.read           = cyttsp_i2c_read_block_data,
+};
+
+static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	struct cyttsp *ts;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "I2C functionality not Supported\n");
+		return -EIO;
+	}
+
+	ts = cyttsp_probe(&cyttsp_i2c_bus_ops, &client->dev, client->irq,
+			  CY_I2C_DATA_SIZE);
+
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+}
+
+static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+{
+	struct cyttsp *ts = i2c_get_clientdata(client);
+
+	cyttsp_remove(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id cyttsp_i2c_id[] = {
+	{ CY_I2C_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
+
+static struct i2c_driver cyttsp_i2c_driver = {
+	.driver = {
+		.name	= CY_I2C_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &cyttsp_pm_ops,
+	},
+	.probe		= cyttsp_i2c_probe,
+	.remove		= __devexit_p(cyttsp_i2c_remove),
+	.id_table	= cyttsp_i2c_id,
+};
+
+module_i2c_driver(cyttsp_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("i2c:cyttsp");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_spi.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100644
index 0000000..9f26341
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/cyttsp_spi.c
@@ -0,0 +1,200 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+
+#define CY_SPI_WR_OP		0x00 /* r/~w */
+#define CY_SPI_RD_OP		0x01
+#define CY_SPI_CMD_BYTES	4
+#define CY_SPI_SYNC_BYTE	2
+#define CY_SPI_SYNC_ACK1	0x62 /* from protocol v.2 */
+#define CY_SPI_SYNC_ACK2	0x9D /* from protocol v.2 */
+#define CY_SPI_DATA_SIZE	128
+#define CY_SPI_DATA_BUF_SIZE	(CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+#define CY_SPI_BITS_PER_WORD	8
+
+static int cyttsp_spi_xfer(struct cyttsp *ts,
+			   u8 op, u8 reg, u8 *buf, int length)
+{
+	struct spi_device *spi = to_spi_device(ts->dev);
+	struct spi_message msg;
+	struct spi_transfer xfer[2];
+	u8 *wr_buf = &ts->xfer_buf[0];
+	u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE];
+	int retval;
+	int i;
+
+	if (length > CY_SPI_DATA_SIZE) {
+		dev_err(ts->dev, "%s: length %d is too big.\n",
+			__func__, length);
+		return -EINVAL;
+	}
+
+	memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
+	memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
+
+	wr_buf[0] = 0x00; /* header byte 0 */
+	wr_buf[1] = 0xFF; /* header byte 1 */
+	wr_buf[2] = reg;  /* reg index */
+	wr_buf[3] = op;   /* r/~w */
+	if (op == CY_SPI_WR_OP)
+		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+
+	memset(xfer, 0, sizeof(xfer));
+	spi_message_init(&msg);
+
+	/*
+	  We set both TX and RX buffers because Cypress TTSP
+	  requires full duplex operation.
+	*/
+	xfer[0].tx_buf = wr_buf;
+	xfer[0].rx_buf = rd_buf;
+	switch (op) {
+	case CY_SPI_WR_OP:
+		xfer[0].len = length + CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+		break;
+
+	case CY_SPI_RD_OP:
+		xfer[0].len = CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+
+		xfer[1].rx_buf = buf;
+		xfer[1].len = length;
+		spi_message_add_tail(&xfer[1], &msg);
+		break;
+
+	default:
+		dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op);
+		return -EINVAL;
+	}
+
+	retval = spi_sync(spi, &msg);
+	if (retval < 0) {
+		dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
+			__func__, retval, xfer[1].len, op);
+
+		/*
+		 * do not return here since was a bad ACK sequence
+		 * let the following ACK check handle any errors and
+		 * allow silent retries
+		 */
+	}
+
+	if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 ||
+	    rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) {
+
+		dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op);
+
+		for (i = 0; i < CY_SPI_CMD_BYTES; i++)
+			dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n",
+				__func__, i, rd_buf[i]);
+		for (i = 0; i < length; i++)
+			dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n",
+				__func__, i, buf[i]);
+
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int cyttsp_spi_read_block_data(struct cyttsp *ts,
+				      u8 addr, u8 length, void *data)
+{
+	return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length);
+}
+
+static int cyttsp_spi_write_block_data(struct cyttsp *ts,
+				       u8 addr, u8 length, const void *data)
+{
+	return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length);
+}
+
+static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
+	.bustype	= BUS_SPI,
+	.write		= cyttsp_spi_write_block_data,
+	.read		= cyttsp_spi_read_block_data,
+};
+
+static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+{
+	struct cyttsp *ts;
+	int error;
+
+	/* Set up SPI*/
+	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+	spi->mode = SPI_MODE_0;
+	error = spi_setup(spi);
+	if (error < 0) {
+		dev_err(&spi->dev, "%s: SPI setup error %d\n",
+			__func__, error);
+		return error;
+	}
+
+	ts = cyttsp_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
+			  CY_SPI_DATA_BUF_SIZE * 2);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	spi_set_drvdata(spi, ts);
+
+	return 0;
+}
+
+static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+{
+	struct cyttsp *ts = spi_get_drvdata(spi);
+
+	cyttsp_remove(ts);
+
+	return 0;
+}
+
+static struct spi_driver cyttsp_spi_driver = {
+	.driver = {
+		.name	= CY_SPI_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &cyttsp_pm_ops,
+	},
+	.probe  = cyttsp_spi_probe,
+	.remove = __devexit_p(cyttsp_spi_remove),
+};
+
+module_spi_driver(cyttsp_spi_driver);
+
+MODULE_ALIAS("spi:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("spi:cyttsp");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/da9034-ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/da9034-ts.c
new file mode 100644
index 0000000..36b65cf
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/da9034-ts.c
@@ -0,0 +1,387 @@
+/*
+ * Touchscreen driver for Dialog Semiconductor DA9034
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ *	Fengwei Yin <fengwei.yin@marvell.com>
+ *	Bin Yang  <bin.yang@marvell.com>
+ *	Eric Miao <eric.miao@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/mfd/da903x.h>
+#include <linux/slab.h>
+
+#define DA9034_MANUAL_CTRL	0x50
+#define DA9034_LDO_ADC_EN	(1 << 4)
+
+#define DA9034_AUTO_CTRL1	0x51
+
+#define DA9034_AUTO_CTRL2	0x52
+#define DA9034_AUTO_TSI_EN	(1 << 3)
+#define DA9034_PEN_DETECT	(1 << 4)
+
+#define DA9034_TSI_CTRL1	0x53
+#define DA9034_TSI_CTRL2	0x54
+#define DA9034_TSI_X_MSB	0x6c
+#define DA9034_TSI_Y_MSB	0x6d
+#define DA9034_TSI_XY_LSB	0x6e
+
+enum {
+	STATE_IDLE,	/* wait for pendown */
+	STATE_BUSY,	/* TSI busy sampling */
+	STATE_STOP,	/* sample available */
+	STATE_WAIT,	/* Wait to start next sample */
+};
+
+enum {
+	EVENT_PEN_DOWN,
+	EVENT_PEN_UP,
+	EVENT_TSI_READY,
+	EVENT_TIMEDOUT,
+};
+
+struct da9034_touch {
+	struct device		*da9034_dev;
+	struct input_dev	*input_dev;
+
+	struct delayed_work	tsi_work;
+	struct notifier_block	notifier;
+
+	int	state;
+
+	int	interval_ms;
+	int	x_inverted;
+	int	y_inverted;
+
+	int	last_x;
+	int	last_y;
+};
+
+static inline int is_pen_down(struct da9034_touch *touch)
+{
+	return da903x_query_status(touch->da9034_dev, DA9034_STATUS_PEN_DOWN);
+}
+
+static inline int detect_pen_down(struct da9034_touch *touch, int on)
+{
+	if (on)
+		return da903x_set_bits(touch->da9034_dev,
+				DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
+	else
+		return da903x_clr_bits(touch->da9034_dev,
+				DA9034_AUTO_CTRL2, DA9034_PEN_DETECT);
+}
+
+static int read_tsi(struct da9034_touch *touch)
+{
+	uint8_t _x, _y, _v;
+	int ret;
+
+	ret = da903x_read(touch->da9034_dev, DA9034_TSI_X_MSB, &_x);
+	if (ret)
+		return ret;
+
+	ret = da903x_read(touch->da9034_dev, DA9034_TSI_Y_MSB, &_y);
+	if (ret)
+		return ret;
+
+	ret = da903x_read(touch->da9034_dev, DA9034_TSI_XY_LSB, &_v);
+	if (ret)
+		return ret;
+
+	touch->last_x = ((_x << 2) & 0x3fc) | (_v & 0x3);
+	touch->last_y = ((_y << 2) & 0x3fc) | ((_v & 0xc) >> 2);
+
+	return 0;
+}
+
+static inline int start_tsi(struct da9034_touch *touch)
+{
+	return da903x_set_bits(touch->da9034_dev,
+			DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
+}
+
+static inline int stop_tsi(struct da9034_touch *touch)
+{
+	return da903x_clr_bits(touch->da9034_dev,
+			DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN);
+}
+
+static inline void report_pen_down(struct da9034_touch *touch)
+{
+	int x = touch->last_x;
+	int y = touch->last_y;
+
+	x &= 0xfff;
+	if (touch->x_inverted)
+		x = 1024 - x;
+	y &= 0xfff;
+	if (touch->y_inverted)
+		y = 1024 - y;
+
+	input_report_abs(touch->input_dev, ABS_X, x);
+	input_report_abs(touch->input_dev, ABS_Y, y);
+	input_report_key(touch->input_dev, BTN_TOUCH, 1);
+
+	input_sync(touch->input_dev);
+}
+
+static inline void report_pen_up(struct da9034_touch *touch)
+{
+	input_report_key(touch->input_dev, BTN_TOUCH, 0);
+	input_sync(touch->input_dev);
+}
+
+static void da9034_event_handler(struct da9034_touch *touch, int event)
+{
+	int err;
+
+	switch (touch->state) {
+	case STATE_IDLE:
+		if (event != EVENT_PEN_DOWN)
+			break;
+
+		/* Enable auto measurement of the TSI, this will
+		 * automatically disable pen down detection
+		 */
+		err = start_tsi(touch);
+		if (err)
+			goto err_reset;
+
+		touch->state = STATE_BUSY;
+		break;
+
+	case STATE_BUSY:
+		if (event != EVENT_TSI_READY)
+			break;
+
+		err = read_tsi(touch);
+		if (err)
+			goto err_reset;
+
+		/* Disable auto measurement of the TSI, so that
+		 * pen down status will be available
+		 */
+		err = stop_tsi(touch);
+		if (err)
+			goto err_reset;
+
+		touch->state = STATE_STOP;
+
+		/* FIXME: PEN_{UP/DOWN} events are expected to be
+		 * available by stopping TSI, but this is found not
+		 * always true, delay and simulate such an event
+		 * here is more reliable
+		 */
+		mdelay(1);
+		da9034_event_handler(touch,
+				     is_pen_down(touch) ? EVENT_PEN_DOWN :
+							  EVENT_PEN_UP);
+		break;
+
+	case STATE_STOP:
+		if (event == EVENT_PEN_DOWN) {
+			report_pen_down(touch);
+			schedule_delayed_work(&touch->tsi_work,
+				msecs_to_jiffies(touch->interval_ms));
+			touch->state = STATE_WAIT;
+		}
+
+		if (event == EVENT_PEN_UP) {
+			report_pen_up(touch);
+			touch->state = STATE_IDLE;
+		}
+		break;
+
+	case STATE_WAIT:
+		if (event != EVENT_TIMEDOUT)
+			break;
+
+		if (is_pen_down(touch)) {
+			start_tsi(touch);
+			touch->state = STATE_BUSY;
+		} else {
+			report_pen_up(touch);
+			touch->state = STATE_IDLE;
+		}
+		break;
+	}
+	return;
+
+err_reset:
+	touch->state = STATE_IDLE;
+	stop_tsi(touch);
+	detect_pen_down(touch, 1);
+}
+
+static void da9034_tsi_work(struct work_struct *work)
+{
+	struct da9034_touch *touch =
+		container_of(work, struct da9034_touch, tsi_work.work);
+
+	da9034_event_handler(touch, EVENT_TIMEDOUT);
+}
+
+static int da9034_touch_notifier(struct notifier_block *nb,
+				 unsigned long event, void *data)
+{
+	struct da9034_touch *touch =
+		container_of(nb, struct da9034_touch, notifier);
+
+	if (event & DA9034_EVENT_TSI_READY)
+		da9034_event_handler(touch, EVENT_TSI_READY);
+
+	if ((event & DA9034_EVENT_PEN_DOWN) && touch->state == STATE_IDLE)
+		da9034_event_handler(touch, EVENT_PEN_DOWN);
+
+	return 0;
+}
+
+static int da9034_touch_open(struct input_dev *dev)
+{
+	struct da9034_touch *touch = input_get_drvdata(dev);
+	int ret;
+
+	ret = da903x_register_notifier(touch->da9034_dev, &touch->notifier,
+			DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
+	if (ret)
+		return -EBUSY;
+
+	/* Enable ADC LDO */
+	ret = da903x_set_bits(touch->da9034_dev,
+			DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
+	if (ret)
+		return ret;
+
+	/* TSI_DELAY: 3 slots, TSI_SKIP: 3 slots */
+	ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL1, 0x1b);
+	if (ret)
+		return ret;
+
+	ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL2, 0x00);
+	if (ret)
+		return ret;
+
+	touch->state = STATE_IDLE;
+	detect_pen_down(touch, 1);
+
+	return 0;
+}
+
+static void da9034_touch_close(struct input_dev *dev)
+{
+	struct da9034_touch *touch = input_get_drvdata(dev);
+
+	da903x_unregister_notifier(touch->da9034_dev, &touch->notifier,
+			DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY);
+
+	cancel_delayed_work_sync(&touch->tsi_work);
+
+	touch->state = STATE_IDLE;
+	stop_tsi(touch);
+	detect_pen_down(touch, 0);
+
+	/* Disable ADC LDO */
+	da903x_clr_bits(touch->da9034_dev,
+			DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN);
+}
+
+
+static int __devinit da9034_touch_probe(struct platform_device *pdev)
+{
+	struct da9034_touch_pdata *pdata = pdev->dev.platform_data;
+	struct da9034_touch *touch;
+	struct input_dev *input_dev;
+	int ret;
+
+	touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL);
+	if (touch == NULL) {
+		dev_err(&pdev->dev, "failed to allocate driver data\n");
+		return -ENOMEM;
+	}
+
+	touch->da9034_dev = pdev->dev.parent;
+
+	if (pdata) {
+		touch->interval_ms	= pdata->interval_ms;
+		touch->x_inverted	= pdata->x_inverted;
+		touch->y_inverted	= pdata->y_inverted;
+	} else
+		/* fallback into default */
+		touch->interval_ms	= 10;
+
+	INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work);
+	touch->notifier.notifier_call = da9034_touch_notifier;
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(&pdev->dev, "failed to allocate input device\n");
+		ret = -ENOMEM;
+		goto err_free_touch;
+	}
+
+	input_dev->name		= pdev->name;
+	input_dev->open		= da9034_touch_open;
+	input_dev->close	= da9034_touch_close;
+	input_dev->dev.parent	= &pdev->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(ABS_X, input_dev->absbit);
+	__set_bit(ABS_Y, input_dev->absbit);
+	input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	touch->input_dev = input_dev;
+	input_set_drvdata(input_dev, touch);
+
+	ret = input_register_device(input_dev);
+	if (ret)
+		goto err_free_input;
+
+	platform_set_drvdata(pdev, touch);
+	return 0;
+
+err_free_input:
+	input_free_device(input_dev);
+err_free_touch:
+	kfree(touch);
+	return ret;
+}
+
+static int __devexit da9034_touch_remove(struct platform_device *pdev)
+{
+	struct da9034_touch *touch = platform_get_drvdata(pdev);
+
+	input_unregister_device(touch->input_dev);
+	kfree(touch);
+
+	return 0;
+}
+
+static struct platform_driver da9034_touch_driver = {
+	.driver	= {
+		.name	= "da9034-touch",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= da9034_touch_probe,
+	.remove		= __devexit_p(da9034_touch_remove),
+};
+module_platform_driver(da9034_touch_driver);
+
+MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>, Bin Yang <bin.yang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9034-touch");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/dynapro.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/dynapro.c
new file mode 100644
index 0000000..4553539
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/dynapro.c
@@ -0,0 +1,206 @@
+/*
+ * Dynapro serial touchscreen driver
+ *
+ * Copyright (c) 2009 Tias Guns
+ * Based on the inexio driver (c) Vojtech Pavlik and Dan Streetman and
+ * Richard Lemon
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * 2009/09/19 Tias Guns <tias@ulyssis.org>
+ *   Copied inexio.c and edited for Dynapro protocol (from retired Xorg module)
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Dynapro serial touchscreen driver"
+
+MODULE_AUTHOR("Tias Guns <tias@ulyssis.org>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define DYNAPRO_FORMAT_TOUCH_BIT 0x40
+#define DYNAPRO_FORMAT_LENGTH 3
+#define DYNAPRO_RESPONSE_BEGIN_BYTE 0x80
+
+#define DYNAPRO_MIN_XC 0
+#define DYNAPRO_MAX_XC 0x3ff
+#define DYNAPRO_MIN_YC 0
+#define DYNAPRO_MAX_YC 0x3ff
+
+#define DYNAPRO_GET_XC(data) (data[1] | ((data[0] & 0x38) << 4))
+#define DYNAPRO_GET_YC(data) (data[2] | ((data[0] & 0x07) << 7))
+#define DYNAPRO_GET_TOUCHED(data) (DYNAPRO_FORMAT_TOUCH_BIT & data[0])
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct dynapro {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[DYNAPRO_FORMAT_LENGTH];
+	char phys[32];
+};
+
+static void dynapro_process_data(struct dynapro *pdynapro)
+{
+	struct input_dev *dev = pdynapro->dev;
+
+	if (DYNAPRO_FORMAT_LENGTH == ++pdynapro->idx) {
+		input_report_abs(dev, ABS_X, DYNAPRO_GET_XC(pdynapro->data));
+		input_report_abs(dev, ABS_Y, DYNAPRO_GET_YC(pdynapro->data));
+		input_report_key(dev, BTN_TOUCH,
+				 DYNAPRO_GET_TOUCHED(pdynapro->data));
+		input_sync(dev);
+
+		pdynapro->idx = 0;
+	}
+}
+
+static irqreturn_t dynapro_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct dynapro *pdynapro = serio_get_drvdata(serio);
+
+	pdynapro->data[pdynapro->idx] = data;
+
+	if (DYNAPRO_RESPONSE_BEGIN_BYTE & pdynapro->data[0])
+		dynapro_process_data(pdynapro);
+	else
+		dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
+			pdynapro->data[0]);
+
+	return IRQ_HANDLED;
+}
+
+static void dynapro_disconnect(struct serio *serio)
+{
+	struct dynapro *pdynapro = serio_get_drvdata(serio);
+
+	input_get_device(pdynapro->dev);
+	input_unregister_device(pdynapro->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(pdynapro->dev);
+	kfree(pdynapro);
+}
+
+/*
+ * dynapro_connect() is the routine that is called when someone adds a
+ * new serio device that supports dynapro protocol and registers it as
+ * an input device. This is usually accomplished using inputattach.
+ */
+
+static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct dynapro *pdynapro;
+	struct input_dev *input_dev;
+	int err;
+
+	pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!pdynapro || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	pdynapro->serio = serio;
+	pdynapro->dev = input_dev;
+	snprintf(pdynapro->phys, sizeof(pdynapro->phys),
+		 "%s/input0", serio->phys);
+
+	input_dev->name = "Dynapro Serial TouchScreen";
+	input_dev->phys = pdynapro->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_DYNAPRO;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0001;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(pdynapro->dev, ABS_X,
+			     DYNAPRO_MIN_XC, DYNAPRO_MAX_XC, 0, 0);
+	input_set_abs_params(pdynapro->dev, ABS_Y,
+			     DYNAPRO_MIN_YC, DYNAPRO_MAX_YC, 0, 0);
+
+	serio_set_drvdata(serio, pdynapro);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(pdynapro->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(pdynapro);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id dynapro_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_DYNAPRO,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, dynapro_serio_ids);
+
+static struct serio_driver dynapro_drv = {
+	.driver		= {
+		.name	= "dynapro",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= dynapro_serio_ids,
+	.interrupt	= dynapro_interrupt,
+	.connect	= dynapro_connect,
+	.disconnect	= dynapro_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init dynapro_init(void)
+{
+	return serio_register_driver(&dynapro_drv);
+}
+
+static void __exit dynapro_exit(void)
+{
+	serio_unregister_driver(&dynapro_drv);
+}
+
+module_init(dynapro_init);
+module_exit(dynapro_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/eeti_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/eeti_ts.c
new file mode 100644
index 0000000..908407e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/eeti_ts.c
@@ -0,0 +1,332 @@
+/*
+ * Touch Screen driver for EETI's I2C connected touch screen panels
+ *   Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * See EETI's software guide for the protocol specification:
+ *   http://home.eeti.com.tw/web20/eg/guide.htm
+ *
+ * Based on migor_ts.c
+ *   Copyright (c) 2008 Magnus Damm
+ *   Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>
+ *
+ * This file 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 file 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/input/eeti_ts.h>
+#include <linux/slab.h>
+
+static bool flip_x;
+module_param(flip_x, bool, 0644);
+MODULE_PARM_DESC(flip_x, "flip x coordinate");
+
+static bool flip_y;
+module_param(flip_y, bool, 0644);
+MODULE_PARM_DESC(flip_y, "flip y coordinate");
+
+struct eeti_ts_priv {
+	struct i2c_client *client;
+	struct input_dev *input;
+	struct work_struct work;
+	struct mutex mutex;
+	int irq_gpio, irq, irq_active_high;
+};
+
+#define EETI_TS_BITDEPTH	(11)
+#define EETI_MAXVAL		((1 << (EETI_TS_BITDEPTH + 1)) - 1)
+
+#define REPORT_BIT_PRESSED	(1 << 0)
+#define REPORT_BIT_AD0		(1 << 1)
+#define REPORT_BIT_AD1		(1 << 2)
+#define REPORT_BIT_HAS_PRESSURE	(1 << 6)
+#define REPORT_RES_BITS(v)	(((v) >> 1) + EETI_TS_BITDEPTH)
+
+static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
+{
+	return gpio_get_value(priv->irq_gpio) == priv->irq_active_high;
+}
+
+static void eeti_ts_read(struct work_struct *work)
+{
+	char buf[6];
+	unsigned int x, y, res, pressed, to = 100;
+	struct eeti_ts_priv *priv =
+		container_of(work, struct eeti_ts_priv, work);
+
+	mutex_lock(&priv->mutex);
+
+	while (eeti_ts_irq_active(priv) && --to)
+		i2c_master_recv(priv->client, buf, sizeof(buf));
+
+	if (!to) {
+		dev_err(&priv->client->dev,
+			"unable to clear IRQ - line stuck?\n");
+		goto out;
+	}
+
+	/* drop non-report packets */
+	if (!(buf[0] & 0x80))
+		goto out;
+
+	pressed = buf[0] & REPORT_BIT_PRESSED;
+	res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1));
+	x = buf[2] | (buf[1] << 8);
+	y = buf[4] | (buf[3] << 8);
+
+	/* fix the range to 11 bits */
+	x >>= res - EETI_TS_BITDEPTH;
+	y >>= res - EETI_TS_BITDEPTH;
+
+	if (flip_x)
+		x = EETI_MAXVAL - x;
+
+	if (flip_y)
+		y = EETI_MAXVAL - y;
+
+	if (buf[0] & REPORT_BIT_HAS_PRESSURE)
+		input_report_abs(priv->input, ABS_PRESSURE, buf[5]);
+
+	input_report_abs(priv->input, ABS_X, x);
+	input_report_abs(priv->input, ABS_Y, y);
+	input_report_key(priv->input, BTN_TOUCH, !!pressed);
+	input_sync(priv->input);
+
+out:
+	mutex_unlock(&priv->mutex);
+}
+
+static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
+{
+	struct eeti_ts_priv *priv = dev_id;
+
+	 /* postpone I2C transactions as we are atomic */
+	schedule_work(&priv->work);
+
+	return IRQ_HANDLED;
+}
+
+static void eeti_ts_start(struct eeti_ts_priv *priv)
+{
+	enable_irq(priv->irq);
+
+	/* Read the events once to arm the IRQ */
+	eeti_ts_read(&priv->work);
+}
+
+static void eeti_ts_stop(struct eeti_ts_priv *priv)
+{
+	disable_irq(priv->irq);
+	cancel_work_sync(&priv->work);
+}
+
+static int eeti_ts_open(struct input_dev *dev)
+{
+	struct eeti_ts_priv *priv = input_get_drvdata(dev);
+
+	eeti_ts_start(priv);
+
+	return 0;
+}
+
+static void eeti_ts_close(struct input_dev *dev)
+{
+	struct eeti_ts_priv *priv = input_get_drvdata(dev);
+
+	eeti_ts_stop(priv);
+}
+
+static int __devinit eeti_ts_probe(struct i2c_client *client,
+				   const struct i2c_device_id *idp)
+{
+	struct eeti_ts_platform_data *pdata = client->dev.platform_data;
+	struct eeti_ts_priv *priv;
+	struct input_dev *input;
+	unsigned int irq_flags;
+	int err = -ENOMEM;
+
+	/*
+	 * In contrast to what's described in the datasheet, there seems
+	 * to be no way of probing the presence of that device using I2C
+	 * commands. So we need to blindly believe it is there, and wait
+	 * for interrupts to occur.
+	 */
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&client->dev, "failed to allocate driver data\n");
+		goto err0;
+	}
+
+	mutex_init(&priv->mutex);
+	input = input_allocate_device();
+
+	if (!input) {
+		dev_err(&client->dev, "Failed to allocate input device.\n");
+		goto err1;
+	}
+
+	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0);
+
+	input->name = client->name;
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &client->dev;
+	input->open = eeti_ts_open;
+	input->close = eeti_ts_close;
+
+	priv->client = client;
+	priv->input = input;
+	priv->irq_gpio = pdata->irq_gpio;
+	priv->irq = gpio_to_irq(pdata->irq_gpio);
+
+	err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name);
+	if (err < 0)
+		goto err1;
+
+	if (pdata)
+		priv->irq_active_high = pdata->irq_active_high;
+
+	irq_flags = priv->irq_active_high ?
+		IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+
+	INIT_WORK(&priv->work, eeti_ts_read);
+	i2c_set_clientdata(client, priv);
+	input_set_drvdata(input, priv);
+
+	err = input_register_device(input);
+	if (err)
+		goto err2;
+
+	err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
+			  client->name, priv);
+	if (err) {
+		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+		goto err3;
+	}
+
+	/*
+	 * Disable the device for now. It will be enabled once the
+	 * input device is opened.
+	 */
+	eeti_ts_stop(priv);
+
+	device_init_wakeup(&client->dev, 0);
+	return 0;
+
+err3:
+	input_unregister_device(input);
+	input = NULL; /* so we dont try to free it below */
+err2:
+	gpio_free(pdata->irq_gpio);
+err1:
+	input_free_device(input);
+	kfree(priv);
+err0:
+	return err;
+}
+
+static int __devexit eeti_ts_remove(struct i2c_client *client)
+{
+	struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+
+	free_irq(priv->irq, priv);
+	/*
+	 * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it
+	 * so that device still works if we reload the driver.
+	 */
+	enable_irq(priv->irq);
+
+	input_unregister_device(priv->input);
+	kfree(priv);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int eeti_ts_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+	struct input_dev *input_dev = priv->input;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		eeti_ts_stop(priv);
+
+	mutex_unlock(&input_dev->mutex);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(priv->irq);
+
+	return 0;
+}
+
+static int eeti_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+	struct input_dev *input_dev = priv->input;
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(priv->irq);
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		eeti_ts_start(priv);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
+#endif
+
+static const struct i2c_device_id eeti_ts_id[] = {
+	{ "eeti_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
+
+static struct i2c_driver eeti_ts_driver = {
+	.driver = {
+		.name = "eeti_ts",
+#ifdef CONFIG_PM
+		.pm = &eeti_ts_pm,
+#endif
+	},
+	.probe = eeti_ts_probe,
+	.remove = __devexit_p(eeti_ts_remove),
+	.id_table = eeti_ts_id,
+};
+
+module_i2c_driver(eeti_ts_driver);
+
+MODULE_DESCRIPTION("EETI Touchscreen driver");
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/egalax_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/egalax_ts.c
new file mode 100644
index 0000000..70524dd
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/egalax_ts.c
@@ -0,0 +1,292 @@
+/*
+ * Driver for EETI eGalax Multiple Touch Controller
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * based on max11801_ts.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* EETI eGalax serial touch screen controller is a I2C based multiple
+ * touch screen controller, it supports 5 point multiple touch. */
+
+/* TODO:
+  - auto idle mode support
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/input/mt.h>
+
+/*
+ * Mouse Mode: some panel may configure the controller to mouse mode,
+ * which can only report one point at a given time.
+ * This driver will ignore events in this mode.
+ */
+#define REPORT_MODE_MOUSE		0x1
+/*
+ * Vendor Mode: this mode is used to transfer some vendor specific
+ * messages.
+ * This driver will ignore events in this mode.
+ */
+#define REPORT_MODE_VENDOR		0x3
+/* Multiple Touch Mode */
+#define REPORT_MODE_MTTOUCH		0x4
+
+#define MAX_SUPPORT_POINTS		5
+
+#define EVENT_VALID_OFFSET	7
+#define EVENT_VALID_MASK	(0x1 << EVENT_VALID_OFFSET)
+#define EVENT_ID_OFFSET		2
+#define EVENT_ID_MASK		(0xf << EVENT_ID_OFFSET)
+#define EVENT_IN_RANGE		(0x1 << 1)
+#define EVENT_DOWN_UP		(0X1 << 0)
+
+#define MAX_I2C_DATA_LEN	10
+
+#define EGALAX_MAX_X	32760
+#define EGALAX_MAX_Y	32760
+#define EGALAX_MAX_TRIES 100
+
+struct egalax_ts {
+	struct i2c_client		*client;
+	struct input_dev		*input_dev;
+};
+
+static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
+{
+	struct egalax_ts *ts = dev_id;
+	struct input_dev *input_dev = ts->input_dev;
+	struct i2c_client *client = ts->client;
+	u8 buf[MAX_I2C_DATA_LEN];
+	int id, ret, x, y, z;
+	int tries = 0;
+	bool down, valid;
+	u8 state;
+
+	do {
+		ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN);
+	} while (ret == -EAGAIN && tries++ < EGALAX_MAX_TRIES);
+
+	if (ret < 0)
+		return IRQ_HANDLED;
+
+	if (buf[0] != REPORT_MODE_MTTOUCH) {
+		/* ignore mouse events and vendor events */
+		return IRQ_HANDLED;
+	}
+
+	state = buf[1];
+	x = (buf[3] << 8) | buf[2];
+	y = (buf[5] << 8) | buf[4];
+	z = (buf[7] << 8) | buf[6];
+
+	valid = state & EVENT_VALID_MASK;
+	id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET;
+	down = state & EVENT_DOWN_UP;
+
+	if (!valid || id > MAX_SUPPORT_POINTS) {
+		dev_dbg(&client->dev, "point invalid\n");
+		return IRQ_HANDLED;
+	}
+
+	input_mt_slot(input_dev, id);
+	input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down);
+
+	dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d",
+		down ? "down" : "up", id, x, y, z);
+
+	if (down) {
+		input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+		input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+		input_report_abs(input_dev, ABS_MT_PRESSURE, z);
+	}
+
+	input_mt_report_pointer_emulation(input_dev, true);
+	input_sync(input_dev);
+
+	return IRQ_HANDLED;
+}
+
+/* wake up controller by an falling edge of interrupt gpio.  */
+static int egalax_wake_up_device(struct i2c_client *client)
+{
+	int gpio = irq_to_gpio(client->irq);
+	int ret;
+
+	ret = gpio_request(gpio, "egalax_irq");
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"request gpio failed, cannot wake up controller: %d\n",
+			ret);
+		return ret;
+	}
+
+	/* wake up controller via an falling edge on IRQ gpio. */
+	gpio_direction_output(gpio, 0);
+	gpio_set_value(gpio, 1);
+
+	/* controller should be waken up, return irq.  */
+	gpio_direction_input(gpio);
+	gpio_free(gpio);
+
+	return 0;
+}
+
+static int __devinit egalax_firmware_version(struct i2c_client *client)
+{
+	static const u8 cmd[MAX_I2C_DATA_LEN] = { 0x03, 0x03, 0xa, 0x01, 0x41 };
+	int ret;
+
+	ret = i2c_master_send(client, cmd, MAX_I2C_DATA_LEN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int __devinit egalax_ts_probe(struct i2c_client *client,
+				       const struct i2c_device_id *id)
+{
+	struct egalax_ts *ts;
+	struct input_dev *input_dev;
+	int ret;
+	int error;
+
+	ts = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL);
+	if (!ts) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_ts;
+	}
+
+	ts->client = client;
+	ts->input_dev = input_dev;
+
+	/* controller may be in sleep, wake it up. */
+	egalax_wake_up_device(client);
+
+	ret = egalax_firmware_version(client);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to read firmware version\n");
+		error = -EIO;
+		goto err_free_dev;
+	}
+
+	input_dev->name = "EETI eGalax Touch Screen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	input_set_abs_params(input_dev, ABS_X, 0, EGALAX_MAX_X, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, EGALAX_MAX_Y, 0, 0);
+	input_set_abs_params(input_dev,
+			     ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
+	input_set_abs_params(input_dev,
+			     ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0);
+	input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS);
+
+	input_set_drvdata(input_dev, ts);
+
+	error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt,
+				     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				     "egalax_ts", ts);
+	if (error < 0) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_dev;
+	}
+
+	error = input_register_device(ts->input_dev);
+	if (error)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, ts);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, ts);
+err_free_dev:
+	input_free_device(input_dev);
+err_free_ts:
+	kfree(ts);
+
+	return error;
+}
+
+static __devexit int egalax_ts_remove(struct i2c_client *client)
+{
+	struct egalax_ts *ts = i2c_get_clientdata(client);
+
+	free_irq(client->irq, ts);
+
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id egalax_ts_id[] = {
+	{ "egalax_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
+
+#ifdef CONFIG_PM_SLEEP
+static int egalax_ts_suspend(struct device *dev)
+{
+	static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = {
+		0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0
+	};
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = i2c_master_send(client, suspend_cmd, MAX_I2C_DATA_LEN);
+	return ret > 0 ? 0 : ret;
+}
+
+static int egalax_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return egalax_wake_up_device(client);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
+
+static struct i2c_driver egalax_ts_driver = {
+	.driver = {
+		.name	= "egalax_ts",
+		.owner	= THIS_MODULE,
+		.pm	= &egalax_ts_pm_ops,
+	},
+	.id_table	= egalax_ts_id,
+	.probe		= egalax_ts_probe,
+	.remove		= __devexit_p(egalax_ts_remove),
+};
+
+module_i2c_driver(egalax_ts_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Touchscreen driver for EETI eGalax touch controller");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/elo.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/elo.c
new file mode 100644
index 0000000..486d31b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/elo.c
@@ -0,0 +1,423 @@
+/*
+ * Elo serial touchscreen driver
+ *
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * This driver can handle serial Elo touchscreens using either the Elo standard
+ * 'E271-2210' 10-byte protocol, Elo legacy 'E281A-4002' 6-byte protocol, Elo
+ * legacy 'E271-140' 4-byte protocol and Elo legacy 'E261-280' 3-byte protocol.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+
+#define DRIVER_DESC	"Elo serial touchscreen driver"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define ELO_MAX_LENGTH		10
+
+#define ELO10_PACKET_LEN	8
+#define ELO10_TOUCH		0x03
+#define ELO10_PRESSURE		0x80
+
+#define ELO10_LEAD_BYTE		'U'
+
+#define ELO10_ID_CMD		'i'
+
+#define ELO10_TOUCH_PACKET	'T'
+#define ELO10_ACK_PACKET	'A'
+#define ELI10_ID_PACKET		'I'
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct elo {
+	struct input_dev *dev;
+	struct serio *serio;
+	struct mutex cmd_mutex;
+	struct completion cmd_done;
+	int id;
+	int idx;
+	unsigned char expected_packet;
+	unsigned char csum;
+	unsigned char data[ELO_MAX_LENGTH];
+	unsigned char response[ELO10_PACKET_LEN];
+	char phys[32];
+};
+
+static void elo_process_data_10(struct elo *elo, unsigned char data)
+{
+	struct input_dev *dev = elo->dev;
+
+	elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+	case 0:
+		elo->csum = 0xaa;
+		if (data != ELO10_LEAD_BYTE) {
+			dev_dbg(&elo->serio->dev,
+				"unsynchronized data: 0x%02x\n", data);
+			elo->idx = 0;
+		}
+		break;
+
+	case 9:
+		elo->idx = 0;
+		if (data != elo->csum) {
+			dev_dbg(&elo->serio->dev,
+				"bad checksum: 0x%02x, expected 0x%02x\n",
+				 data, elo->csum);
+			break;
+		}
+		if (elo->data[1] != elo->expected_packet) {
+			if (elo->data[1] != ELO10_TOUCH_PACKET)
+				dev_dbg(&elo->serio->dev,
+					"unexpected packet: 0x%02x\n",
+					 elo->data[1]);
+			break;
+		}
+		if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
+			input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
+			input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
+			if (elo->data[2] & ELO10_PRESSURE)
+				input_report_abs(dev, ABS_PRESSURE,
+						(elo->data[8] << 8) | elo->data[7]);
+			input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
+			input_sync(dev);
+		} else if (elo->data[1] == ELO10_ACK_PACKET) {
+			if (elo->data[2] == '0')
+				elo->expected_packet = ELO10_TOUCH_PACKET;
+			complete(&elo->cmd_done);
+		} else {
+			memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
+			elo->expected_packet = ELO10_ACK_PACKET;
+		}
+		break;
+	}
+	elo->csum += data;
+}
+
+static void elo_process_data_6(struct elo *elo, unsigned char data)
+{
+	struct input_dev *dev = elo->dev;
+
+	elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+	case 0:
+		if ((data & 0xc0) != 0xc0)
+			elo->idx = 0;
+		break;
+
+	case 1:
+		if ((data & 0xc0) != 0x80)
+			elo->idx = 0;
+		break;
+
+	case 2:
+		if ((data & 0xc0) != 0x40)
+			elo->idx = 0;
+		break;
+
+	case 3:
+		if (data & 0xc0) {
+			elo->idx = 0;
+			break;
+		}
+
+		input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
+		input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
+
+		if (elo->id == 2) {
+			input_report_key(dev, BTN_TOUCH, 1);
+			input_sync(dev);
+			elo->idx = 0;
+		}
+
+		break;
+
+	case 4:
+		if (data) {
+			input_sync(dev);
+			elo->idx = 0;
+		}
+		break;
+
+	case 5:
+		if ((data & 0xf0) == 0) {
+			input_report_abs(dev, ABS_PRESSURE, elo->data[5]);
+			input_report_key(dev, BTN_TOUCH, !!elo->data[5]);
+		}
+		input_sync(dev);
+		elo->idx = 0;
+		break;
+	}
+}
+
+static void elo_process_data_3(struct elo *elo, unsigned char data)
+{
+	struct input_dev *dev = elo->dev;
+
+	elo->data[elo->idx] = data;
+
+	switch (elo->idx++) {
+
+	case 0:
+		if ((data & 0x7f) != 0x01)
+			elo->idx = 0;
+		break;
+	case 2:
+		input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
+		input_report_abs(dev, ABS_X, elo->data[1]);
+		input_report_abs(dev, ABS_Y, elo->data[2]);
+		input_sync(dev);
+		elo->idx = 0;
+		break;
+	}
+}
+
+static irqreturn_t elo_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct elo *elo = serio_get_drvdata(serio);
+
+	switch (elo->id) {
+	case 0:
+		elo_process_data_10(elo, data);
+		break;
+
+	case 1:
+	case 2:
+		elo_process_data_6(elo, data);
+		break;
+
+	case 3:
+		elo_process_data_3(elo, data);
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int elo_command_10(struct elo *elo, unsigned char *packet)
+{
+	int rc = -1;
+	int i;
+	unsigned char csum = 0xaa + ELO10_LEAD_BYTE;
+
+	mutex_lock(&elo->cmd_mutex);
+
+	serio_pause_rx(elo->serio);
+	elo->expected_packet = toupper(packet[0]);
+	init_completion(&elo->cmd_done);
+	serio_continue_rx(elo->serio);
+
+	if (serio_write(elo->serio, ELO10_LEAD_BYTE))
+		goto out;
+
+	for (i = 0; i < ELO10_PACKET_LEN; i++) {
+		csum += packet[i];
+		if (serio_write(elo->serio, packet[i]))
+			goto out;
+	}
+
+	if (serio_write(elo->serio, csum))
+		goto out;
+
+	wait_for_completion_timeout(&elo->cmd_done, HZ);
+
+	if (elo->expected_packet == ELO10_TOUCH_PACKET) {
+		/* We are back in reporting mode, the command was ACKed */
+		memcpy(packet, elo->response, ELO10_PACKET_LEN);
+		rc = 0;
+	}
+
+ out:
+	mutex_unlock(&elo->cmd_mutex);
+	return rc;
+}
+
+static int elo_setup_10(struct elo *elo)
+{
+	static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" };
+	struct input_dev *dev = elo->dev;
+	unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD };
+
+	if (elo_command_10(elo, packet))
+		return -1;
+
+	dev->id.version = (packet[5] << 8) | packet[4];
+
+	input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0);
+	input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0);
+	if (packet[3] & ELO10_PRESSURE)
+		input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
+
+	dev_info(&elo->serio->dev,
+		 "%sTouch touchscreen, fw: %02x.%02x, features: 0x%02x, controller: 0x%02x\n",
+		 elo_types[(packet[1] -'0') & 0x03],
+		 packet[5], packet[4], packet[3], packet[7]);
+
+	return 0;
+}
+
+/*
+ * elo_disconnect() is the opposite of elo_connect()
+ */
+
+static void elo_disconnect(struct serio *serio)
+{
+	struct elo *elo = serio_get_drvdata(serio);
+
+	input_get_device(elo->dev);
+	input_unregister_device(elo->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(elo->dev);
+	kfree(elo);
+}
+
+/*
+ * elo_connect() is the routine that is called when someone adds a
+ * new serio device that supports Gunze protocol and registers it as
+ * an input device.
+ */
+
+static int elo_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct elo *elo;
+	struct input_dev *input_dev;
+	int err;
+
+	elo = kzalloc(sizeof(struct elo), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!elo || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	elo->serio = serio;
+	elo->id = serio->id.id;
+	elo->dev = input_dev;
+	elo->expected_packet = ELO10_TOUCH_PACKET;
+	mutex_init(&elo->cmd_mutex);
+	init_completion(&elo->cmd_done);
+	snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "Elo Serial TouchScreen";
+	input_dev->phys = elo->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_ELO;
+	input_dev->id.product = elo->id;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	serio_set_drvdata(serio, elo);
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	switch (elo->id) {
+
+	case 0: /* 10-byte protocol */
+		if (elo_setup_10(elo))
+			goto fail3;
+
+		break;
+
+	case 1: /* 6-byte protocol */
+		input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
+
+	case 2: /* 4-byte protocol */
+		input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
+		input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
+		break;
+
+	case 3: /* 3-byte protocol */
+		input_set_abs_params(input_dev, ABS_X, 0, 255, 0, 0);
+		input_set_abs_params(input_dev, ABS_Y, 0, 255, 0, 0);
+		break;
+	}
+
+	err = input_register_device(elo->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3: serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(elo);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id elo_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_ELO,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, elo_serio_ids);
+
+static struct serio_driver elo_drv = {
+	.driver		= {
+		.name	= "elo",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= elo_serio_ids,
+	.interrupt	= elo_interrupt,
+	.connect	= elo_connect,
+	.disconnect	= elo_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init elo_init(void)
+{
+	return serio_register_driver(&elo_drv);
+}
+
+static void __exit elo_exit(void)
+{
+	serio_unregister_driver(&elo_drv);
+}
+
+module_init(elo_init);
+module_exit(elo_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ft6x06_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ft6x06_ts.c
new file mode 100644
index 0000000..6798970
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ft6x06_ts.c
@@ -0,0 +1,143 @@
+/* drivers/input/touchscreen/ft6x06_ts.c 

+* 

+* FocalTech ft6x06 TouchScreen driver. 

+* 

+* Copyright (c) 2010 Focal tech Ltd. 

+* 

+* This software is licensed under the terms of the GNU General Public 

+* License version 2, as published by the Free Software Foundation, and 

+* may be copied, distributed, and modified under those terms. 

+* 

+* This program is distributed in the hope that it will be useful, 

+* but WITHOUT ANY WARRANTY; without even the implied warranty of 

+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

+* GNU General Public License for more details. 

+* 

+*/ 

+#include <linux/i2c.h> 

+#include <linux/input.h> 

+#include <linux/delay.h> 

+#include <linux/slab.h> 

+#include <linux/interrupt.h> 

+#include <mach/irqs.h> 

+#include <linux/kernel.h> 

+#include <linux/semaphore.h> 

+#include <linux/mutex.h> 

+#include <linux/platform_device.h>

+#include <linux/module.h> 

+#include <linux/gpio.h> 

+#include <linux/syscalls.h> 

+#include <linux/unistd.h> 

+#include <linux/uaccess.h> 

+#include <linux/fs.h> 

+#include <linux/string.h> 

+#include <linux/timer.h> 

+#include <linux/of.h> 

+#include <linux/of_gpio.h> 

+#include <linux/irq.h>

+#include <linux/input/touchscreen.h> 

+#include <linux/input/ft6x06_ts.h> 

+

+extern enum touchscreen_type touchscreen_detected_type;

+

+int ft6x06_read_touchdata(struct ts_data *data) 

+{ 

+	struct ts_event *event = data->events; 

+	struct ft6x06_packet buf = {0}; 

+	int ret = -1; 

+	int i; 

+	ret = tp_read(data->client, 0, sizeof(buf), &buf); 

+	if (ret < 0) { 

+		dev_err(&data->client->dev, "%s read touchdata failed.\n", 

+		__func__); 

+		printk("[TP]ft6x06_read_touchdata tp_read failed!\n");

+

+		return ret; 

+	} 

+

+	dev_dbg(&data->input_dev->dev, "detected %d touch events\n", buf.touches); 

+

+	data->touch_points = buf.touches; 

+	if (data->touch_points > CFG_MAX_TOUCH_POINTS) { 

+		dev_err(&data->input_dev->dev, 

+		"touchscreen reports %d points, %d are supported\n", 

+		data->touch_points, CFG_MAX_TOUCH_POINTS); 

+		data->touch_points = CFG_MAX_TOUCH_POINTS; 

+	} 

+

+	for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++) { 

+		event[i].x = ((buf.points[i].xhi & 0xf) << 8); 

+		event[i].x |= buf.points[i].xlo; 

+		event[i].y = ((buf.points[i].yhi & 0xf) << 8); 

+		event[i].y |= buf.points[i].ylo; 

+		event[i].event = buf.points[i].event >> 6; 

+		event[i].id = buf.points[i].id >> 4; 

+		event[i].pressure = FT_PRESS; 

+		//printk("[TP]ft6x06_read_touchdata x= 0x%x, y = 0x%x!\n",event[i].x,event[i].y);

+	} 

+	

+	return 0; 

+} 

+

+static struct touchscreen_operations ft6x06_operations =

+{

+	ft6x06_read_touchdata,

+};

+

+int ft6x06_id_detect(struct i2c_client *client)

+{

+	int ret = 0 ;

+	u8 chip_vendor_id = 0;

+	u8 ctpm_vendor_id = 0;

+	/* allow touch panel controller to boot, before querying it */ 

+	msleep(150); 

+	

+	client->addr = FT_I2C_SLAVE_ADDR;

+	ret = tp_read(client, TP_REG_CHIP_VENDOR_ID, 1, &chip_vendor_id);

+	if(ret < 0)

+	{

+  		client->addr = 0xA7;

+		printk("[TP] ft6x06_id_detect TP_REG_CHIP_VENDOR_ID 0x%x failed\n",client->addr);

+	}

+	

+	ret = tp_read(client, TP_REG_CHIP_VENDOR_ID, 1, &chip_vendor_id);

+	if(ret < 0)

+	{

+		printk("[TP] ft6x06_id_detect TP_REG_CHIP_VENDOR_ID 0x%x failed\n",client->addr);

+     		return -EINVAL;

+	}

+

+	ret = tp_read(client, TP_REG_CTPM_VENDOR_ID, 1, &ctpm_vendor_id);

+	if(ret < 0)

+	{

+		printk("[TP] ft6x06_id_detect TP_REG_CTPM_VENDOR_ID 0x%x failed\n",client->addr);

+     		return -EINVAL;

+	}

+	

+	if((chip_vendor_id == 0x64) &&(ctpm_vendor_id == 0x23))

+	{

+		touchscreen_detected_type = TOUCHSCREEN_FT6X06;

+	}

+	else

+	{

+		return -EINVAL;

+	}

+	

+	touchscreen_set_operations(TOUCHSCREEN_FT6X06, &ft6x06_operations);

+

+	return 0;

+}

+

+static struct touchscreen_register ft6x06_id_register = 

+{

+	ft6x06_id_detect

+};

+

+static int  ft6x06_ts_driver_init()

+{

+	touchscreen_register(TOUCHSCREEN_FT6X06, &ft6x06_id_register);

+	return 0;

+}

+

+subsys_initcall(ft6x06_ts_driver_init);

+

diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/fujitsu_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/fujitsu_ts.c
new file mode 100644
index 0000000..80b2180
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/fujitsu_ts.c
@@ -0,0 +1,189 @@
+/*
+ * Fujitsu serial touchscreen driver
+ *
+ * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Fujitsu serial touchscreen driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define FUJITSU_LENGTH 5
+
+/*
+ * Per-touchscreen data.
+ */
+struct fujitsu {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[FUJITSU_LENGTH];
+	char phys[32];
+};
+
+/*
+ * Decode serial data (5 bytes per packet)
+ * First byte
+ * 1 C 0 0 R S S S
+ * Where C is 1 while in calibration mode (which we don't use)
+ * R is 1 when no coordinate corection was done.
+ * S are button state
+ */
+static irqreturn_t fujitsu_interrupt(struct serio *serio,
+				     unsigned char data, unsigned int flags)
+{
+	struct fujitsu *fujitsu = serio_get_drvdata(serio);
+	struct input_dev *dev = fujitsu->dev;
+
+	if (fujitsu->idx == 0) {
+		/* resync skip until start of frame */
+		if ((data & 0xf0) != 0x80)
+			return IRQ_HANDLED;
+	} else {
+		/* resync skip garbage */
+		if (data & 0x80) {
+			fujitsu->idx = 0;
+			return IRQ_HANDLED;
+		}
+	}
+
+	fujitsu->data[fujitsu->idx++] = data;
+	if (fujitsu->idx == FUJITSU_LENGTH) {
+		input_report_abs(dev, ABS_X,
+				 (fujitsu->data[2] << 7) | fujitsu->data[1]);
+		input_report_abs(dev, ABS_Y,
+				 (fujitsu->data[4] << 7) | fujitsu->data[3]);
+		input_report_key(dev, BTN_TOUCH,
+				 (fujitsu->data[0] & 0x03) != 2);
+		input_sync(dev);
+		fujitsu->idx = 0;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * fujitsu_disconnect() is the opposite of fujitsu_connect()
+ */
+static void fujitsu_disconnect(struct serio *serio)
+{
+	struct fujitsu *fujitsu = serio_get_drvdata(serio);
+
+	input_get_device(fujitsu->dev);
+	input_unregister_device(fujitsu->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(fujitsu->dev);
+	kfree(fujitsu);
+}
+
+/*
+ * fujitsu_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Fujitsu protocol and registers it
+ * as input device.
+ */
+static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct fujitsu *fujitsu;
+	struct input_dev *input_dev;
+	int err;
+
+	fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!fujitsu || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	fujitsu->serio = serio;
+	fujitsu->dev = input_dev;
+	snprintf(fujitsu->phys, sizeof(fujitsu->phys),
+		 "%s/input0", serio->phys);
+
+	input_dev->name = "Fujitsu Serial Touchscreen";
+	input_dev->phys = fujitsu->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_FUJITSU;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0100;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
+	serio_set_drvdata(serio, fujitsu);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(fujitsu->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:
+	serio_close(serio);
+ fail2:
+	serio_set_drvdata(serio, NULL);
+ fail1:
+	input_free_device(input_dev);
+	kfree(fujitsu);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+static struct serio_device_id fujitsu_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_FUJITSU,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
+
+static struct serio_driver fujitsu_drv = {
+	.driver		= {
+		.name	= "fujitsu_ts",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= fujitsu_serio_ids,
+	.interrupt	= fujitsu_interrupt,
+	.connect	= fujitsu_connect,
+	.disconnect	= fujitsu_disconnect,
+};
+
+static int __init fujitsu_init(void)
+{
+	return serio_register_driver(&fujitsu_drv);
+}
+
+static void __exit fujitsu_exit(void)
+{
+	serio_unregister_driver(&fujitsu_drv);
+}
+
+module_init(fujitsu_init);
+module_exit(fujitsu_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/gunze.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/gunze.c
new file mode 100644
index 0000000..a54f90e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/gunze.c
@@ -0,0 +1,204 @@
+/*
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ */
+
+/*
+ * Gunze AHL-51S touchscreen driver for Linux
+ */
+
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Gunze AHL-51S touchscreen driver"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define	GUNZE_MAX_LENGTH	10
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct gunze {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[GUNZE_MAX_LENGTH];
+	char phys[32];
+};
+
+static void gunze_process_packet(struct gunze* gunze)
+{
+	struct input_dev *dev = gunze->dev;
+
+	if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
+		(gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
+		printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data);
+		return;
+	}
+
+	input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
+	input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
+	input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
+	input_sync(dev);
+}
+
+static irqreturn_t gunze_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct gunze* gunze = serio_get_drvdata(serio);
+
+	if (data == '\r') {
+		gunze_process_packet(gunze);
+		gunze->idx = 0;
+	} else {
+		if (gunze->idx < GUNZE_MAX_LENGTH)
+			gunze->data[gunze->idx++] = data;
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * gunze_disconnect() is the opposite of gunze_connect()
+ */
+
+static void gunze_disconnect(struct serio *serio)
+{
+	struct gunze *gunze = serio_get_drvdata(serio);
+
+	input_get_device(gunze->dev);
+	input_unregister_device(gunze->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(gunze->dev);
+	kfree(gunze);
+}
+
+/*
+ * gunze_connect() is the routine that is called when someone adds a
+ * new serio device that supports Gunze protocol and registers it as
+ * an input device.
+ */
+
+static int gunze_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct gunze *gunze;
+	struct input_dev *input_dev;
+	int err;
+
+	gunze = kzalloc(sizeof(struct gunze), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!gunze || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	gunze->serio = serio;
+	gunze->dev = input_dev;
+	snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "Gunze AHL-51S TouchScreen";
+	input_dev->phys = gunze->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_GUNZE;
+	input_dev->id.product = 0x0051;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 24, 1000, 0, 0);
+
+	serio_set_drvdata(serio, gunze);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(gunze->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(gunze);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id gunze_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_GUNZE,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, gunze_serio_ids);
+
+static struct serio_driver gunze_drv = {
+	.driver		= {
+		.name	= "gunze",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= gunze_serio_ids,
+	.interrupt	= gunze_interrupt,
+	.connect	= gunze_connect,
+	.disconnect	= gunze_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init gunze_init(void)
+{
+	return serio_register_driver(&gunze_drv);
+}
+
+static void __exit gunze_exit(void)
+{
+	serio_unregister_driver(&gunze_drv);
+}
+
+module_init(gunze_init);
+module_exit(gunze_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/h3600_ts_input.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/h3600_ts_input.c
new file mode 100644
index 0000000..6107e56
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/h3600_ts_input.c
@@ -0,0 +1,494 @@
+/*
+ *  Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com
+ *
+ *  Sponsored by Transvirtual Technology.
+ *
+ *  Derived from the code in h3600_ts.[ch] by Charles Flynn
+ */
+
+/*
+ * Driver for the h3600 Touch Screen and other Atmel controlled devices.
+ */
+
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so by
+ * e-mail - mail your message to <jsimmons@transvirtual.com>.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+/* SA1100 serial defines */
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+#define DRIVER_DESC	"H3600 touchscreen driver"
+
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+/* The start and end of frame characters SOF and EOF */
+#define CHAR_SOF                0x02
+#define CHAR_EOF                0x03
+#define FRAME_OVERHEAD          3       /* CHAR_SOF,CHAR_EOF,LENGTH = 3 */
+
+/*
+        Atmel events and response IDs contained in frame.
+        Programmer has no control over these numbers.
+        TODO there are holes - specifically  1,7,0x0a
+*/
+#define VERSION_ID              0       /* Get Version (request/response) */
+#define KEYBD_ID                2       /* Keyboard (event) */
+#define TOUCHS_ID               3       /* Touch Screen (event)*/
+#define EEPROM_READ_ID          4       /* (request/response) */
+#define EEPROM_WRITE_ID         5       /* (request/response) */
+#define THERMAL_ID              6       /* (request/response) */
+#define NOTIFY_LED_ID           8       /* (request/response) */
+#define BATTERY_ID              9       /* (request/response) */
+#define SPI_READ_ID             0x0b    /* ( request/response) */
+#define SPI_WRITE_ID            0x0c    /* ( request/response) */
+#define FLITE_ID                0x0d    /* backlight ( request/response) */
+#define STX_ID                  0xa1    /* extension pack status (req/resp) */
+
+#define MAX_ID                  14
+
+#define H3600_MAX_LENGTH 16
+#define H3600_KEY 0xf
+
+#define H3600_SCANCODE_RECORD	1	 /* 1 -> record button */
+#define H3600_SCANCODE_CALENDAR 2	 /* 2 -> calendar */
+#define H3600_SCANCODE_CONTACTS 3	 /* 3 -> contact */
+#define H3600_SCANCODE_Q	4	 /* 4 -> Q button */
+#define	H3600_SCANCODE_START	5	 /* 5 -> start menu */
+#define	H3600_SCANCODE_UP	6	 /* 6 -> up */
+#define H3600_SCANCODE_RIGHT	7	 /* 7 -> right */
+#define H3600_SCANCODE_LEFT	8	 /* 8 -> left */
+#define H3600_SCANCODE_DOWN	9	 /* 9 -> down */
+
+/*
+ * Per-touchscreen data.
+ */
+struct h3600_dev {
+	struct input_dev *dev;
+	struct serio *serio;
+	unsigned char event;	/* event ID from packet */
+	unsigned char chksum;
+	unsigned char len;
+	unsigned char idx;
+	unsigned char buf[H3600_MAX_LENGTH];
+	char phys[32];
+};
+
+static irqreturn_t action_button_handler(int irq, void *dev_id)
+{
+	int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+	struct input_dev *dev = dev_id;
+
+	input_report_key(dev, KEY_ENTER, down);
+	input_sync(dev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t npower_button_handler(int irq, void *dev_id)
+{
+	int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+	struct input_dev *dev = dev_id;
+
+	/*
+	 * This interrupt is only called when we release the key. So we have
+	 * to fake a key press.
+	 */
+	input_report_key(dev, KEY_SUSPEND, 1);
+	input_report_key(dev, KEY_SUSPEND, down);
+	input_sync(dev);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+
+static int flite_brightness = 25;
+
+enum flite_pwr {
+	FLITE_PWR_OFF = 0,
+	FLITE_PWR_ON = 1
+};
+
+/*
+ * h3600_flite_power: enables or disables power to frontlight, using last bright */
+unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
+{
+	unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
+	struct h3600_dev *ts = input_get_drvdata(dev);
+
+	/* Must be in this order */
+	serio_write(ts->serio, 1);
+	serio_write(ts->serio, pwr);
+	serio_write(ts->serio, brightness);
+
+	return 0;
+}
+
+#endif
+
+/*
+ * This function translates the native event packets to linux input event
+ * packets. Some packets coming from serial are not touchscreen related. In
+ * this case we send them off to be processed elsewhere.
+ */
+static void h3600ts_process_packet(struct h3600_dev *ts)
+{
+	struct input_dev *dev = ts->dev;
+	static int touched = 0;
+	int key, down = 0;
+
+	switch (ts->event) {
+		/*
+		   Buttons - returned as a single byte
+			7 6 5 4 3 2 1 0
+			S x x x N N N N
+
+		   S       switch state ( 0=pressed 1=released)
+		   x       Unused.
+		   NNNN    switch number 0-15
+
+		   Note: This is true for non interrupt generated key events.
+		*/
+		case KEYBD_ID:
+			down = (ts->buf[0] & 0x80) ? 0 : 1;
+
+			switch (ts->buf[0] & 0x7f) {
+				case H3600_SCANCODE_RECORD:
+					key = KEY_RECORD;
+					break;
+				case H3600_SCANCODE_CALENDAR:
+					key = KEY_PROG1;
+                                        break;
+				case H3600_SCANCODE_CONTACTS:
+					key = KEY_PROG2;
+					break;
+				case H3600_SCANCODE_Q:
+					key = KEY_Q;
+					break;
+				case H3600_SCANCODE_START:
+					key = KEY_PROG3;
+					break;
+				case H3600_SCANCODE_UP:
+					key = KEY_UP;
+					break;
+				case H3600_SCANCODE_RIGHT:
+					key = KEY_RIGHT;
+					break;
+				case H3600_SCANCODE_LEFT:
+					key = KEY_LEFT;
+					break;
+				case H3600_SCANCODE_DOWN:
+					key = KEY_DOWN;
+					break;
+				default:
+					key = 0;
+			}
+			if (key)
+				input_report_key(dev, key, down);
+			break;
+		/*
+		 * Native touchscreen event data is formatted as shown below:-
+		 *
+		 *      +-------+-------+-------+-------+
+		 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
+		 *      +-------+-------+-------+-------+
+		 *       byte 0    1       2       3
+		 */
+		case TOUCHS_ID:
+			if (!touched) {
+				input_report_key(dev, BTN_TOUCH, 1);
+				touched = 1;
+			}
+
+			if (ts->len) {
+				unsigned short x, y;
+
+				x = ts->buf[0]; x <<= 8; x += ts->buf[1];
+				y = ts->buf[2]; y <<= 8; y += ts->buf[3];
+
+				input_report_abs(dev, ABS_X, x);
+				input_report_abs(dev, ABS_Y, y);
+			} else {
+				input_report_key(dev, BTN_TOUCH, 0);
+				touched = 0;
+			}
+			break;
+		default:
+			/* Send a non input event elsewhere */
+			break;
+	}
+
+	input_sync(dev);
+}
+
+/*
+ * h3600ts_event() handles events from the input module.
+ */
+static int h3600ts_event(struct input_dev *dev, unsigned int type,
+			 unsigned int code, int value)
+{
+#if 0
+	struct h3600_dev *ts = input_get_drvdata(dev);
+
+	switch (type) {
+		case EV_LED: {
+		//	serio_write(ts->serio, SOME_CMD);
+			return 0;
+		}
+	}
+	return -1;
+#endif
+	return 0;
+}
+
+/*
+        Frame format
+  byte    1       2               3              len + 4
+        +-------+---------------+---------------+--=------------+
+        |SOF    |id     |len    | len bytes     | Chksum        |
+        +-------+---------------+---------------+--=------------+
+  bit   0     7  8    11 12   15 16
+
+        +-------+---------------+-------+
+        |SOF    |id     |0      |Chksum | - Note Chksum does not include SOF
+        +-------+---------------+-------+
+  bit   0     7  8    11 12   15 16
+
+*/
+
+static int state;
+
+/* decode States  */
+#define STATE_SOF       0       /* start of FRAME */
+#define STATE_ID        1       /* state where we decode the ID & len */
+#define STATE_DATA      2       /* state where we decode data */
+#define STATE_EOF       3       /* state where we decode checksum or EOF */
+
+static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
+                                     unsigned int flags)
+{
+	struct h3600_dev *ts = serio_get_drvdata(serio);
+
+	/*
+	 * We have a new frame coming in.
+	 */
+	switch (state) {
+		case STATE_SOF:
+			if (data == CHAR_SOF)
+				state = STATE_ID;
+			break;
+		case STATE_ID:
+			ts->event = (data & 0xf0) >> 4;
+			ts->len = (data & 0xf);
+			ts->idx = 0;
+			if (ts->event >= MAX_ID) {
+				state = STATE_SOF;
+				break;
+			}
+			ts->chksum = data;
+			state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
+			break;
+		case STATE_DATA:
+			ts->chksum += data;
+			ts->buf[ts->idx]= data;
+			if (++ts->idx == ts->len)
+				state = STATE_EOF;
+			break;
+		case STATE_EOF:
+			state = STATE_SOF;
+			if (data == CHAR_EOF || data == ts->chksum)
+				h3600ts_process_packet(ts);
+			break;
+		default:
+			printk("Error3\n");
+			break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * h3600ts_connect() is the routine that is called when someone adds a
+ * new serio device that supports H3600 protocol and registers it as
+ * an input device.
+ */
+static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct h3600_dev *ts;
+	struct input_dev *input_dev;
+	int err;
+
+	ts = kzalloc(sizeof(struct h3600_dev), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	ts->serio = serio;
+	ts->dev = input_dev;
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "H3600 TouchScreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_H3600;
+	input_dev->id.product = 0x0666;  /* FIXME !!! We can ask the hardware */
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+
+	input_set_drvdata(input_dev, ts);
+
+	input_dev->event = h3600ts_event;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
+		BIT_MASK(EV_LED) | BIT_MASK(EV_PWR);
+	input_dev->ledbit[0] = BIT_MASK(LED_SLEEP);
+	input_set_abs_params(input_dev, ABS_X, 60, 985, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 35, 1024, 0, 0);
+
+	set_bit(KEY_RECORD, input_dev->keybit);
+	set_bit(KEY_Q, input_dev->keybit);
+	set_bit(KEY_PROG1, input_dev->keybit);
+	set_bit(KEY_PROG2, input_dev->keybit);
+	set_bit(KEY_PROG3, input_dev->keybit);
+	set_bit(KEY_UP, input_dev->keybit);
+	set_bit(KEY_RIGHT, input_dev->keybit);
+	set_bit(KEY_LEFT, input_dev->keybit);
+	set_bit(KEY_DOWN, input_dev->keybit);
+	set_bit(KEY_ENTER, input_dev->keybit);
+	set_bit(KEY_SUSPEND, input_dev->keybit);
+	set_bit(BTN_TOUCH, input_dev->keybit);
+
+	/* Device specific stuff */
+	set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
+	set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
+
+	if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
+			IRQF_SHARED, "h3600_action", ts->dev)) {
+		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
+		err = -EBUSY;
+		goto fail1;
+	}
+
+	if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
+			IRQF_SHARED, "h3600_suspend", ts->dev)) {
+		printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
+		err = -EBUSY;
+		goto fail2;
+	}
+
+	serio_set_drvdata(serio, ts);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail3;
+
+	//h3600_flite_control(1, 25);     /* default brightness */
+	err = input_register_device(ts->dev);
+	if (err)
+		goto fail4;
+
+	return 0;
+
+fail4:	serio_close(serio);
+fail3:	serio_set_drvdata(serio, NULL);
+	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
+fail2:	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
+fail1:	input_free_device(input_dev);
+	kfree(ts);
+	return err;
+}
+
+/*
+ * h3600ts_disconnect() is the opposite of h3600ts_connect()
+ */
+
+static void h3600ts_disconnect(struct serio *serio)
+{
+	struct h3600_dev *ts = serio_get_drvdata(serio);
+
+	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
+	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
+	input_get_device(ts->dev);
+	input_unregister_device(ts->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(ts->dev);
+	kfree(ts);
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id h3600ts_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_H3600,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids);
+
+static struct serio_driver h3600ts_drv = {
+	.driver		= {
+		.name	= "h3600ts",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= h3600ts_serio_ids,
+	.interrupt	= h3600ts_interrupt,
+	.connect	= h3600ts_connect,
+	.disconnect	= h3600ts_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init h3600ts_init(void)
+{
+	return serio_register_driver(&h3600ts_drv);
+}
+
+static void __exit h3600ts_exit(void)
+{
+	serio_unregister_driver(&h3600ts_drv);
+}
+
+module_init(h3600ts_init);
+module_exit(h3600ts_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/hampshire.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/hampshire.c
new file mode 100644
index 0000000..2da6cc3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/hampshire.c
@@ -0,0 +1,205 @@
+/*
+ * Hampshire serial touchscreen driver
+ *
+ * Copyright (c) 2010 Adam Bennett
+ * Based on the dynapro driver (c) Tias Guns
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * 2010/04/08 Adam Bennett <abennett72@gmail.com>
+ *   Copied dynapro.c and edited for Hampshire 4-byte protocol
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Hampshire serial touchscreen driver"
+
+MODULE_AUTHOR("Adam Bennett <abennett72@gmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define HAMPSHIRE_FORMAT_TOUCH_BIT 0x40
+#define HAMPSHIRE_FORMAT_LENGTH 4
+#define HAMPSHIRE_RESPONSE_BEGIN_BYTE 0x80
+
+#define HAMPSHIRE_MIN_XC 0
+#define HAMPSHIRE_MAX_XC 0x1000
+#define HAMPSHIRE_MIN_YC 0
+#define HAMPSHIRE_MAX_YC 0x1000
+
+#define HAMPSHIRE_GET_XC(data) (((data[3] & 0x0c) >> 2) | (data[1] << 2) | ((data[0] & 0x38) << 6))
+#define HAMPSHIRE_GET_YC(data) ((data[3] & 0x03) | (data[2] << 2) | ((data[0] & 0x07) << 9))
+#define HAMPSHIRE_GET_TOUCHED(data) (HAMPSHIRE_FORMAT_TOUCH_BIT & data[0])
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct hampshire {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[HAMPSHIRE_FORMAT_LENGTH];
+	char phys[32];
+};
+
+static void hampshire_process_data(struct hampshire *phampshire)
+{
+	struct input_dev *dev = phampshire->dev;
+
+	if (HAMPSHIRE_FORMAT_LENGTH == ++phampshire->idx) {
+		input_report_abs(dev, ABS_X, HAMPSHIRE_GET_XC(phampshire->data));
+		input_report_abs(dev, ABS_Y, HAMPSHIRE_GET_YC(phampshire->data));
+		input_report_key(dev, BTN_TOUCH,
+				 HAMPSHIRE_GET_TOUCHED(phampshire->data));
+		input_sync(dev);
+
+		phampshire->idx = 0;
+	}
+}
+
+static irqreturn_t hampshire_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct hampshire *phampshire = serio_get_drvdata(serio);
+
+	phampshire->data[phampshire->idx] = data;
+
+	if (HAMPSHIRE_RESPONSE_BEGIN_BYTE & phampshire->data[0])
+		hampshire_process_data(phampshire);
+	else
+		dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
+			phampshire->data[0]);
+
+	return IRQ_HANDLED;
+}
+
+static void hampshire_disconnect(struct serio *serio)
+{
+	struct hampshire *phampshire = serio_get_drvdata(serio);
+
+	input_get_device(phampshire->dev);
+	input_unregister_device(phampshire->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(phampshire->dev);
+	kfree(phampshire);
+}
+
+/*
+ * hampshire_connect() is the routine that is called when someone adds a
+ * new serio device that supports hampshire protocol and registers it as
+ * an input device. This is usually accomplished using inputattach.
+ */
+
+static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct hampshire *phampshire;
+	struct input_dev *input_dev;
+	int err;
+
+	phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!phampshire || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	phampshire->serio = serio;
+	phampshire->dev = input_dev;
+	snprintf(phampshire->phys, sizeof(phampshire->phys),
+		 "%s/input0", serio->phys);
+
+	input_dev->name = "Hampshire Serial TouchScreen";
+	input_dev->phys = phampshire->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_HAMPSHIRE;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0001;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(phampshire->dev, ABS_X,
+			     HAMPSHIRE_MIN_XC, HAMPSHIRE_MAX_XC, 0, 0);
+	input_set_abs_params(phampshire->dev, ABS_Y,
+			     HAMPSHIRE_MIN_YC, HAMPSHIRE_MAX_YC, 0, 0);
+
+	serio_set_drvdata(serio, phampshire);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(phampshire->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(phampshire);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id hampshire_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_HAMPSHIRE,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, hampshire_serio_ids);
+
+static struct serio_driver hampshire_drv = {
+	.driver		= {
+		.name	= "hampshire",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= hampshire_serio_ids,
+	.interrupt	= hampshire_interrupt,
+	.connect	= hampshire_connect,
+	.disconnect	= hampshire_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init hampshire_init(void)
+{
+	return serio_register_driver(&hampshire_drv);
+}
+
+static void __exit hampshire_exit(void)
+{
+	serio_unregister_driver(&hampshire_drv);
+}
+
+module_init(hampshire_init);
+module_exit(hampshire_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/hp680_ts_input.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/hp680_ts_input.c
new file mode 100644
index 0000000..85cf9be
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/hp680_ts_input.c
@@ -0,0 +1,127 @@
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/adc.h>
+#include <mach/hp6xx.h>
+
+#define MODNAME "hp680_ts_input"
+
+#define HP680_TS_ABS_X_MIN	40
+#define HP680_TS_ABS_X_MAX	950
+#define HP680_TS_ABS_Y_MIN	80
+#define HP680_TS_ABS_Y_MAX	910
+
+#define	PHDR	0xa400012e
+#define SCPDR	0xa4000136
+
+static void do_softint(struct work_struct *work);
+
+static struct input_dev *hp680_ts_dev;
+static DECLARE_DELAYED_WORK(work, do_softint);
+
+static void do_softint(struct work_struct *work)
+{
+	int absx = 0, absy = 0;
+	u8 scpdr;
+	int touched = 0;
+
+	if (__raw_readb(PHDR) & PHDR_TS_PEN_DOWN) {
+		scpdr = __raw_readb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_ENABLE;
+		scpdr &= ~SCPDR_TS_SCAN_Y;
+		__raw_writeb(scpdr, SCPDR);
+		udelay(30);
+
+		absy = adc_single(ADC_CHANNEL_TS_Y);
+
+		scpdr = __raw_readb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_Y;
+		scpdr &= ~SCPDR_TS_SCAN_X;
+		__raw_writeb(scpdr, SCPDR);
+		udelay(30);
+
+		absx = adc_single(ADC_CHANNEL_TS_X);
+
+		scpdr = __raw_readb(SCPDR);
+		scpdr |= SCPDR_TS_SCAN_X;
+		scpdr &= ~SCPDR_TS_SCAN_ENABLE;
+		__raw_writeb(scpdr, SCPDR);
+		udelay(100);
+		touched = __raw_readb(PHDR) & PHDR_TS_PEN_DOWN;
+	}
+
+	if (touched) {
+		input_report_key(hp680_ts_dev, BTN_TOUCH, 1);
+		input_report_abs(hp680_ts_dev, ABS_X, absx);
+		input_report_abs(hp680_ts_dev, ABS_Y, absy);
+	} else {
+		input_report_key(hp680_ts_dev, BTN_TOUCH, 0);
+	}
+
+	input_sync(hp680_ts_dev);
+	enable_irq(HP680_TS_IRQ);
+}
+
+static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
+{
+	disable_irq_nosync(irq);
+	schedule_delayed_work(&work, HZ / 20);
+
+	return IRQ_HANDLED;
+}
+
+static int __init hp680_ts_init(void)
+{
+	int err;
+
+	hp680_ts_dev = input_allocate_device();
+	if (!hp680_ts_dev)
+		return -ENOMEM;
+
+	hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
+	hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(hp680_ts_dev, ABS_X,
+		HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
+	input_set_abs_params(hp680_ts_dev, ABS_Y,
+		HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
+
+	hp680_ts_dev->name = "HP Jornada touchscreen";
+	hp680_ts_dev->phys = "hp680_ts/input0";
+
+	if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
+			0, MODNAME, NULL) < 0) {
+		printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
+		       HP680_TS_IRQ);
+		err = -EBUSY;
+		goto fail1;
+	}
+
+	err = input_register_device(hp680_ts_dev);
+	if (err)
+		goto fail2;
+
+	return 0;
+
+ fail2:	free_irq(HP680_TS_IRQ, NULL);
+	cancel_delayed_work_sync(&work);
+ fail1:	input_free_device(hp680_ts_dev);
+	return err;
+}
+
+static void __exit hp680_ts_exit(void)
+{
+	free_irq(HP680_TS_IRQ, NULL);
+	cancel_delayed_work_sync(&work);
+	input_unregister_device(hp680_ts_dev);
+}
+
+module_init(hp680_ts_init);
+module_exit(hp680_ts_exit);
+
+MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
+MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/htcpen.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/htcpen.c
new file mode 100644
index 0000000..d13143b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/htcpen.c
@@ -0,0 +1,250 @@
+/*
+ * HTC Shift touchscreen driver
+ *
+ * Copyright (C) 2008 Pau Oliva Fora <pof@eslack.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/isa.h>
+#include <linux/ioport.h>
+#include <linux/dmi.h>
+
+MODULE_AUTHOR("Pau Oliva Fora <pau@eslack.org>");
+MODULE_DESCRIPTION("HTC Shift touchscreen driver");
+MODULE_LICENSE("GPL");
+
+#define HTCPEN_PORT_IRQ_CLEAR	0x068
+#define HTCPEN_PORT_INIT	0x06c
+#define HTCPEN_PORT_INDEX	0x0250
+#define HTCPEN_PORT_DATA	0x0251
+#define HTCPEN_IRQ		3
+
+#define DEVICE_ENABLE		0xa2
+#define DEVICE_DISABLE		0xa3
+
+#define X_INDEX			3
+#define Y_INDEX			5
+#define TOUCH_INDEX		0xb
+#define LSB_XY_INDEX		0xc
+#define X_AXIS_MAX		2040
+#define Y_AXIS_MAX		2040
+
+static bool invert_x;
+module_param(invert_x, bool, 0644);
+MODULE_PARM_DESC(invert_x, "If set, X axis is inverted");
+static bool invert_y;
+module_param(invert_y, bool, 0644);
+MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted");
+
+static irqreturn_t htcpen_interrupt(int irq, void *handle)
+{
+	struct input_dev *htcpen_dev = handle;
+	unsigned short x, y, xy;
+
+	/* 0 = press; 1 = release */
+	outb_p(TOUCH_INDEX, HTCPEN_PORT_INDEX);
+
+	if (inb_p(HTCPEN_PORT_DATA)) {
+		input_report_key(htcpen_dev, BTN_TOUCH, 0);
+	} else {
+		outb_p(X_INDEX, HTCPEN_PORT_INDEX);
+		x = inb_p(HTCPEN_PORT_DATA);
+
+		outb_p(Y_INDEX, HTCPEN_PORT_INDEX);
+		y = inb_p(HTCPEN_PORT_DATA);
+
+		outb_p(LSB_XY_INDEX, HTCPEN_PORT_INDEX);
+		xy = inb_p(HTCPEN_PORT_DATA);
+
+		/* get high resolution value of X and Y using LSB */
+		x = X_AXIS_MAX - ((x * 8) + ((xy >> 4) & 0xf));
+		y = (y * 8) + (xy & 0xf);
+		if (invert_x)
+			x = X_AXIS_MAX - x;
+		if (invert_y)
+			y = Y_AXIS_MAX - y;
+
+		if (x != X_AXIS_MAX && x != 0) {
+			input_report_key(htcpen_dev, BTN_TOUCH, 1);
+			input_report_abs(htcpen_dev, ABS_X, x);
+			input_report_abs(htcpen_dev, ABS_Y, y);
+		}
+	}
+
+	input_sync(htcpen_dev);
+
+	inb_p(HTCPEN_PORT_IRQ_CLEAR);
+
+	return IRQ_HANDLED;
+}
+
+static int htcpen_open(struct input_dev *dev)
+{
+	outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);
+
+	return 0;
+}
+
+static void htcpen_close(struct input_dev *dev)
+{
+	outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);
+	synchronize_irq(HTCPEN_IRQ);
+}
+
+static int __devinit htcpen_isa_probe(struct device *dev, unsigned int id)
+{
+	struct input_dev *htcpen_dev;
+	int err = -EBUSY;
+
+	if (!request_region(HTCPEN_PORT_IRQ_CLEAR, 1, "htcpen")) {
+		printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
+			HTCPEN_PORT_IRQ_CLEAR);
+		goto request_region1_failed;
+	}
+
+	if (!request_region(HTCPEN_PORT_INIT, 1, "htcpen")) {
+		printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
+			HTCPEN_PORT_INIT);
+		goto request_region2_failed;
+	}
+
+	if (!request_region(HTCPEN_PORT_INDEX, 2, "htcpen")) {
+		printk(KERN_ERR "htcpen: unable to get IO region 0x%x\n",
+			HTCPEN_PORT_INDEX);
+		goto request_region3_failed;
+	}
+
+	htcpen_dev = input_allocate_device();
+	if (!htcpen_dev) {
+		printk(KERN_ERR "htcpen: can't allocate device\n");
+		err = -ENOMEM;
+		goto input_alloc_failed;
+	}
+
+	htcpen_dev->name = "HTC Shift EC TouchScreen";
+	htcpen_dev->id.bustype = BUS_ISA;
+
+	htcpen_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
+	htcpen_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(htcpen_dev, ABS_X, 0, X_AXIS_MAX, 0, 0);
+	input_set_abs_params(htcpen_dev, ABS_Y, 0, Y_AXIS_MAX, 0, 0);
+
+	htcpen_dev->open = htcpen_open;
+	htcpen_dev->close = htcpen_close;
+
+	err = request_irq(HTCPEN_IRQ, htcpen_interrupt, 0, "htcpen",
+			htcpen_dev);
+	if (err) {
+		printk(KERN_ERR "htcpen: irq busy\n");
+		goto request_irq_failed;
+	}
+
+	inb_p(HTCPEN_PORT_IRQ_CLEAR);
+
+	err = input_register_device(htcpen_dev);
+	if (err)
+		goto input_register_failed;
+
+	dev_set_drvdata(dev, htcpen_dev);
+
+	return 0;
+
+ input_register_failed:
+	free_irq(HTCPEN_IRQ, htcpen_dev);
+ request_irq_failed:
+	input_free_device(htcpen_dev);
+ input_alloc_failed:
+	release_region(HTCPEN_PORT_INDEX, 2);
+ request_region3_failed:
+	release_region(HTCPEN_PORT_INIT, 1);
+ request_region2_failed:
+	release_region(HTCPEN_PORT_IRQ_CLEAR, 1);
+ request_region1_failed:
+	return err;
+}
+
+static int __devexit htcpen_isa_remove(struct device *dev, unsigned int id)
+{
+	struct input_dev *htcpen_dev = dev_get_drvdata(dev);
+
+	input_unregister_device(htcpen_dev);
+
+	free_irq(HTCPEN_IRQ, htcpen_dev);
+
+	release_region(HTCPEN_PORT_INDEX, 2);
+	release_region(HTCPEN_PORT_INIT, 1);
+	release_region(HTCPEN_PORT_IRQ_CLEAR, 1);
+
+	dev_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int htcpen_isa_suspend(struct device *dev, unsigned int n,
+				pm_message_t state)
+{
+	outb_p(DEVICE_DISABLE, HTCPEN_PORT_INIT);
+
+	return 0;
+}
+
+static int htcpen_isa_resume(struct device *dev, unsigned int n)
+{
+	outb_p(DEVICE_ENABLE, HTCPEN_PORT_INIT);
+
+	return 0;
+}
+#endif
+
+static struct isa_driver htcpen_isa_driver = {
+	.probe		= htcpen_isa_probe,
+	.remove		= __devexit_p(htcpen_isa_remove),
+#ifdef CONFIG_PM
+	.suspend	= htcpen_isa_suspend,
+	.resume		= htcpen_isa_resume,
+#endif
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "htcpen",
+	}
+};
+
+static struct dmi_system_id __initdata htcshift_dmi_table[] = {
+	{
+		.ident = "Shift",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "High Tech Computer Corp"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Shift"),
+		},
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(dmi, htcshift_dmi_table);
+
+static int __init htcpen_isa_init(void)
+{
+	if (!dmi_check_system(htcshift_dmi_table))
+		return -ENODEV;
+
+	return isa_register_driver(&htcpen_isa_driver, 1);
+}
+
+static void __exit htcpen_isa_exit(void)
+{
+	isa_unregister_driver(&htcpen_isa_driver);
+}
+
+module_init(htcpen_isa_init);
+module_exit(htcpen_isa_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ili210x.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ili210x.c
new file mode 100644
index 0000000..c004417
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ili210x.c
@@ -0,0 +1,360 @@
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/input/ili210x.h>
+
+#define MAX_TOUCHES		2
+#define DEFAULT_POLL_PERIOD	20
+
+/* Touchscreen commands */
+#define REG_TOUCHDATA		0x10
+#define REG_PANEL_INFO		0x20
+#define REG_FIRMWARE_VERSION	0x40
+#define REG_CALIBRATE		0xcc
+
+struct finger {
+	u8 x_low;
+	u8 x_high;
+	u8 y_low;
+	u8 y_high;
+} __packed;
+
+struct touchdata {
+	u8 status;
+	struct finger finger[MAX_TOUCHES];
+} __packed;
+
+struct panel_info {
+	struct finger finger_max;
+	u8 xchannel_num;
+	u8 ychannel_num;
+} __packed;
+
+struct firmware_version {
+	u8 id;
+	u8 major;
+	u8 minor;
+} __packed;
+
+struct ili210x {
+	struct i2c_client *client;
+	struct input_dev *input;
+	bool (*get_pendown_state)(void);
+	unsigned int poll_period;
+	struct delayed_work dwork;
+};
+
+static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
+			    size_t len)
+{
+	struct i2c_msg msg[2] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0,
+			.len	= 1,
+			.buf	= &reg,
+		},
+		{
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.len	= len,
+			.buf	= buf,
+		}
+	};
+
+	if (i2c_transfer(client->adapter, msg, 2) != 2) {
+		dev_err(&client->dev, "i2c transfer failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void ili210x_report_events(struct input_dev *input,
+				  const struct touchdata *touchdata)
+{
+	int i;
+	bool touch;
+	unsigned int x, y;
+	const struct finger *finger;
+
+	for (i = 0; i < MAX_TOUCHES; i++) {
+		input_mt_slot(input, i);
+
+		finger = &touchdata->finger[i];
+
+		touch = touchdata->status & (1 << i);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+		if (touch) {
+			x = finger->x_low | (finger->x_high << 8);
+			y = finger->y_low | (finger->y_high << 8);
+
+			input_report_abs(input, ABS_MT_POSITION_X, x);
+			input_report_abs(input, ABS_MT_POSITION_Y, y);
+		}
+	}
+
+	input_mt_report_pointer_emulation(input, false);
+	input_sync(input);
+}
+
+static bool get_pendown_state(const struct ili210x *priv)
+{
+	bool state = false;
+
+	if (priv->get_pendown_state)
+		state = priv->get_pendown_state();
+
+	return state;
+}
+
+static void ili210x_work(struct work_struct *work)
+{
+	struct ili210x *priv = container_of(work, struct ili210x,
+					    dwork.work);
+	struct i2c_client *client = priv->client;
+	struct touchdata touchdata;
+	int error;
+
+	error = ili210x_read_reg(client, REG_TOUCHDATA,
+				 &touchdata, sizeof(touchdata));
+	if (error) {
+		dev_err(&client->dev,
+			"Unable to get touchdata, err = %d\n", error);
+		return;
+	}
+
+	ili210x_report_events(priv->input, &touchdata);
+
+	if ((touchdata.status & 0xf3) || get_pendown_state(priv))
+		schedule_delayed_work(&priv->dwork,
+				      msecs_to_jiffies(priv->poll_period));
+}
+
+static irqreturn_t ili210x_irq(int irq, void *irq_data)
+{
+	struct ili210x *priv = irq_data;
+
+	schedule_delayed_work(&priv->dwork, 0);
+
+	return IRQ_HANDLED;
+}
+
+static ssize_t ili210x_calibrate(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ili210x *priv = i2c_get_clientdata(client);
+	unsigned long calibrate;
+	int rc;
+	u8 cmd = REG_CALIBRATE;
+
+	if (kstrtoul(buf, 10, &calibrate))
+		return -EINVAL;
+
+	if (calibrate > 1)
+		return -EINVAL;
+
+	if (calibrate) {
+		rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
+		if (rc != sizeof(cmd))
+			return -EIO;
+	}
+
+	return count;
+}
+static DEVICE_ATTR(calibrate, 0644, NULL, ili210x_calibrate);
+
+static struct attribute *ili210x_attributes[] = {
+	&dev_attr_calibrate.attr,
+	NULL,
+};
+
+static const struct attribute_group ili210x_attr_group = {
+	.attrs = ili210x_attributes,
+};
+
+static int __devinit ili210x_i2c_probe(struct i2c_client *client,
+				       const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	const struct ili210x_platform_data *pdata = dev->platform_data;
+	struct ili210x *priv;
+	struct input_dev *input;
+	struct panel_info panel;
+	struct firmware_version firmware;
+	int xmax, ymax;
+	int error;
+
+	dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
+
+	if (!pdata) {
+		dev_err(dev, "No platform data!\n");
+		return -EINVAL;
+	}
+
+	if (client->irq <= 0) {
+		dev_err(dev, "No IRQ!\n");
+		return -EINVAL;
+	}
+
+	/* Get firmware version */
+	error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
+				 &firmware, sizeof(firmware));
+	if (error) {
+		dev_err(dev, "Failed to get firmware version, err: %d\n",
+			error);
+		return error;
+	}
+
+	/* get panel info */
+	error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
+	if (error) {
+		dev_err(dev, "Failed to get panel informations, err: %d\n",
+			error);
+		return error;
+	}
+
+	xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
+	ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!priv || !input) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	priv->client = client;
+	priv->input = input;
+	priv->get_pendown_state = pdata->get_pendown_state;
+	priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
+	INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
+
+	/* Setup input device */
+	input->name = "ILI210x Touchscreen";
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = dev;
+
+	__set_bit(EV_SYN, input->evbit);
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+
+	/* Single touch */
+	input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
+
+	/* Multi touch */
+	input_mt_init_slots(input, MAX_TOUCHES);
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
+
+	input_set_drvdata(input, priv);
+	i2c_set_clientdata(client, priv);
+
+	error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
+			    client->name, priv);
+	if (error) {
+		dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
+			error);
+		goto err_free_mem;
+	}
+
+	error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
+	if (error) {
+		dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
+			error);
+		goto err_free_irq;
+	}
+
+	error = input_register_device(priv->input);
+	if (error) {
+		dev_err(dev, "Cannot regiser input device, err: %d\n", error);
+		goto err_remove_sysfs;
+	}
+
+	device_init_wakeup(&client->dev, 1);
+
+	dev_dbg(dev,
+		"ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
+		client->irq, firmware.id, firmware.major, firmware.minor);
+
+	return 0;
+
+err_remove_sysfs:
+	sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
+err_free_irq:
+	free_irq(client->irq, priv);
+err_free_mem:
+	input_free_device(input);
+	kfree(priv);
+	return error;
+}
+
+static int __devexit ili210x_i2c_remove(struct i2c_client *client)
+{
+	struct ili210x *priv = i2c_get_clientdata(client);
+
+	sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
+	free_irq(priv->client->irq, priv);
+	cancel_delayed_work_sync(&priv->dwork);
+	input_unregister_device(priv->input);
+	kfree(priv);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ili210x_i2c_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(client->irq);
+
+	return 0;
+}
+
+static int ili210x_i2c_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(client->irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
+			 ili210x_i2c_suspend, ili210x_i2c_resume);
+
+static const struct i2c_device_id ili210x_i2c_id[] = {
+	{ "ili210x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
+
+static struct i2c_driver ili210x_ts_driver = {
+	.driver = {
+		.name = "ili210x_i2c",
+		.owner = THIS_MODULE,
+		.pm = &ili210x_i2c_pm,
+	},
+	.id_table = ili210x_i2c_id,
+	.probe = ili210x_i2c_probe,
+	.remove = __devexit_p(ili210x_i2c_remove),
+};
+
+module_i2c_driver(ili210x_ts_driver);
+
+MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
+MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/inexio.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/inexio.c
new file mode 100644
index 0000000..192ade0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/inexio.c
@@ -0,0 +1,207 @@
+/*
+ * iNexio serial touchscreen driver
+ *
+ * Copyright (c) 2008 Richard Lemon
+ * Based on the mtouch driver (c) Vojtech Pavlik and Dan Streetman
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * 2008/06/19 Richard Lemon <richard@codelemon.com>
+ *   Copied mtouch.c and edited for iNexio protocol
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"iNexio serial touchscreen driver"
+
+MODULE_AUTHOR("Richard Lemon <richard@codelemon.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define INEXIO_FORMAT_TOUCH_BIT 0x01
+#define INEXIO_FORMAT_LENGTH 5
+#define INEXIO_RESPONSE_BEGIN_BYTE 0x80
+
+/* todo: check specs for max length of all responses */
+#define INEXIO_MAX_LENGTH 16
+
+#define INEXIO_MIN_XC 0
+#define INEXIO_MAX_XC 0x3fff
+#define INEXIO_MIN_YC 0
+#define INEXIO_MAX_YC 0x3fff
+
+#define INEXIO_GET_XC(data) (((data[1])<<7) | data[2])
+#define INEXIO_GET_YC(data) (((data[3])<<7) | data[4])
+#define INEXIO_GET_TOUCHED(data) (INEXIO_FORMAT_TOUCH_BIT & data[0])
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct inexio {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[INEXIO_MAX_LENGTH];
+	char phys[32];
+};
+
+static void inexio_process_data(struct inexio *pinexio)
+{
+	struct input_dev *dev = pinexio->dev;
+
+	if (INEXIO_FORMAT_LENGTH == ++pinexio->idx) {
+		input_report_abs(dev, ABS_X, INEXIO_GET_XC(pinexio->data));
+		input_report_abs(dev, ABS_Y, INEXIO_GET_YC(pinexio->data));
+		input_report_key(dev, BTN_TOUCH, INEXIO_GET_TOUCHED(pinexio->data));
+		input_sync(dev);
+
+		pinexio->idx = 0;
+	}
+}
+
+static irqreturn_t inexio_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct inexio* pinexio = serio_get_drvdata(serio);
+
+	pinexio->data[pinexio->idx] = data;
+
+	if (INEXIO_RESPONSE_BEGIN_BYTE&pinexio->data[0])
+		inexio_process_data(pinexio);
+	else
+		printk(KERN_DEBUG "inexio.c: unknown/unsynchronized data from device, byte %x\n",pinexio->data[0]);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * inexio_disconnect() is the opposite of inexio_connect()
+ */
+
+static void inexio_disconnect(struct serio *serio)
+{
+	struct inexio* pinexio = serio_get_drvdata(serio);
+
+	input_get_device(pinexio->dev);
+	input_unregister_device(pinexio->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(pinexio->dev);
+	kfree(pinexio);
+}
+
+/*
+ * inexio_connect() is the routine that is called when someone adds a
+ * new serio device that supports iNexio protocol and registers it as
+ * an input device. This is usually accomplished using inputattach.
+ */
+
+static int inexio_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct inexio *pinexio;
+	struct input_dev *input_dev;
+	int err;
+
+	pinexio = kzalloc(sizeof(struct inexio), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!pinexio || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	pinexio->serio = serio;
+	pinexio->dev = input_dev;
+	snprintf(pinexio->phys, sizeof(pinexio->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "iNexio Serial TouchScreen";
+	input_dev->phys = pinexio->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_INEXIO;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0001;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(pinexio->dev, ABS_X, INEXIO_MIN_XC, INEXIO_MAX_XC, 0, 0);
+	input_set_abs_params(pinexio->dev, ABS_Y, INEXIO_MIN_YC, INEXIO_MAX_YC, 0, 0);
+
+	serio_set_drvdata(serio, pinexio);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(pinexio->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(pinexio);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id inexio_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_INEXIO,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, inexio_serio_ids);
+
+static struct serio_driver inexio_drv = {
+	.driver		= {
+		.name	= "inexio",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= inexio_serio_ids,
+	.interrupt	= inexio_interrupt,
+	.connect	= inexio_connect,
+	.disconnect	= inexio_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init inexio_init(void)
+{
+	return serio_register_driver(&inexio_drv);
+}
+
+static void __exit inexio_exit(void)
+{
+	serio_unregister_driver(&inexio_drv);
+}
+
+module_init(inexio_init);
+module_exit(inexio_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/intel-mid-touch.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/intel-mid-touch.c
new file mode 100644
index 0000000..3cd7a83
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/intel-mid-touch.c
@@ -0,0 +1,671 @@
+/*
+ * Intel MID Resistive Touch Screen Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
+ *			    Ramesh Agarwal (ramesh.agarwal@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TODO:
+ *	review conversion of r/m/w sequences
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <asm/intel_scu_ipc.h>
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_ID1		0x00 /* PMIC ID1 register */
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_INT		0x04 /* PMIC interrupt register */
+#define PMIC_REG_MINT		0x05 /* PMIC interrupt mask register */
+
+/* ADC Interrupt registers */
+#define PMIC_REG_ADCINT		0x5F /* ADC interrupt register */
+#define PMIC_REG_MADCINT	0x60 /* ADC interrupt mask register */
+
+/* ADC Control registers */
+#define PMIC_REG_ADCCNTL1	0x61 /* ADC control register */
+
+/* ADC Channel Selection registers */
+#define PMICADDR0		0xA4
+#define END_OF_CHANNEL		0x1F
+
+/* ADC Result register */
+#define PMIC_REG_ADCSNS0H	0x64
+
+/* ADC channels for touch screen */
+#define MRST_TS_CHAN10		0xA /* Touch screen X+ connection */
+#define MRST_TS_CHAN11		0xB /* Touch screen X- connection */
+#define MRST_TS_CHAN12		0xC /* Touch screen Y+ connection */
+#define MRST_TS_CHAN13		0xD /* Touch screen Y- connection */
+
+/* Touch screen channel BIAS constants */
+#define MRST_XBIAS		0x20
+#define MRST_YBIAS		0x40
+#define MRST_ZBIAS		0x80
+
+/* Touch screen coordinates */
+#define MRST_X_MIN		10
+#define MRST_X_MAX		1024
+#define MRST_X_FUZZ		5
+#define MRST_Y_MIN		10
+#define MRST_Y_MAX		1024
+#define MRST_Y_FUZZ		5
+#define MRST_PRESSURE_MIN	0
+#define MRST_PRESSURE_NOMINAL	50
+#define MRST_PRESSURE_MAX	100
+
+#define WAIT_ADC_COMPLETION	10 /* msec */
+
+/* PMIC ADC round robin delays */
+#define ADC_LOOP_DELAY0		0x0 /* Continuous loop */
+#define ADC_LOOP_DELAY1		0x1 /* 4.5  ms approximate */
+
+/* PMIC Vendor Identifiers */
+#define PMIC_VENDOR_FS		0 /* PMIC vendor FreeScale */
+#define PMIC_VENDOR_MAXIM	1 /* PMIC vendor MAXIM */
+#define PMIC_VENDOR_NEC		2 /* PMIC vendor NEC */
+#define MRSTOUCH_MAX_CHANNELS	32 /* Maximum ADC channels */
+
+/* Touch screen device structure */
+struct mrstouch_dev {
+	struct device *dev; /* device associated with touch screen */
+	struct input_dev *input;
+	char phys[32];
+	u16 asr;		/* Address selection register */
+	int irq;
+	unsigned int vendor;	/* PMIC vendor */
+	unsigned int rev;	/* PMIC revision */
+
+	int (*read_prepare)(struct mrstouch_dev *tsdev);
+	int (*read)(struct mrstouch_dev *tsdev, u16 *x, u16 *y, u16 *z);
+	int (*read_finish)(struct mrstouch_dev *tsdev);
+};
+
+
+/*************************** NEC and Maxim Interface ************************/
+
+static int mrstouch_nec_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+	return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0, 0x20);
+}
+
+/*
+ * Enables PENDET interrupt.
+ */
+static int mrstouch_nec_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+	int err;
+
+	err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x20, 0x20);
+	if (!err)
+		err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, 0, 0x05);
+
+	return err;
+}
+
+/*
+ * Reads PMIC ADC touch screen result
+ * Reads ADC storage registers for higher 7 and lower 3 bits and
+ * converts the two readings into a single value and turns off gain bit
+ */
+static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
+{
+	int err;
+	u16 result;
+	u32 res;
+
+	result = PMIC_REG_ADCSNS0H + offset;
+
+	if (chan == MRST_TS_CHAN12)
+		result += 4;
+
+	err = intel_scu_ipc_ioread32(result, &res);
+	if (err)
+		return err;
+
+	/* Mash the bits up */
+
+	*vp = (res & 0xFF) << 3;	/* Highest 7 bits */
+	*vp |= (res >> 8) & 0x07;	/* Lower 3 bits */
+	*vp &= 0x3FF;
+
+	res >>= 16;
+
+	*vm = (res & 0xFF) << 3;	/* Highest 7 bits */
+	*vm |= (res >> 8) & 0x07;	/* Lower 3 bits */
+	*vm &= 0x3FF;
+
+	return 0;
+}
+
+/*
+ * Enables X, Y and Z bias values
+ * Enables YPYM for X channels and XPXM for Y channels
+ */
+static int mrstouch_ts_bias_set(uint offset, uint bias)
+{
+	int count;
+	u16 chan, start;
+	u16 reg[4];
+	u8 data[4];
+
+	chan = PMICADDR0 + offset;
+	start = MRST_TS_CHAN10;
+
+	for (count = 0; count <= 3; count++) {
+		reg[count] = chan++;
+		data[count] = bias | (start + count);
+	}
+
+	return intel_scu_ipc_writev(reg, data, 4);
+}
+
+/* To read touch screen channel values */
+static int mrstouch_nec_adc_read(struct mrstouch_dev *tsdev,
+				 u16 *x, u16 *y, u16 *z)
+{
+	int err;
+	u16 xm, ym, zm;
+
+	/* configure Y bias for X channels */
+	err = mrstouch_ts_bias_set(tsdev->asr, MRST_YBIAS);
+	if (err)
+		goto ipc_error;
+
+	msleep(WAIT_ADC_COMPLETION);
+
+	/* read x+ and x- channels */
+	err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, x, &xm);
+	if (err)
+		goto ipc_error;
+
+	/* configure x bias for y channels */
+	err = mrstouch_ts_bias_set(tsdev->asr, MRST_XBIAS);
+	if (err)
+		goto ipc_error;
+
+	msleep(WAIT_ADC_COMPLETION);
+
+	/* read y+ and y- channels */
+	err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, y, &ym);
+	if (err)
+		goto ipc_error;
+
+	/* configure z bias for x and y channels */
+	err = mrstouch_ts_bias_set(tsdev->asr, MRST_ZBIAS);
+	if (err)
+		goto ipc_error;
+
+	msleep(WAIT_ADC_COMPLETION);
+
+	/* read z+ and z- channels */
+	err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, z, &zm);
+	if (err)
+		goto ipc_error;
+
+	return 0;
+
+ipc_error:
+	dev_err(tsdev->dev, "ipc error during adc read\n");
+	return err;
+}
+
+
+/*************************** Freescale Interface ************************/
+
+static int mrstouch_fs_adc_read_prepare(struct mrstouch_dev *tsdev)
+{
+	int err, count;
+	u16 chan;
+	u16 reg[5];
+	u8 data[5];
+
+	/* Stop the ADC */
+	err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
+	if (err)
+		goto ipc_error;
+
+	chan = PMICADDR0 + tsdev->asr;
+
+	/* Set X BIAS */
+	for (count = 0; count <= 3; count++) {
+		reg[count] = chan++;
+		data[count] = 0x2A;
+	}
+	reg[count] =  chan++; /* Dummy */
+	data[count] = 0;
+
+	err = intel_scu_ipc_writev(reg, data, 5);
+	if (err)
+		goto ipc_error;
+
+	msleep(WAIT_ADC_COMPLETION);
+
+	/* Set Y BIAS */
+	for (count = 0; count <= 3; count++) {
+		reg[count] = chan++;
+		data[count] = 0x4A;
+	}
+	reg[count] = chan++; /* Dummy */
+	data[count] = 0;
+
+	err = intel_scu_ipc_writev(reg, data, 5);
+	if (err)
+		goto ipc_error;
+
+	msleep(WAIT_ADC_COMPLETION);
+
+	/* Set Z BIAS */
+	err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
+	if (err)
+		goto ipc_error;
+
+	msleep(WAIT_ADC_COMPLETION);
+
+	return 0;
+
+ipc_error:
+	dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+	return err;
+}
+
+static int mrstouch_fs_adc_read(struct mrstouch_dev *tsdev,
+				u16 *x, u16 *y, u16 *z)
+{
+	int err;
+	u16 result;
+	u16 reg[4];
+	u8 data[4];
+
+	result = PMIC_REG_ADCSNS0H + tsdev->asr;
+
+	reg[0] = result + 4;
+	reg[1] = result + 5;
+	reg[2] = result + 16;
+	reg[3] = result + 17;
+
+	err = intel_scu_ipc_readv(reg, data, 4);
+	if (err)
+		goto ipc_error;
+
+	*x = data[0] << 3; /* Higher 7 bits */
+	*x |= data[1] & 0x7; /* Lower 3 bits */
+	*x &= 0x3FF;
+
+	*y = data[2] << 3; /* Higher 7 bits */
+	*y |= data[3] & 0x7; /* Lower 3 bits */
+	*y &= 0x3FF;
+
+	/* Read Z value */
+	reg[0] = result + 28;
+	reg[1] = result + 29;
+
+	err = intel_scu_ipc_readv(reg, data, 4);
+	if (err)
+		goto ipc_error;
+
+	*z = data[0] << 3; /* Higher 7 bits */
+	*z |= data[1] & 0x7; /* Lower 3 bits */
+	*z &= 0x3FF;
+
+	return 0;
+
+ipc_error:
+	dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+	return err;
+}
+
+static int mrstouch_fs_adc_read_finish(struct mrstouch_dev *tsdev)
+{
+	int err, count;
+	u16 chan;
+	u16 reg[5];
+	u8 data[5];
+
+	/* Clear all TS channels */
+	chan = PMICADDR0 + tsdev->asr;
+	for (count = 0; count <= 4; count++) {
+		reg[count] = chan++;
+		data[count] = 0;
+	}
+	err = intel_scu_ipc_writev(reg, data, 5);
+	if (err)
+		goto ipc_error;
+
+	for (count = 0; count <= 4; count++) {
+		reg[count] = chan++;
+		data[count] = 0;
+	}
+	err = intel_scu_ipc_writev(reg, data, 5);
+	if (err)
+		goto ipc_error;
+
+	err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
+	if (err)
+		goto ipc_error;
+
+	/* Start ADC */
+	err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
+	if (err)
+		goto ipc_error;
+
+	return 0;
+
+ipc_error:
+	dev_err(tsdev->dev, "ipc error during %s\n", __func__);
+	return err;
+}
+
+static void mrstouch_report_event(struct input_dev *input,
+			unsigned int x, unsigned int y, unsigned int z)
+{
+	if (z > MRST_PRESSURE_NOMINAL) {
+		/* Pen touched, report button touch and coordinates */
+		input_report_key(input, BTN_TOUCH, 1);
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+	} else {
+		input_report_key(input, BTN_TOUCH, 0);
+	}
+
+	input_report_abs(input, ABS_PRESSURE, z);
+	input_sync(input);
+}
+
+/* PENDET interrupt handler */
+static irqreturn_t mrstouch_pendet_irq(int irq, void *dev_id)
+{
+	struct mrstouch_dev *tsdev = dev_id;
+	u16 x, y, z;
+
+	/*
+	 * Should we lower thread priority? Probably not, since we are
+	 * not spinning but sleeping...
+	 */
+
+	if (tsdev->read_prepare(tsdev))
+		goto out;
+
+	do {
+		if (tsdev->read(tsdev, &x, &y, &z))
+			break;
+
+		mrstouch_report_event(tsdev->input, x, y, z);
+	} while (z > MRST_PRESSURE_NOMINAL);
+
+	tsdev->read_finish(tsdev);
+
+out:
+	return IRQ_HANDLED;
+}
+
+/* Utility to read PMIC ID */
+static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
+{
+	int err;
+	u8 r;
+
+	err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
+	if (err)
+		return err;
+
+	*vendor = r & 0x7;
+	*rev = (r >> 3) & 0x7;
+
+	return 0;
+}
+
+/*
+ * Parse ADC channels to find end of the channel configured by other ADC user
+ * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
+ */
+static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
+{
+	int found = 0;
+	int err, i;
+	u8 r8;
+
+	for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
+		err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8);
+		if (err)
+			return err;
+
+		if (r8 == END_OF_CHANNEL) {
+			found = i;
+			break;
+		}
+	}
+
+	if (tsdev->vendor == PMIC_VENDOR_FS) {
+		if (found > MRSTOUCH_MAX_CHANNELS - 18)
+			return -ENOSPC;
+	} else {
+		if (found > MRSTOUCH_MAX_CHANNELS - 4)
+			return -ENOSPC;
+	}
+
+	return found;
+}
+
+
+/*
+ * Writes touch screen channels to ADC address selection registers
+ */
+static int __devinit mrstouch_ts_chan_set(uint offset)
+{
+	u16 chan;
+
+	int ret, count;
+
+	chan = PMICADDR0 + offset;
+	for (count = 0; count <= 3; count++) {
+		ret = intel_scu_ipc_iowrite8(chan++, MRST_TS_CHAN10 + count);
+		if (ret)
+			return ret;
+	}
+	return intel_scu_ipc_iowrite8(chan++, END_OF_CHANNEL);
+}
+
+/* Initialize ADC */
+static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev)
+{
+	int err, start;
+	u8 ra, rm;
+
+	err = mrstouch_read_pmic_id(&tsdev->vendor, &tsdev->rev);
+	if (err) {
+		dev_err(tsdev->dev, "Unable to read PMIC id\n");
+		return err;
+	}
+
+	switch (tsdev->vendor) {
+	case PMIC_VENDOR_NEC:
+	case PMIC_VENDOR_MAXIM:
+		tsdev->read_prepare = mrstouch_nec_adc_read_prepare;
+		tsdev->read = mrstouch_nec_adc_read;
+		tsdev->read_finish = mrstouch_nec_adc_read_finish;
+		break;
+
+	case PMIC_VENDOR_FS:
+		tsdev->read_prepare = mrstouch_fs_adc_read_prepare;
+		tsdev->read = mrstouch_fs_adc_read;
+		tsdev->read_finish = mrstouch_fs_adc_read_finish;
+		break;
+
+	default:
+		dev_err(tsdev->dev,
+			"Unsupported touchscreen: %d\n", tsdev->vendor);
+		return -ENXIO;
+	}
+
+	start = mrstouch_chan_parse(tsdev);
+	if (start < 0) {
+		dev_err(tsdev->dev, "Unable to parse channels\n");
+		return start;
+	}
+
+	tsdev->asr = start;
+
+	/*
+	 * ADC power on, start, enable PENDET and set loop delay
+	 * ADC loop delay is set to 4.5 ms approximately
+	 * Loop delay more than this results in jitter in adc readings
+	 * Setting loop delay to 0 (continuous loop) in MAXIM stops PENDET
+	 * interrupt generation sometimes.
+	 */
+
+	if (tsdev->vendor == PMIC_VENDOR_FS) {
+		ra = 0xE0 | ADC_LOOP_DELAY0;
+		rm = 0x5;
+	} else {
+		/* NEC and MAXIm not consistent with loop delay 0 */
+		ra = 0xE0 | ADC_LOOP_DELAY1;
+		rm = 0x0;
+
+		/* configure touch screen channels */
+		err = mrstouch_ts_chan_set(tsdev->asr);
+		if (err)
+			return err;
+	}
+
+	err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
+	if (err)
+		return err;
+
+	err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+
+/* Probe function for touch screen driver */
+static int __devinit mrstouch_probe(struct platform_device *pdev)
+{
+	struct mrstouch_dev *tsdev;
+	struct input_dev *input;
+	int err;
+	int irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no interrupt assigned\n");
+		return -EINVAL;
+	}
+
+	tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!tsdev || !input) {
+		dev_err(&pdev->dev, "unable to allocate memory\n");
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	tsdev->dev = &pdev->dev;
+	tsdev->input = input;
+	tsdev->irq = irq;
+
+	snprintf(tsdev->phys, sizeof(tsdev->phys),
+		 "%s/input0", dev_name(tsdev->dev));
+
+	err = mrstouch_adc_init(tsdev);
+	if (err) {
+		dev_err(&pdev->dev, "ADC initialization failed\n");
+		goto err_free_mem;
+	}
+
+	input->name = "mrst_touchscreen";
+	input->phys = tsdev->phys;
+	input->dev.parent = tsdev->dev;
+
+	input->id.vendor = tsdev->vendor;
+	input->id.version = tsdev->rev;
+
+	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(tsdev->input, ABS_X,
+			     MRST_X_MIN, MRST_X_MAX, MRST_X_FUZZ, 0);
+	input_set_abs_params(tsdev->input, ABS_Y,
+			     MRST_Y_MIN, MRST_Y_MAX, MRST_Y_FUZZ, 0);
+	input_set_abs_params(tsdev->input, ABS_PRESSURE,
+			     MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
+
+	err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
+				   0, "mrstouch", tsdev);
+	if (err) {
+		dev_err(tsdev->dev, "unable to allocate irq\n");
+		goto err_free_mem;
+	}
+
+	err = input_register_device(tsdev->input);
+	if (err) {
+		dev_err(tsdev->dev, "unable to register input device\n");
+		goto err_free_irq;
+	}
+
+	platform_set_drvdata(pdev, tsdev);
+	return 0;
+
+err_free_irq:
+	free_irq(tsdev->irq, tsdev);
+err_free_mem:
+	input_free_device(input);
+	kfree(tsdev);
+	return err;
+}
+
+static int __devexit mrstouch_remove(struct platform_device *pdev)
+{
+	struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
+
+	free_irq(tsdev->irq, tsdev);
+	input_unregister_device(tsdev->input);
+	kfree(tsdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver mrstouch_driver = {
+	.driver = {
+		.name	= "pmic_touch",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= mrstouch_probe,
+	.remove		= __devexit_p(mrstouch_remove),
+};
+module_platform_driver(mrstouch_driver);
+
+MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
+MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/jornada720_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/jornada720_ts.c
new file mode 100644
index 0000000..d9be6ea
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/jornada720_ts.c
@@ -0,0 +1,176 @@
+/*
+ * drivers/input/touchscreen/jornada720_ts.c
+ *
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *
+ *  Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
+ *  based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * HP Jornada 710/720/729 Touchscreen Driver
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/jornada720.h>
+#include <mach/irqs.h>
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
+MODULE_LICENSE("GPL v2");
+
+struct jornada_ts {
+	struct input_dev *dev;
+	int x_data[4];		/* X sample values */
+	int y_data[4];		/* Y sample values */
+};
+
+static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
+{
+
+    /* 3 low word X samples */
+    jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
+    jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
+    jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY);
+
+    /* 3 low word Y samples */
+    jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY);
+    jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY);
+    jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY);
+
+    /* combined x samples bits */
+    jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY);
+
+    /* combined y samples bits */
+    jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY);
+}
+
+static int jornada720_ts_average(int coords[4])
+{
+	int coord, high_bits = coords[3];
+
+	coord  = coords[0] | ((high_bits & 0x03) << 8);
+	coord += coords[1] | ((high_bits & 0x0c) << 6);
+	coord += coords[2] | ((high_bits & 0x30) << 4);
+
+	return coord / 3;
+}
+
+static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
+	struct input_dev *input = jornada_ts->dev;
+	int x, y;
+
+	/* If GPIO_GPIO9 is set to high then report pen up */
+	if (GPLR & GPIO_GPIO(9)) {
+		input_report_key(input, BTN_TOUCH, 0);
+		input_sync(input);
+	} else {
+		jornada_ssp_start();
+
+		/* proper reply to request is always TXDUMMY */
+		if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) {
+			jornada720_ts_collect_data(jornada_ts);
+
+			x = jornada720_ts_average(jornada_ts->x_data);
+			y = jornada720_ts_average(jornada_ts->y_data);
+
+			input_report_key(input, BTN_TOUCH, 1);
+			input_report_abs(input, ABS_X, x);
+			input_report_abs(input, ABS_Y, y);
+			input_sync(input);
+		}
+
+		jornada_ssp_end();
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit jornada720_ts_probe(struct platform_device *pdev)
+{
+	struct jornada_ts *jornada_ts;
+	struct input_dev *input_dev;
+	int error;
+
+	jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL);
+	input_dev = input_allocate_device();
+
+	if (!jornada_ts || !input_dev) {
+		error = -ENOMEM;
+		goto fail1;
+	}
+
+	platform_set_drvdata(pdev, jornada_ts);
+
+	jornada_ts->dev = input_dev;
+
+	input_dev->name = "HP Jornada 7xx Touchscreen";
+	input_dev->phys = "jornadats/input0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &pdev->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
+
+	error = request_irq(IRQ_GPIO9,
+			jornada720_ts_interrupt,
+			IRQF_TRIGGER_RISING,
+			"HP7XX Touchscreen driver", pdev);
+	if (error) {
+		printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
+		goto fail1;
+	}
+
+	error = input_register_device(jornada_ts->dev);
+	if (error)
+		goto fail2;
+
+	return 0;
+
+ fail2:
+	free_irq(IRQ_GPIO9, pdev);
+ fail1:
+	platform_set_drvdata(pdev, NULL);
+	input_free_device(input_dev);
+	kfree(jornada_ts);
+	return error;
+}
+
+static int __devexit jornada720_ts_remove(struct platform_device *pdev)
+{
+	struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
+
+	free_irq(IRQ_GPIO9, pdev);
+	platform_set_drvdata(pdev, NULL);
+	input_unregister_device(jornada_ts->dev);
+	kfree(jornada_ts);
+
+	return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:jornada_ts");
+
+static struct platform_driver jornada720_ts_driver = {
+	.probe		= jornada720_ts_probe,
+	.remove		= __devexit_p(jornada720_ts_remove),
+	.driver		= {
+		.name	= "jornada_ts",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(jornada720_ts_driver);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/lpc32xx_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/lpc32xx_ts.c
new file mode 100644
index 0000000..afcd069
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/lpc32xx_ts.c
@@ -0,0 +1,400 @@
+/*
+ * LPC32xx built-in touchscreen driver
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/*
+ * Touchscreen controller register offsets
+ */
+#define LPC32XX_TSC_STAT			0x00
+#define LPC32XX_TSC_SEL				0x04
+#define LPC32XX_TSC_CON				0x08
+#define LPC32XX_TSC_FIFO			0x0C
+#define LPC32XX_TSC_DTR				0x10
+#define LPC32XX_TSC_RTR				0x14
+#define LPC32XX_TSC_UTR				0x18
+#define LPC32XX_TSC_TTR				0x1C
+#define LPC32XX_TSC_DXP				0x20
+#define LPC32XX_TSC_MIN_X			0x24
+#define LPC32XX_TSC_MAX_X			0x28
+#define LPC32XX_TSC_MIN_Y			0x2C
+#define LPC32XX_TSC_MAX_Y			0x30
+#define LPC32XX_TSC_AUX_UTR			0x34
+#define LPC32XX_TSC_AUX_MIN			0x38
+#define LPC32XX_TSC_AUX_MAX			0x3C
+
+#define LPC32XX_TSC_STAT_FIFO_OVRRN		(1 << 8)
+#define LPC32XX_TSC_STAT_FIFO_EMPTY		(1 << 7)
+
+#define LPC32XX_TSC_SEL_DEFVAL			0x0284
+
+#define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4	(0x1 << 11)
+#define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s)	((10 - (s)) << 7)
+#define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s)	((10 - (s)) << 4)
+#define LPC32XX_TSC_ADCCON_POWER_UP		(1 << 2)
+#define LPC32XX_TSC_ADCCON_AUTO_EN		(1 << 0)
+
+#define LPC32XX_TSC_FIFO_TS_P_LEVEL		(1 << 31)
+#define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x)	(((x) & 0x03FF0000) >> 16)
+#define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y)	((y) & 0x000003FF)
+
+#define LPC32XX_TSC_ADCDAT_VALUE_MASK		0x000003FF
+
+#define LPC32XX_TSC_MIN_XY_VAL			0x0
+#define LPC32XX_TSC_MAX_XY_VAL			0x3FF
+
+#define MOD_NAME "ts-lpc32xx"
+
+#define tsc_readl(dev, reg) \
+	__raw_readl((dev)->tsc_base + (reg))
+#define tsc_writel(dev, reg, val) \
+	__raw_writel((val), (dev)->tsc_base + (reg))
+
+struct lpc32xx_tsc {
+	struct input_dev *dev;
+	void __iomem *tsc_base;
+	int irq;
+	struct clk *clk;
+};
+
+static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
+{
+	while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+			LPC32XX_TSC_STAT_FIFO_EMPTY))
+		tsc_readl(tsc, LPC32XX_TSC_FIFO);
+}
+
+static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
+{
+	u32 tmp, rv[4], xs[4], ys[4];
+	int idx;
+	struct lpc32xx_tsc *tsc = dev_id;
+	struct input_dev *input = tsc->dev;
+
+	tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);
+
+	if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
+		/* FIFO overflow - throw away samples */
+		lpc32xx_fifo_clear(tsc);
+		return IRQ_HANDLED;
+	}
+
+	/*
+	 * Gather and normalize 4 samples. Pen-up events may have less
+	 * than 4 samples, but its ok to pop 4 and let the last sample
+	 * pen status check drop the samples.
+	 */
+	idx = 0;
+	while (idx < 4 &&
+	       !(tsc_readl(tsc, LPC32XX_TSC_STAT) &
+			LPC32XX_TSC_STAT_FIFO_EMPTY)) {
+		tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
+		xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+			LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
+		ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
+			LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
+		rv[idx] = tmp;
+		idx++;
+	}
+
+	/* Data is only valid if pen is still down in last sample */
+	if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
+		/* Use average of 2nd and 3rd sample for position */
+		input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
+		input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
+		input_report_key(input, BTN_TOUCH, 1);
+	} else {
+		input_report_key(input, BTN_TOUCH, 0);
+	}
+
+	input_sync(input);
+
+	return IRQ_HANDLED;
+}
+
+static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
+{
+	/* Disable auto mode */
+	tsc_writel(tsc, LPC32XX_TSC_CON,
+		   tsc_readl(tsc, LPC32XX_TSC_CON) &
+			     ~LPC32XX_TSC_ADCCON_AUTO_EN);
+
+	clk_disable(tsc->clk);
+}
+
+static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
+{
+	u32 tmp;
+
+	clk_enable(tsc->clk);
+
+	tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
+
+	/* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
+	tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
+	      LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
+	      LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
+	tsc_writel(tsc, LPC32XX_TSC_CON, tmp);
+
+	/* These values are all preset */
+	tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);
+	tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);
+	tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);
+	tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);
+	tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);
+
+	/* Aux support is not used */
+	tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);
+	tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);
+	tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);
+
+	/*
+	 * Set sample rate to about 240Hz per X/Y pair. A single measurement
+	 * consists of 4 pairs which gives about a 60Hz sample rate based on
+	 * a stable 32768Hz clock source. Values are in clocks.
+	 * Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4
+	 */
+	tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);
+	tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);
+	tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);
+	tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);
+	tsc_writel(tsc, LPC32XX_TSC_UTR, 88);
+
+	lpc32xx_fifo_clear(tsc);
+
+	/* Enable automatic ts event capture */
+	tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
+}
+
+static int lpc32xx_ts_open(struct input_dev *dev)
+{
+	struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+	lpc32xx_setup_tsc(tsc);
+
+	return 0;
+}
+
+static void lpc32xx_ts_close(struct input_dev *dev)
+{
+	struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
+
+	lpc32xx_stop_tsc(tsc);
+}
+
+static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
+{
+	struct lpc32xx_tsc *tsc;
+	struct input_dev *input;
+	struct resource *res;
+	resource_size_t size;
+	int irq;
+	int error;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Can't get memory resource\n");
+		return -ENOENT;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Can't get interrupt resource\n");
+		return irq;
+	}
+
+	tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!tsc || !input) {
+		dev_err(&pdev->dev, "failed allocating memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	tsc->dev = input;
+	tsc->irq = irq;
+
+	size = resource_size(res);
+
+	if (!request_mem_region(res->start, size, pdev->name)) {
+		dev_err(&pdev->dev, "TSC registers are not free\n");
+		error = -EBUSY;
+		goto err_free_mem;
+	}
+
+	tsc->tsc_base = ioremap(res->start, size);
+	if (!tsc->tsc_base) {
+		dev_err(&pdev->dev, "Can't map memory\n");
+		error = -ENOMEM;
+		goto err_release_mem;
+	}
+
+	tsc->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(tsc->clk)) {
+		dev_err(&pdev->dev, "failed getting clock\n");
+		error = PTR_ERR(tsc->clk);
+		goto err_unmap;
+	}
+
+	input->name = MOD_NAME;
+	input->phys = "lpc32xx/input0";
+	input->id.bustype = BUS_HOST;
+	input->id.vendor = 0x0001;
+	input->id.product = 0x0002;
+	input->id.version = 0x0100;
+	input->dev.parent = &pdev->dev;
+	input->open = lpc32xx_ts_open;
+	input->close = lpc32xx_ts_close;
+
+	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
+			     LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+	input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
+			     LPC32XX_TSC_MAX_XY_VAL, 0, 0);
+
+	input_set_drvdata(input, tsc);
+
+	error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
+			    0, pdev->name, tsc);
+	if (error) {
+		dev_err(&pdev->dev, "failed requesting interrupt\n");
+		goto err_put_clock;
+	}
+
+	error = input_register_device(input);
+	if (error) {
+		dev_err(&pdev->dev, "failed registering input device\n");
+		goto err_free_irq;
+	}
+
+	platform_set_drvdata(pdev, tsc);
+	device_init_wakeup(&pdev->dev, 1);
+
+	return 0;
+
+err_free_irq:
+	free_irq(tsc->irq, tsc);
+err_put_clock:
+	clk_put(tsc->clk);
+err_unmap:
+	iounmap(tsc->tsc_base);
+err_release_mem:
+	release_mem_region(res->start, size);
+err_free_mem:
+	input_free_device(input);
+	kfree(tsc);
+
+	return error;
+}
+
+static int __devexit lpc32xx_ts_remove(struct platform_device *pdev)
+{
+	struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	device_init_wakeup(&pdev->dev, 0);
+	free_irq(tsc->irq, tsc);
+
+	input_unregister_device(tsc->dev);
+
+	clk_put(tsc->clk);
+
+	iounmap(tsc->tsc_base);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+
+	kfree(tsc);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_ts_suspend(struct device *dev)
+{
+	struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+	struct input_dev *input = tsc->dev;
+
+	/*
+	 * Suspend and resume can be called when the device hasn't been
+	 * enabled. If there are no users that have the device open, then
+	 * avoid calling the TSC stop and start functions as the TSC
+	 * isn't yet clocked.
+	 */
+	mutex_lock(&input->mutex);
+
+	if (input->users) {
+		if (device_may_wakeup(dev))
+			enable_irq_wake(tsc->irq);
+		else
+			lpc32xx_stop_tsc(tsc);
+	}
+
+	mutex_unlock(&input->mutex);
+
+	return 0;
+}
+
+static int lpc32xx_ts_resume(struct device *dev)
+{
+	struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
+	struct input_dev *input = tsc->dev;
+
+	mutex_lock(&input->mutex);
+
+	if (input->users) {
+		if (device_may_wakeup(dev))
+			disable_irq_wake(tsc->irq);
+		else
+			lpc32xx_setup_tsc(tsc);
+	}
+
+	mutex_unlock(&input->mutex);
+
+	return 0;
+}
+
+static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
+	.suspend	= lpc32xx_ts_suspend,
+	.resume		= lpc32xx_ts_resume,
+};
+#define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)
+#else
+#define LPC32XX_TS_PM_OPS NULL
+#endif
+
+static struct platform_driver lpc32xx_ts_driver = {
+	.probe		= lpc32xx_ts_probe,
+	.remove		= __devexit_p(lpc32xx_ts_remove),
+	.driver		= {
+		.name	= MOD_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= LPC32XX_TS_PM_OPS,
+	},
+};
+module_platform_driver(lpc32xx_ts_driver);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
+MODULE_DESCRIPTION("LPC32XX TSC Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc32xx_ts");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mainstone-wm97xx.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mainstone-wm97xx.c
new file mode 100644
index 0000000..7d2b213
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -0,0 +1,310 @@
+/*
+ * mainstone-wm97xx.c  --  Mainstone Continuous Touch screen driver for
+ *                         Wolfson WM97xx AC97 Codecs.
+ *
+ * Copyright 2004, 2007 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ *                   Andrew Zabolotny <zap@homelink.ru>
+ *
+ *  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.
+ *
+ * Notes:
+ *     This is a wm97xx extended touch driver to capture touch
+ *     data in a continuous manner on the Intel XScale architecture
+ *
+ *  Features:
+ *       - codecs supported:- WM9705, WM9712, WM9713
+ *       - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/wm97xx.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/regs-ac97.h>
+
+#include <asm/mach-types.h>
+
+struct continuous {
+	u16 id;    /* codec id */
+	u8 code;   /* continuous code */
+	u8 reads;  /* number of coord reads per read cycle */
+	u32 speed; /* number of coords per second */
+};
+
+#define WM_READS(sp) ((sp / HZ) + 1)
+
+static const struct continuous cinfo[] = {
+	{WM9705_ID2, 0, WM_READS(94), 94},
+	{WM9705_ID2, 1, WM_READS(188), 188},
+	{WM9705_ID2, 2, WM_READS(375), 375},
+	{WM9705_ID2, 3, WM_READS(750), 750},
+	{WM9712_ID2, 0, WM_READS(94), 94},
+	{WM9712_ID2, 1, WM_READS(188), 188},
+	{WM9712_ID2, 2, WM_READS(375), 375},
+	{WM9712_ID2, 3, WM_READS(750), 750},
+	{WM9713_ID2, 0, WM_READS(94), 94},
+	{WM9713_ID2, 1, WM_READS(120), 120},
+	{WM9713_ID2, 2, WM_READS(154), 154},
+	{WM9713_ID2, 3, WM_READS(188), 188},
+};
+
+/* continuous speed index */
+static int sp_idx;
+static u16 last, tries;
+static int irq;
+
+/*
+ * Pen sampling frequency (Hz) in continuous mode.
+ */
+static int cont_rate = 200;
+module_param(cont_rate, int, 0);
+MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
+
+/*
+ * Pen down detection.
+ *
+ * This driver can either poll or use an interrupt to indicate a pen down
+ * event. If the irq request fails then it will fall back to polling mode.
+ */
+static int pen_int;
+module_param(pen_int, int, 0);
+MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
+
+/*
+ * Pressure readback.
+ *
+ * Set to 1 to read back pen down pressure
+ */
+static int pressure;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
+
+/*
+ * AC97 touch data slot.
+ *
+ * Touch screen readback data ac97 slot
+ */
+static int ac97_touch_slot = 5;
+module_param(ac97_touch_slot, int, 0);
+MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
+
+
+/* flush AC97 slot 5 FIFO on pxa machines */
+#ifdef CONFIG_PXA27x
+static void wm97xx_acc_pen_up(struct wm97xx *wm)
+{
+	schedule_timeout_uninterruptible(1);
+
+	while (MISR & (1 << 2))
+		MODR;
+}
+#else
+static void wm97xx_acc_pen_up(struct wm97xx *wm)
+{
+	unsigned int count;
+
+	schedule_timeout_uninterruptible(1);
+
+	for (count = 0; count < 16; count++)
+		MODR;
+}
+#endif
+
+static int wm97xx_acc_pen_down(struct wm97xx *wm)
+{
+	u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
+	int reads = 0;
+
+	/* When the AC97 queue has been drained we need to allow time
+	 * to buffer up samples otherwise we end up spinning polling
+	 * for samples.  The controller can't have a suitably low
+	 * threshold set to use the notifications it gives.
+	 */
+	schedule_timeout_uninterruptible(1);
+
+	if (tries > 5) {
+		tries = 0;
+		return RC_PENUP;
+	}
+
+	x = MODR;
+	if (x == last) {
+		tries++;
+		return RC_AGAIN;
+	}
+	last = x;
+	do {
+		if (reads)
+			x = MODR;
+		y = MODR;
+		if (pressure)
+			p = MODR;
+
+		dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
+			x, y, p);
+
+		/* are samples valid */
+		if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
+		    (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
+		    (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
+			goto up;
+
+		/* coordinate is good */
+		tries = 0;
+		input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
+		input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
+		input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
+		input_report_key(wm->input_dev, BTN_TOUCH, (p != 0));
+		input_sync(wm->input_dev);
+		reads++;
+	} while (reads < cinfo[sp_idx].reads);
+up:
+	return RC_PENDOWN | RC_AGAIN;
+}
+
+static int wm97xx_acc_startup(struct wm97xx *wm)
+{
+	int idx = 0, ret = 0;
+
+	/* check we have a codec */
+	if (wm->ac97 == NULL)
+		return -ENODEV;
+
+	/* Go you big red fire engine */
+	for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
+		if (wm->id != cinfo[idx].id)
+			continue;
+		sp_idx = idx;
+		if (cont_rate <= cinfo[idx].speed)
+			break;
+	}
+	wm->acc_rate = cinfo[sp_idx].code;
+	wm->acc_slot = ac97_touch_slot;
+	dev_info(wm->dev,
+		 "mainstone accelerated touchscreen driver, %d samples/sec\n",
+		 cinfo[sp_idx].speed);
+
+	/* IRQ driven touchscreen is used on Palm hardware */
+	if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
+		pen_int = 1;
+		irq = 27;
+		/* There is some obscure mutant of WM9712 interbred with WM9713
+		 * used on Palm HW */
+		wm->variant = WM97xx_WM1613;
+	} else if (machine_is_mainstone() && pen_int)
+		irq = 4;
+
+	if (irq) {
+		ret = gpio_request(irq, "Touchscreen IRQ");
+		if (ret)
+			goto out;
+
+		ret = gpio_direction_input(irq);
+		if (ret) {
+			gpio_free(irq);
+			goto out;
+		}
+
+		wm->pen_irq = gpio_to_irq(irq);
+		irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
+	} else /* pen irq not supported */
+		pen_int = 0;
+
+	/* codec specific irq config */
+	if (pen_int) {
+		switch (wm->id) {
+		case WM9705_ID2:
+			break;
+		case WM9712_ID2:
+		case WM9713_ID2:
+			/* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
+			wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
+					   WM97XX_GPIO_POL_HIGH,
+					   WM97XX_GPIO_STICKY,
+					   WM97XX_GPIO_WAKE);
+			wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
+					   WM97XX_GPIO_POL_HIGH,
+					   WM97XX_GPIO_NOTSTICKY,
+					   WM97XX_GPIO_NOWAKE);
+			break;
+		default:
+			dev_err(wm->dev,
+				"pen down irq not supported on this device\n");
+			pen_int = 0;
+			break;
+		}
+	}
+
+out:
+	return ret;
+}
+
+static void wm97xx_acc_shutdown(struct wm97xx *wm)
+{
+	/* codec specific deconfig */
+	if (pen_int) {
+		if (irq)
+			gpio_free(irq);
+		wm->pen_irq = 0;
+	}
+}
+
+static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
+{
+	if (enable)
+		enable_irq(wm->pen_irq);
+	else
+		disable_irq_nosync(wm->pen_irq);
+}
+
+static struct wm97xx_mach_ops mainstone_mach_ops = {
+	.acc_enabled = 1,
+	.acc_pen_up = wm97xx_acc_pen_up,
+	.acc_pen_down = wm97xx_acc_pen_down,
+	.acc_startup = wm97xx_acc_startup,
+	.acc_shutdown = wm97xx_acc_shutdown,
+	.irq_enable = wm97xx_irq_enable,
+	.irq_gpio = WM97XX_GPIO_2,
+};
+
+static int mainstone_wm97xx_probe(struct platform_device *pdev)
+{
+	struct wm97xx *wm = platform_get_drvdata(pdev);
+
+	return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
+}
+
+static int mainstone_wm97xx_remove(struct platform_device *pdev)
+{
+	struct wm97xx *wm = platform_get_drvdata(pdev);
+
+	wm97xx_unregister_mach_ops(wm);
+	return 0;
+}
+
+static struct platform_driver mainstone_wm97xx_driver = {
+	.probe = mainstone_wm97xx_probe,
+	.remove = mainstone_wm97xx_remove,
+	.driver = {
+		.name = "wm97xx-touch",
+	},
+};
+module_platform_driver(mainstone_wm97xx_driver);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/max11801_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/max11801_ts.c
new file mode 100644
index 0000000..4eab50b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/max11801_ts.c
@@ -0,0 +1,262 @@
+/*
+ * Driver for MAXI MAX11801 - A Resistive touch screen controller with
+ * i2c interface
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs5000_ts.c
+ *
+ * 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 driver aims to support the series of MAXI touch chips max11801
+ * through max11803. The main difference between these 4 chips can be
+ * found in the table below:
+ * -----------------------------------------------------
+ * | CHIP     |  AUTO MODE SUPPORT(FIFO) | INTERFACE    |
+ * |----------------------------------------------------|
+ * | max11800 |  YES                     |   SPI        |
+ * | max11801 |  YES                     |   I2C        |
+ * | max11802 |  NO                      |   SPI        |
+ * | max11803 |  NO                      |   I2C        |
+ * ------------------------------------------------------
+ *
+ * Currently, this driver only supports max11801.
+ *
+ * Data Sheet:
+ * http://www.maxim-ic.com/datasheet/index.mvp/id/5943
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+
+/* Register Address define */
+#define GENERNAL_STATUS_REG		0x00
+#define GENERNAL_CONF_REG		0x01
+#define MESURE_RES_CONF_REG		0x02
+#define MESURE_AVER_CONF_REG		0x03
+#define ADC_SAMPLE_TIME_CONF_REG	0x04
+#define PANEL_SETUPTIME_CONF_REG	0x05
+#define DELAY_CONVERSION_CONF_REG	0x06
+#define TOUCH_DETECT_PULLUP_CONF_REG	0x07
+#define AUTO_MODE_TIME_CONF_REG		0x08 /* only for max11800/max11801 */
+#define APERTURE_CONF_REG		0x09 /* only for max11800/max11801 */
+#define AUX_MESURE_CONF_REG		0x0a
+#define OP_MODE_CONF_REG		0x0b
+
+/* FIFO is found only in max11800 and max11801 */
+#define FIFO_RD_CMD			(0x50 << 1)
+#define MAX11801_FIFO_INT		(1 << 2)
+#define MAX11801_FIFO_OVERFLOW		(1 << 3)
+
+#define XY_BUFSIZE			4
+#define XY_BUF_OFFSET			4
+
+#define MAX11801_MAX_X			0xfff
+#define MAX11801_MAX_Y			0xfff
+
+#define MEASURE_TAG_OFFSET		2
+#define MEASURE_TAG_MASK		(3 << MEASURE_TAG_OFFSET)
+#define EVENT_TAG_OFFSET		0
+#define EVENT_TAG_MASK			(3 << EVENT_TAG_OFFSET)
+#define MEASURE_X_TAG			(0 << MEASURE_TAG_OFFSET)
+#define MEASURE_Y_TAG			(1 << MEASURE_TAG_OFFSET)
+
+/* These are the state of touch event state machine */
+enum {
+	EVENT_INIT,
+	EVENT_MIDDLE,
+	EVENT_RELEASE,
+	EVENT_FIFO_END
+};
+
+struct max11801_data {
+	struct i2c_client		*client;
+	struct input_dev		*input_dev;
+};
+
+static u8 read_register(struct i2c_client *client, int addr)
+{
+	/* XXX: The chip ignores LSB of register address */
+	return i2c_smbus_read_byte_data(client, addr << 1);
+}
+
+static int max11801_write_reg(struct i2c_client *client, int addr, int data)
+{
+	/* XXX: The chip ignores LSB of register address */
+	return i2c_smbus_write_byte_data(client, addr << 1, data);
+}
+
+static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
+{
+	struct max11801_data *data = dev_id;
+	struct i2c_client *client = data->client;
+	int status, i, ret;
+	u8 buf[XY_BUFSIZE];
+	int x = -1;
+	int y = -1;
+
+	status = read_register(data->client, GENERNAL_STATUS_REG);
+
+	if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) {
+		status = read_register(data->client, GENERNAL_STATUS_REG);
+
+		ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
+						    XY_BUFSIZE, buf);
+
+		/*
+		 * We should get 4 bytes buffer that contains X,Y
+		 * and event tag
+		 */
+		if (ret < XY_BUFSIZE)
+			goto out;
+
+		for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) {
+			if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG)
+				x = (buf[i] << XY_BUF_OFFSET) +
+				    (buf[i + 1] >> XY_BUF_OFFSET);
+			else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG)
+				y = (buf[i] << XY_BUF_OFFSET) +
+				    (buf[i + 1] >> XY_BUF_OFFSET);
+		}
+
+		if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK))
+			goto out;
+
+		switch (buf[1] & EVENT_TAG_MASK) {
+		case EVENT_INIT:
+			/* fall through */
+		case EVENT_MIDDLE:
+			input_report_abs(data->input_dev, ABS_X, x);
+			input_report_abs(data->input_dev, ABS_Y, y);
+			input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1);
+			input_sync(data->input_dev);
+			break;
+
+		case EVENT_RELEASE:
+			input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
+			input_sync(data->input_dev);
+			break;
+
+		case EVENT_FIFO_END:
+			break;
+		}
+	}
+out:
+	return IRQ_HANDLED;
+}
+
+static void __devinit max11801_ts_phy_init(struct max11801_data *data)
+{
+	struct i2c_client *client = data->client;
+
+	/* Average X,Y, take 16 samples, average eight media sample */
+	max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff);
+	/* X,Y panel setup time set to 20us */
+	max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11);
+	/* Rough pullup time (2uS), Fine pullup time (10us)  */
+	max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10);
+	/* Auto mode init period = 5ms , scan period = 5ms*/
+	max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa);
+	/* Aperture X,Y set to +- 4LSB */
+	max11801_write_reg(client, APERTURE_CONF_REG, 0x33);
+	/* Enable Power, enable Automode, enable Aperture, enable Average X,Y */
+	max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
+}
+
+static int __devinit max11801_ts_probe(struct i2c_client *client,
+				       const struct i2c_device_id *id)
+{
+	struct max11801_data *data;
+	struct input_dev *input_dev;
+	int error;
+
+	data = kzalloc(sizeof(struct max11801_data), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	data->client = client;
+	data->input_dev = input_dev;
+
+	input_dev->name = "max11801_ts";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	input_set_abs_params(input_dev, ABS_X, 0, MAX11801_MAX_X, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0);
+	input_set_drvdata(input_dev, data);
+
+	max11801_ts_phy_init(data);
+
+	error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt,
+				     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				     "max11801_ts", data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(data->input_dev);
+	if (error)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, data);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+	return error;
+}
+
+static __devexit int max11801_ts_remove(struct i2c_client *client)
+{
+	struct max11801_data *data = i2c_get_clientdata(client);
+
+	free_irq(client->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id max11801_ts_id[] = {
+	{"max11801", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+
+static struct i2c_driver max11801_ts_driver = {
+	.driver = {
+		.name	= "max11801_ts",
+		.owner	= THIS_MODULE,
+	},
+	.id_table	= max11801_ts_id,
+	.probe		= max11801_ts_probe,
+	.remove		= __devexit_p(max11801_ts_remove),
+};
+
+module_i2c_driver(max11801_ts_driver);
+
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mc13783_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mc13783_ts.c
new file mode 100644
index 0000000..48dc5b0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mc13783_ts.c
@@ -0,0 +1,268 @@
+/*
+ * Driver for the Freescale Semiconductor MC13783 touchscreen.
+ *
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009 Sascha Hauer, Pengutronix
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/platform_device.h>
+#include <linux/mfd/mc13783.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#define MC13783_TS_NAME	"mc13783-ts"
+
+#define DEFAULT_SAMPLE_TOLERANCE 300
+
+static unsigned int sample_tolerance = DEFAULT_SAMPLE_TOLERANCE;
+module_param(sample_tolerance, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sample_tolerance,
+		"If the minimal and maximal value read out for one axis (out "
+		"of three) differ by this value (default: "
+		__stringify(DEFAULT_SAMPLE_TOLERANCE) ") or more, the reading "
+		"is supposed to be wrong and is discarded.  Set to 0 to "
+		"disable this check.");
+
+struct mc13783_ts_priv {
+	struct input_dev *idev;
+	struct mc13xxx *mc13xxx;
+	struct delayed_work work;
+	struct workqueue_struct *workq;
+	unsigned int sample[4];
+	struct mc13xxx_ts_platform_data *touch;
+};
+
+static irqreturn_t mc13783_ts_handler(int irq, void *data)
+{
+	struct mc13783_ts_priv *priv = data;
+
+	mc13xxx_irq_ack(priv->mc13xxx, irq);
+
+	/*
+	 * Kick off reading coordinates. Note that if work happens already
+	 * be queued for future execution (it rearms itself) it will not
+	 * be rescheduled for immediate execution here. However the rearm
+	 * delay is HZ / 50 which is acceptable.
+	 */
+	queue_delayed_work(priv->workq, &priv->work, 0);
+
+	return IRQ_HANDLED;
+}
+
+#define sort3(a0, a1, a2) ({						\
+		if (a0 > a1)						\
+			swap(a0, a1);					\
+		if (a1 > a2)						\
+			swap(a1, a2);					\
+		if (a0 > a1)						\
+			swap(a0, a1);					\
+		})
+
+static void mc13783_ts_report_sample(struct mc13783_ts_priv *priv)
+{
+	struct input_dev *idev = priv->idev;
+	int x0, x1, x2, y0, y1, y2;
+	int cr0, cr1;
+
+	/*
+	 * the values are 10-bit wide only, but the two least significant
+	 * bits are for future 12 bit use and reading yields 0
+	 */
+	x0 = priv->sample[0] & 0xfff;
+	x1 = priv->sample[1] & 0xfff;
+	x2 = priv->sample[2] & 0xfff;
+	y0 = priv->sample[3] & 0xfff;
+	y1 = (priv->sample[0] >> 12) & 0xfff;
+	y2 = (priv->sample[1] >> 12) & 0xfff;
+	cr0 = (priv->sample[2] >> 12) & 0xfff;
+	cr1 = (priv->sample[3] >> 12) & 0xfff;
+
+	dev_dbg(&idev->dev,
+		"x: (% 4d,% 4d,% 4d) y: (% 4d, % 4d,% 4d) cr: (% 4d, % 4d)\n",
+		x0, x1, x2, y0, y1, y2, cr0, cr1);
+
+	sort3(x0, x1, x2);
+	sort3(y0, y1, y2);
+
+	cr0 = (cr0 + cr1) / 2;
+
+	if (!cr0 || !sample_tolerance ||
+			(x2 - x0 < sample_tolerance &&
+			 y2 - y0 < sample_tolerance)) {
+		/* report the median coordinate and average pressure */
+		if (cr0) {
+			input_report_abs(idev, ABS_X, x1);
+			input_report_abs(idev, ABS_Y, y1);
+
+			dev_dbg(&idev->dev, "report (%d, %d, %d)\n",
+					x1, y1, 0x1000 - cr0);
+			queue_delayed_work(priv->workq, &priv->work, HZ / 50);
+		} else
+			dev_dbg(&idev->dev, "report release\n");
+
+		input_report_abs(idev, ABS_PRESSURE,
+				cr0 ? 0x1000 - cr0 : cr0);
+		input_report_key(idev, BTN_TOUCH, cr0);
+		input_sync(idev);
+	} else
+		dev_dbg(&idev->dev, "discard event\n");
+}
+
+static void mc13783_ts_work(struct work_struct *work)
+{
+	struct mc13783_ts_priv *priv =
+		container_of(work, struct mc13783_ts_priv, work.work);
+	unsigned int mode = MC13XXX_ADC_MODE_TS;
+	unsigned int channel = 12;
+
+	if (mc13xxx_adc_do_conversion(priv->mc13xxx,
+				mode, channel,
+				priv->touch->ato, priv->touch->atox,
+				priv->sample) == 0)
+		mc13783_ts_report_sample(priv);
+}
+
+static int mc13783_ts_open(struct input_dev *dev)
+{
+	struct mc13783_ts_priv *priv = input_get_drvdata(dev);
+	int ret;
+
+	mc13xxx_lock(priv->mc13xxx);
+
+	mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TS);
+
+	ret = mc13xxx_irq_request(priv->mc13xxx, MC13XXX_IRQ_TS,
+		mc13783_ts_handler, MC13783_TS_NAME, priv);
+	if (ret)
+		goto out;
+
+	ret = mc13xxx_reg_rmw(priv->mc13xxx, MC13XXX_ADC0,
+			MC13XXX_ADC0_TSMOD_MASK, MC13XXX_ADC0_TSMOD0);
+	if (ret)
+		mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TS, priv);
+out:
+	mc13xxx_unlock(priv->mc13xxx);
+	return ret;
+}
+
+static void mc13783_ts_close(struct input_dev *dev)
+{
+	struct mc13783_ts_priv *priv = input_get_drvdata(dev);
+
+	mc13xxx_lock(priv->mc13xxx);
+	mc13xxx_reg_rmw(priv->mc13xxx, MC13XXX_ADC0,
+			MC13XXX_ADC0_TSMOD_MASK, 0);
+	mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TS, priv);
+	mc13xxx_unlock(priv->mc13xxx);
+
+	cancel_delayed_work_sync(&priv->work);
+}
+
+static int __init mc13783_ts_probe(struct platform_device *pdev)
+{
+	struct mc13783_ts_priv *priv;
+	struct input_dev *idev;
+	int ret = -ENOMEM;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	idev = input_allocate_device();
+	if (!priv || !idev)
+		goto err_free_mem;
+
+	INIT_DELAYED_WORK(&priv->work, mc13783_ts_work);
+	priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
+	priv->idev = idev;
+	priv->touch = dev_get_platdata(&pdev->dev);
+	if (!priv->touch) {
+		dev_err(&pdev->dev, "missing platform data\n");
+		ret = -ENODEV;
+		goto err_free_mem;
+	}
+
+	/*
+	 * We need separate workqueue because mc13783_adc_do_conversion
+	 * uses keventd and thus would deadlock.
+	 */
+	priv->workq = create_singlethread_workqueue("mc13783_ts");
+	if (!priv->workq)
+		goto err_free_mem;
+
+	idev->name = MC13783_TS_NAME;
+	idev->dev.parent = &pdev->dev;
+
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0);
+	input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0);
+	input_set_abs_params(idev, ABS_PRESSURE, 0, 0xfff, 0, 0);
+
+	idev->open = mc13783_ts_open;
+	idev->close = mc13783_ts_close;
+
+	input_set_drvdata(idev, priv);
+
+	ret = input_register_device(priv->idev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"register input device failed with %d\n", ret);
+		goto err_destroy_wq;
+	}
+
+	platform_set_drvdata(pdev, priv);
+	return 0;
+
+err_destroy_wq:
+	destroy_workqueue(priv->workq);
+err_free_mem:
+	input_free_device(idev);
+	kfree(priv);
+	return ret;
+}
+
+static int __devexit mc13783_ts_remove(struct platform_device *pdev)
+{
+	struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	destroy_workqueue(priv->workq);
+	input_unregister_device(priv->idev);
+	kfree(priv);
+
+	return 0;
+}
+
+static struct platform_driver mc13783_ts_driver = {
+	.remove		= __devexit_p(mc13783_ts_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= MC13783_TS_NAME,
+	},
+};
+
+static int __init mc13783_ts_init(void)
+{
+	return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
+}
+module_init(mc13783_ts_init);
+
+static void __exit mc13783_ts_exit(void)
+{
+	platform_driver_unregister(&mc13783_ts_driver);
+}
+module_exit(mc13783_ts_exit);
+
+MODULE_DESCRIPTION("MC13783 input touchscreen driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" MC13783_TS_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mcs5000_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mcs5000_ts.c
new file mode 100644
index 0000000..b528511
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mcs5000_ts.c
@@ -0,0 +1,310 @@
+/*
+ * mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * Based on wm97xx-core.c
+ *
+ *  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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/mcs.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+
+/* Registers */
+#define MCS5000_TS_STATUS		0x00
+#define STATUS_OFFSET			0
+#define STATUS_NO			(0 << STATUS_OFFSET)
+#define STATUS_INIT			(1 << STATUS_OFFSET)
+#define STATUS_SENSING			(2 << STATUS_OFFSET)
+#define STATUS_COORD			(3 << STATUS_OFFSET)
+#define STATUS_GESTURE			(4 << STATUS_OFFSET)
+#define ERROR_OFFSET			4
+#define ERROR_NO			(0 << ERROR_OFFSET)
+#define ERROR_POWER_ON_RESET		(1 << ERROR_OFFSET)
+#define ERROR_INT_RESET			(2 << ERROR_OFFSET)
+#define ERROR_EXT_RESET			(3 << ERROR_OFFSET)
+#define ERROR_INVALID_REG_ADDRESS	(8 << ERROR_OFFSET)
+#define ERROR_INVALID_REG_VALUE		(9 << ERROR_OFFSET)
+
+#define MCS5000_TS_OP_MODE		0x01
+#define RESET_OFFSET			0
+#define RESET_NO			(0 << RESET_OFFSET)
+#define RESET_EXT_SOFT			(1 << RESET_OFFSET)
+#define OP_MODE_OFFSET			1
+#define OP_MODE_SLEEP			(0 << OP_MODE_OFFSET)
+#define OP_MODE_ACTIVE			(1 << OP_MODE_OFFSET)
+#define GESTURE_OFFSET			4
+#define GESTURE_DISABLE			(0 << GESTURE_OFFSET)
+#define GESTURE_ENABLE			(1 << GESTURE_OFFSET)
+#define PROXIMITY_OFFSET		5
+#define PROXIMITY_DISABLE		(0 << PROXIMITY_OFFSET)
+#define PROXIMITY_ENABLE		(1 << PROXIMITY_OFFSET)
+#define SCAN_MODE_OFFSET		6
+#define SCAN_MODE_INTERRUPT		(0 << SCAN_MODE_OFFSET)
+#define SCAN_MODE_POLLING		(1 << SCAN_MODE_OFFSET)
+#define REPORT_RATE_OFFSET		7
+#define REPORT_RATE_40			(0 << REPORT_RATE_OFFSET)
+#define REPORT_RATE_80			(1 << REPORT_RATE_OFFSET)
+
+#define MCS5000_TS_SENS_CTL		0x02
+#define MCS5000_TS_FILTER_CTL		0x03
+#define PRI_FILTER_OFFSET		0
+#define SEC_FILTER_OFFSET		4
+
+#define MCS5000_TS_X_SIZE_UPPER		0x08
+#define MCS5000_TS_X_SIZE_LOWER		0x09
+#define MCS5000_TS_Y_SIZE_UPPER		0x0A
+#define MCS5000_TS_Y_SIZE_LOWER		0x0B
+
+#define MCS5000_TS_INPUT_INFO		0x10
+#define INPUT_TYPE_OFFSET		0
+#define INPUT_TYPE_NONTOUCH		(0 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_SINGLE		(1 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_DUAL			(2 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_PALM			(3 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_PROXIMITY		(7 << INPUT_TYPE_OFFSET)
+#define GESTURE_CODE_OFFSET		3
+#define GESTURE_CODE_NO			(0 << GESTURE_CODE_OFFSET)
+
+#define MCS5000_TS_X_POS_UPPER		0x11
+#define MCS5000_TS_X_POS_LOWER		0x12
+#define MCS5000_TS_Y_POS_UPPER		0x13
+#define MCS5000_TS_Y_POS_LOWER		0x14
+#define MCS5000_TS_Z_POS		0x15
+#define MCS5000_TS_WIDTH		0x16
+#define MCS5000_TS_GESTURE_VAL		0x17
+#define MCS5000_TS_MODULE_REV		0x20
+#define MCS5000_TS_FIRMWARE_VER		0x21
+
+/* Touchscreen absolute values */
+#define MCS5000_MAX_XC			0x3ff
+#define MCS5000_MAX_YC			0x3ff
+
+enum mcs5000_ts_read_offset {
+	READ_INPUT_INFO,
+	READ_X_POS_UPPER,
+	READ_X_POS_LOWER,
+	READ_Y_POS_UPPER,
+	READ_Y_POS_LOWER,
+	READ_BLOCK_SIZE,
+};
+
+/* Each client has this additional data */
+struct mcs5000_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	const struct mcs_platform_data *platform_data;
+};
+
+static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
+{
+	struct mcs5000_ts_data *data = dev_id;
+	struct i2c_client *client = data->client;
+	u8 buffer[READ_BLOCK_SIZE];
+	int err;
+	int x;
+	int y;
+
+	err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
+			READ_BLOCK_SIZE, buffer);
+	if (err < 0) {
+		dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
+		goto out;
+	}
+
+	switch (buffer[READ_INPUT_INFO]) {
+	case INPUT_TYPE_NONTOUCH:
+		input_report_key(data->input_dev, BTN_TOUCH, 0);
+		input_sync(data->input_dev);
+		break;
+
+	case INPUT_TYPE_SINGLE:
+		x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
+		y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
+
+		input_report_key(data->input_dev, BTN_TOUCH, 1);
+		input_report_abs(data->input_dev, ABS_X, x);
+		input_report_abs(data->input_dev, ABS_Y, y);
+		input_sync(data->input_dev);
+		break;
+
+	case INPUT_TYPE_DUAL:
+		/* TODO */
+		break;
+
+	case INPUT_TYPE_PALM:
+		/* TODO */
+		break;
+
+	case INPUT_TYPE_PROXIMITY:
+		/* TODO */
+		break;
+
+	default:
+		dev_err(&client->dev, "Unknown ts input type %d\n",
+				buffer[READ_INPUT_INFO]);
+		break;
+	}
+
+ out:
+	return IRQ_HANDLED;
+}
+
+static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
+{
+	const struct mcs_platform_data *platform_data =
+		data->platform_data;
+	struct i2c_client *client = data->client;
+
+	/* Touch reset & sleep mode */
+	i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
+			RESET_EXT_SOFT | OP_MODE_SLEEP);
+
+	/* Touch size */
+	i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
+			platform_data->x_size >> 8);
+	i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
+			platform_data->x_size & 0xff);
+	i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
+			platform_data->y_size >> 8);
+	i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
+			platform_data->y_size & 0xff);
+
+	/* Touch active mode & 80 report rate */
+	i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
+			OP_MODE_ACTIVE | REPORT_RATE_80);
+}
+
+static int __devinit mcs5000_ts_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct mcs5000_ts_data *data;
+	struct input_dev *input_dev;
+	int ret;
+
+	if (!client->dev.platform_data)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		ret = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	data->client = client;
+	data->input_dev = input_dev;
+	data->platform_data = client->dev.platform_data;
+
+	input_dev->name = "MELPAS MCS-5000 Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
+
+	input_set_drvdata(input_dev, data);
+
+	if (data->platform_data->cfg_pin)
+		data->platform_data->cfg_pin();
+
+	ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt,
+			IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data);
+
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	ret = input_register_device(data->input_dev);
+	if (ret < 0)
+		goto err_free_irq;
+
+	mcs5000_ts_phys_init(data);
+	i2c_set_clientdata(client, data);
+
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+	return ret;
+}
+
+static int __devexit mcs5000_ts_remove(struct i2c_client *client)
+{
+	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
+
+	free_irq(client->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcs5000_ts_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	/* Touch sleep mode */
+	i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
+
+	return 0;
+}
+
+static int mcs5000_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct mcs5000_ts_data *data = i2c_get_clientdata(client);
+
+	mcs5000_ts_phys_init(data);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
+#endif
+
+static const struct i2c_device_id mcs5000_ts_id[] = {
+	{ "mcs5000_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
+
+static struct i2c_driver mcs5000_ts_driver = {
+	.probe		= mcs5000_ts_probe,
+	.remove		= __devexit_p(mcs5000_ts_remove),
+	.driver = {
+		.name = "mcs5000_ts",
+#ifdef CONFIG_PM
+		.pm   = &mcs5000_ts_pm,
+#endif
+	},
+	.id_table	= mcs5000_ts_id,
+};
+
+module_i2c_driver(mcs5000_ts_driver);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MELFAS MCS-5000 controller");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/migor_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/migor_ts.c
new file mode 100644
index 0000000..c038db9
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/migor_ts.c
@@ -0,0 +1,249 @@
+/*
+ * Touch Screen driver for Renesas MIGO-R Platform
+ *
+ * Copyright (c) 2008 Magnus Damm
+ * Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>,
+ *  Kenati Technologies Pvt Ltd.
+ *
+ * This file 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 file 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+
+#define EVENT_PENDOWN 1
+#define EVENT_REPEAT  2
+#define EVENT_PENUP   3
+
+struct migor_ts_priv {
+	struct i2c_client *client;
+	struct input_dev *input;
+	int irq;
+};
+
+static const u_int8_t migor_ts_ena_seq[17] = { 0x33, 0x22, 0x11,
+					       0x01, 0x06, 0x07, };
+static const u_int8_t migor_ts_dis_seq[17] = { };
+
+static irqreturn_t migor_ts_isr(int irq, void *dev_id)
+{
+	struct migor_ts_priv *priv = dev_id;
+	unsigned short xpos, ypos;
+	unsigned char event;
+	u_int8_t buf[16];
+
+	/*
+	 * The touch screen controller chip is hooked up to the CPU
+	 * using I2C and a single interrupt line. The interrupt line
+	 * is pulled low whenever someone taps the screen. To deassert
+	 * the interrupt line we need to acknowledge the interrupt by
+	 * communicating with the controller over the slow i2c bus.
+	 *
+	 * Since I2C bus controller may sleep we are using threaded
+	 * IRQ here.
+	 */
+
+	memset(buf, 0, sizeof(buf));
+
+	/* Set Index 0 */
+	buf[0] = 0;
+	if (i2c_master_send(priv->client, buf, 1) != 1) {
+		dev_err(&priv->client->dev, "Unable to write i2c index\n");
+		goto out;
+	}
+
+	/* Now do Page Read */
+	if (i2c_master_recv(priv->client, buf, sizeof(buf)) != sizeof(buf)) {
+		dev_err(&priv->client->dev, "Unable to read i2c page\n");
+		goto out;
+	}
+
+	ypos = ((buf[9] & 0x03) << 8 | buf[8]);
+	xpos = ((buf[11] & 0x03) << 8 | buf[10]);
+	event = buf[12];
+
+	switch (event) {
+	case EVENT_PENDOWN:
+	case EVENT_REPEAT:
+		input_report_key(priv->input, BTN_TOUCH, 1);
+		input_report_abs(priv->input, ABS_X, ypos); /*X-Y swap*/
+		input_report_abs(priv->input, ABS_Y, xpos);
+		input_sync(priv->input);
+		break;
+
+	case EVENT_PENUP:
+		input_report_key(priv->input, BTN_TOUCH, 0);
+		input_sync(priv->input);
+		break;
+	}
+
+ out:
+	return IRQ_HANDLED;
+}
+
+static int migor_ts_open(struct input_dev *dev)
+{
+	struct migor_ts_priv *priv = input_get_drvdata(dev);
+	struct i2c_client *client = priv->client;
+	int count;
+
+	/* enable controller */
+	count = i2c_master_send(client, migor_ts_ena_seq,
+				sizeof(migor_ts_ena_seq));
+	if (count != sizeof(migor_ts_ena_seq)) {
+		dev_err(&client->dev, "Unable to enable touchscreen.\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void migor_ts_close(struct input_dev *dev)
+{
+	struct migor_ts_priv *priv = input_get_drvdata(dev);
+	struct i2c_client *client = priv->client;
+
+	disable_irq(priv->irq);
+
+	/* disable controller */
+	i2c_master_send(client, migor_ts_dis_seq, sizeof(migor_ts_dis_seq));
+
+	enable_irq(priv->irq);
+}
+
+static int migor_ts_probe(struct i2c_client *client,
+			  const struct i2c_device_id *idp)
+{
+	struct migor_ts_priv *priv;
+	struct input_dev *input;
+	int error;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!priv || !input) {
+		dev_err(&client->dev, "failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	priv->client = client;
+	priv->input = input;
+	priv->irq = client->irq;
+
+	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+
+	__set_bit(BTN_TOUCH, input->keybit);
+
+	input_set_abs_params(input, ABS_X, 95, 955, 0, 0);
+	input_set_abs_params(input, ABS_Y, 85, 935, 0, 0);
+
+	input->name = client->name;
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &client->dev;
+
+	input->open = migor_ts_open;
+	input->close = migor_ts_close;
+
+	input_set_drvdata(input, priv);
+
+	error = request_threaded_irq(priv->irq, NULL, migor_ts_isr,
+                                     IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                     client->name, priv);
+	if (error) {
+		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(input);
+	if (error)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, priv);
+	device_init_wakeup(&client->dev, 1);
+
+	return 0;
+
+ err_free_irq:
+	free_irq(priv->irq, priv);
+ err_free_mem:
+	input_free_device(input);
+	kfree(priv);
+	return error;
+}
+
+static int migor_ts_remove(struct i2c_client *client)
+{
+	struct migor_ts_priv *priv = i2c_get_clientdata(client);
+
+	free_irq(priv->irq, priv);
+	input_unregister_device(priv->input);
+	kfree(priv);
+
+	dev_set_drvdata(&client->dev, NULL);
+
+	return 0;
+}
+
+static int migor_ts_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct migor_ts_priv *priv = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(priv->irq);
+
+	return 0;
+}
+
+static int migor_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct migor_ts_priv *priv = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(priv->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
+
+static const struct i2c_device_id migor_ts_id[] = {
+	{ "migor_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, migor_ts);
+
+static struct i2c_driver migor_ts_driver = {
+	.driver = {
+		.name = "migor_ts",
+		.pm = &migor_ts_pm,
+	},
+	.probe = migor_ts_probe,
+	.remove = migor_ts_remove,
+	.id_table = migor_ts_id,
+};
+
+module_i2c_driver(migor_ts_driver);
+
+MODULE_DESCRIPTION("MigoR Touchscreen driver");
+MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mk712.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mk712.c
new file mode 100644
index 0000000..36e57de
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mk712.c
@@ -0,0 +1,219 @@
+/*
+ * ICS MK712 touchscreen controller driver
+ *
+ * Copyright (c) 1999-2002 Transmeta Corporation
+ * Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * This driver supports the ICS MicroClock MK712 TouchScreen controller,
+ * found in Gateway AOL Connected Touchpad computers.
+ *
+ * Documentation for ICS MK712 can be found at:
+ *	http://www.idt.com/products/getDoc.cfm?docID=18713923
+ */
+
+/*
+ * 1999-12-18: original version, Daniel Quinlan
+ * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
+ *             to use queue_empty, Nathan Laredo
+ * 1999-12-20: improved random point rejection, Nathan Laredo
+ * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
+ *             queue code, added module options, other fixes, Daniel Quinlan
+ * 2002-03-15: Clean up for kernel merge <alan@redhat.com>
+ *             Fixed multi open race, fixed memory checks, fixed resource
+ *             allocation, fixed close/powerdown bug, switched to new init
+ * 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
+ * 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <asm/io.h>
+
+MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
+MODULE_LICENSE("GPL");
+
+static unsigned int mk712_io = 0x260;	/* Also 0x200, 0x208, 0x300 */
+module_param_named(io, mk712_io, uint, 0);
+MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
+
+static unsigned int mk712_irq = 10;	/* Also 12, 14, 15 */
+module_param_named(irq, mk712_irq, uint, 0);
+MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
+
+/* eight 8-bit registers */
+#define MK712_STATUS		0
+#define MK712_X			2
+#define MK712_Y			4
+#define MK712_CONTROL		6
+#define MK712_RATE		7
+
+/* status */
+#define	MK712_STATUS_TOUCH			0x10
+#define	MK712_CONVERSION_COMPLETE		0x80
+
+/* control */
+#define MK712_ENABLE_INT			0x01
+#define MK712_INT_ON_CONVERSION_COMPLETE	0x02
+#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS	0x04
+#define MK712_ENABLE_PERIODIC_CONVERSIONS	0x10
+#define MK712_READ_ONE_POINT			0x20
+#define MK712_POWERUP				0x40
+
+static struct input_dev *mk712_dev;
+static DEFINE_SPINLOCK(mk712_lock);
+
+static irqreturn_t mk712_interrupt(int irq, void *dev_id)
+{
+	unsigned char status;
+	static int debounce = 1;
+	static unsigned short last_x;
+	static unsigned short last_y;
+
+	spin_lock(&mk712_lock);
+
+	status = inb(mk712_io + MK712_STATUS);
+
+	if (~status & MK712_CONVERSION_COMPLETE) {
+		debounce = 1;
+		goto end;
+	}
+
+	if (~status & MK712_STATUS_TOUCH) {
+		debounce = 1;
+		input_report_key(mk712_dev, BTN_TOUCH, 0);
+		goto end;
+	}
+
+	if (debounce) {
+		debounce = 0;
+		goto end;
+	}
+
+	input_report_key(mk712_dev, BTN_TOUCH, 1);
+	input_report_abs(mk712_dev, ABS_X, last_x);
+	input_report_abs(mk712_dev, ABS_Y, last_y);
+
+ end:
+	last_x = inw(mk712_io + MK712_X) & 0x0fff;
+	last_y = inw(mk712_io + MK712_Y) & 0x0fff;
+	input_sync(mk712_dev);
+	spin_unlock(&mk712_lock);
+	return IRQ_HANDLED;
+}
+
+static int mk712_open(struct input_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+
+	outb(0, mk712_io + MK712_CONTROL); /* Reset */
+
+	outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+		MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+		MK712_ENABLE_PERIODIC_CONVERSIONS |
+		MK712_POWERUP, mk712_io + MK712_CONTROL);
+
+	outb(10, mk712_io + MK712_RATE); /* 187 points per second */
+
+	spin_unlock_irqrestore(&mk712_lock, flags);
+
+	return 0;
+}
+
+static void mk712_close(struct input_dev *dev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mk712_lock, flags);
+
+	outb(0, mk712_io + MK712_CONTROL);
+
+	spin_unlock_irqrestore(&mk712_lock, flags);
+}
+
+static int __init mk712_init(void)
+{
+	int err;
+
+	if (!request_region(mk712_io, 8, "mk712")) {
+		printk(KERN_WARNING "mk712: unable to get IO region\n");
+		return -ENODEV;
+	}
+
+	outb(0, mk712_io + MK712_CONTROL);
+
+	if ((inw(mk712_io + MK712_X) & 0xf000) ||	/* Sanity check */
+	    (inw(mk712_io + MK712_Y) & 0xf000) ||
+	    (inw(mk712_io + MK712_STATUS) & 0xf333)) {
+		printk(KERN_WARNING "mk712: device not present\n");
+		err = -ENODEV;
+		goto fail1;
+	}
+
+	mk712_dev = input_allocate_device();
+	if (!mk712_dev) {
+		printk(KERN_ERR "mk712: not enough memory\n");
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	mk712_dev->name = "ICS MicroClock MK712 TouchScreen";
+	mk712_dev->phys = "isa0260/input0";
+	mk712_dev->id.bustype = BUS_ISA;
+	mk712_dev->id.vendor  = 0x0005;
+	mk712_dev->id.product = 0x0001;
+	mk712_dev->id.version = 0x0100;
+
+	mk712_dev->open    = mk712_open;
+	mk712_dev->close   = mk712_close;
+
+	mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);
+	input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);
+
+	if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {
+		printk(KERN_WARNING "mk712: unable to get IRQ\n");
+		err = -EBUSY;
+		goto fail1;
+	}
+
+	err = input_register_device(mk712_dev);
+	if (err)
+		goto fail2;
+
+	return 0;
+
+ fail2:	free_irq(mk712_irq, mk712_dev);
+ fail1:	input_free_device(mk712_dev);
+	release_region(mk712_io, 8);
+	return err;
+}
+
+static void __exit mk712_exit(void)
+{
+	input_unregister_device(mk712_dev);
+	free_irq(mk712_irq, mk712_dev);
+	release_region(mk712_io, 8);
+}
+
+module_init(mk712_init);
+module_exit(mk712_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mtouch.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mtouch.c
new file mode 100644
index 0000000..9077228
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/mtouch.c
@@ -0,0 +1,220 @@
+/*
+ * MicroTouch (3M) serial touchscreen driver
+ *
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * 2005/02/19 Dan Streetman <ddstreet@ieee.org>
+ *   Copied elo.c and edited for MicroTouch protocol
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"MicroTouch serial touchscreen driver"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define MTOUCH_FORMAT_TABLET_STATUS_BIT 0x80
+#define MTOUCH_FORMAT_TABLET_TOUCH_BIT 0x40
+#define MTOUCH_FORMAT_TABLET_LENGTH 5
+#define MTOUCH_RESPONSE_BEGIN_BYTE 0x01
+#define MTOUCH_RESPONSE_END_BYTE 0x0d
+
+/* todo: check specs for max length of all responses */
+#define MTOUCH_MAX_LENGTH 16
+
+#define MTOUCH_MIN_XC 0
+#define MTOUCH_MAX_XC 0x3fff
+#define MTOUCH_MIN_YC 0
+#define MTOUCH_MAX_YC 0x3fff
+
+#define MTOUCH_GET_XC(data) (((data[2])<<7) | data[1])
+#define MTOUCH_GET_YC(data) (((data[4])<<7) | data[3])
+#define MTOUCH_GET_TOUCHED(data) (MTOUCH_FORMAT_TABLET_TOUCH_BIT & data[0])
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct mtouch {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[MTOUCH_MAX_LENGTH];
+	char phys[32];
+};
+
+static void mtouch_process_format_tablet(struct mtouch *mtouch)
+{
+	struct input_dev *dev = mtouch->dev;
+
+	if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) {
+		input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data));
+		input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data));
+		input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data));
+		input_sync(dev);
+
+		mtouch->idx = 0;
+	}
+}
+
+static void mtouch_process_response(struct mtouch *mtouch)
+{
+	if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) {
+		/* FIXME - process response */
+		mtouch->idx = 0;
+	} else if (MTOUCH_MAX_LENGTH == mtouch->idx) {
+		printk(KERN_ERR "mtouch.c: too many response bytes\n");
+		mtouch->idx = 0;
+	}
+}
+
+static irqreturn_t mtouch_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct mtouch* mtouch = serio_get_drvdata(serio);
+
+	mtouch->data[mtouch->idx] = data;
+
+	if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
+		mtouch_process_format_tablet(mtouch);
+	else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
+		mtouch_process_response(mtouch);
+	else
+		printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * mtouch_disconnect() is the opposite of mtouch_connect()
+ */
+
+static void mtouch_disconnect(struct serio *serio)
+{
+	struct mtouch* mtouch = serio_get_drvdata(serio);
+
+	input_get_device(mtouch->dev);
+	input_unregister_device(mtouch->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(mtouch->dev);
+	kfree(mtouch);
+}
+
+/*
+ * mtouch_connect() is the routine that is called when someone adds a
+ * new serio device that supports MicroTouch (Format Tablet) protocol and registers it as
+ * an input device.
+ */
+
+static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct mtouch *mtouch;
+	struct input_dev *input_dev;
+	int err;
+
+	mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!mtouch || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	mtouch->serio = serio;
+	mtouch->dev = input_dev;
+	snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "MicroTouch Serial TouchScreen";
+	input_dev->phys = mtouch->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_MICROTOUCH;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
+	input_set_abs_params(mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0);
+
+	serio_set_drvdata(serio, mtouch);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(mtouch->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(mtouch);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id mtouch_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_MICROTOUCH,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, mtouch_serio_ids);
+
+static struct serio_driver mtouch_drv = {
+	.driver		= {
+		.name	= "mtouch",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= mtouch_serio_ids,
+	.interrupt	= mtouch_interrupt,
+	.connect	= mtouch_connect,
+	.disconnect	= mtouch_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init mtouch_init(void)
+{
+	return serio_register_driver(&mtouch_drv);
+}
+
+static void __exit mtouch_exit(void)
+{
+	serio_unregister_driver(&mtouch_drv);
+}
+
+module_init(mtouch_init);
+module_exit(mtouch_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/pcap_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/pcap_ts.c
new file mode 100644
index 0000000..f57aeb8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/pcap_ts.c
@@ -0,0 +1,260 @@
+/*
+ * Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform.
+ *
+ *  Copyright (C) 2006 Harald Welte <laforge@openezx.org>
+ *  Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/mfd/ezx-pcap.h>
+
+struct pcap_ts {
+	struct pcap_chip *pcap;
+	struct input_dev *input;
+	struct delayed_work work;
+	u16 x, y;
+	u16 pressure;
+	u8 read_state;
+};
+
+#define SAMPLE_DELAY	20 /* msecs */
+
+#define X_AXIS_MIN	0
+#define X_AXIS_MAX	1023
+#define Y_AXIS_MAX	X_AXIS_MAX
+#define Y_AXIS_MIN	X_AXIS_MIN
+#define PRESSURE_MAX	X_AXIS_MAX
+#define PRESSURE_MIN	X_AXIS_MIN
+
+static void pcap_ts_read_xy(void *data, u16 res[2])
+{
+	struct pcap_ts *pcap_ts = data;
+
+	switch (pcap_ts->read_state) {
+	case PCAP_ADC_TS_M_PRESSURE:
+		/* pressure reading is unreliable */
+		if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX)
+			pcap_ts->pressure = res[0];
+		pcap_ts->read_state = PCAP_ADC_TS_M_XY;
+		schedule_delayed_work(&pcap_ts->work, 0);
+		break;
+	case PCAP_ADC_TS_M_XY:
+		pcap_ts->y = res[0];
+		pcap_ts->x = res[1];
+		if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX ||
+		    pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) {
+			/* pen has been released */
+			input_report_abs(pcap_ts->input, ABS_PRESSURE, 0);
+			input_report_key(pcap_ts->input, BTN_TOUCH, 0);
+
+			pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
+			schedule_delayed_work(&pcap_ts->work, 0);
+		} else {
+			/* pen is touching the screen */
+			input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x);
+			input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y);
+			input_report_key(pcap_ts->input, BTN_TOUCH, 1);
+			input_report_abs(pcap_ts->input, ABS_PRESSURE,
+						pcap_ts->pressure);
+
+			/* switch back to pressure read mode */
+			pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
+			schedule_delayed_work(&pcap_ts->work,
+					msecs_to_jiffies(SAMPLE_DELAY));
+		}
+		input_sync(pcap_ts->input);
+		break;
+	default:
+		dev_warn(&pcap_ts->input->dev,
+				"pcap_ts: Warning, unhandled read_state %d\n",
+				pcap_ts->read_state);
+		break;
+	}
+}
+
+static void pcap_ts_work(struct work_struct *work)
+{
+	struct delayed_work *dw = container_of(work, struct delayed_work, work);
+	struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work);
+	u8 ch[2];
+
+	pcap_set_ts_bits(pcap_ts->pcap,
+			pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
+
+	if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY)
+		return;
+
+	/* start adc conversion */
+	ch[0] = PCAP_ADC_CH_TS_X1;
+	ch[1] = PCAP_ADC_CH_TS_Y1;
+	pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch,
+						pcap_ts_read_xy, pcap_ts);
+}
+
+static irqreturn_t pcap_ts_event_touch(int pirq, void *data)
+{
+	struct pcap_ts *pcap_ts = data;
+
+	if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) {
+		pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
+		schedule_delayed_work(&pcap_ts->work, 0);
+	}
+	return IRQ_HANDLED;
+}
+
+static int pcap_ts_open(struct input_dev *dev)
+{
+	struct pcap_ts *pcap_ts = input_get_drvdata(dev);
+
+	pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
+	schedule_delayed_work(&pcap_ts->work, 0);
+
+	return 0;
+}
+
+static void pcap_ts_close(struct input_dev *dev)
+{
+	struct pcap_ts *pcap_ts = input_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&pcap_ts->work);
+
+	pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
+	pcap_set_ts_bits(pcap_ts->pcap,
+				pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
+}
+
+static int __devinit pcap_ts_probe(struct platform_device *pdev)
+{
+	struct input_dev *input_dev;
+	struct pcap_ts *pcap_ts;
+	int err = -ENOMEM;
+
+	pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL);
+	if (!pcap_ts)
+		return err;
+
+	pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent);
+	platform_set_drvdata(pdev, pcap_ts);
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		goto fail;
+
+	INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work);
+
+	pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
+	pcap_set_ts_bits(pcap_ts->pcap,
+				pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
+
+	pcap_ts->input = input_dev;
+	input_set_drvdata(input_dev, pcap_ts);
+
+	input_dev->name = "pcap-touchscreen";
+	input_dev->phys = "pcap_ts/input0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor = 0x0001;
+	input_dev->id.product = 0x0002;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = pcap_ts_open;
+	input_dev->close = pcap_ts_close;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN,
+			     PRESSURE_MAX, 0, 0);
+
+	err = input_register_device(pcap_ts->input);
+	if (err)
+		goto fail_allocate;
+
+	err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS),
+			pcap_ts_event_touch, 0, "Touch Screen", pcap_ts);
+	if (err)
+		goto fail_register;
+
+	return 0;
+
+fail_register:
+	input_unregister_device(input_dev);
+	goto fail;
+fail_allocate:
+	input_free_device(input_dev);
+fail:
+	kfree(pcap_ts);
+
+	return err;
+}
+
+static int __devexit pcap_ts_remove(struct platform_device *pdev)
+{
+	struct pcap_ts *pcap_ts = platform_get_drvdata(pdev);
+
+	free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts);
+	cancel_delayed_work_sync(&pcap_ts->work);
+
+	input_unregister_device(pcap_ts->input);
+
+	kfree(pcap_ts);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pcap_ts_suspend(struct device *dev)
+{
+	struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
+
+	pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR);
+	return 0;
+}
+
+static int pcap_ts_resume(struct device *dev)
+{
+	struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
+
+	pcap_set_ts_bits(pcap_ts->pcap,
+				pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
+	return 0;
+}
+
+static const struct dev_pm_ops pcap_ts_pm_ops = {
+	.suspend	= pcap_ts_suspend,
+	.resume		= pcap_ts_resume,
+};
+#define PCAP_TS_PM_OPS (&pcap_ts_pm_ops)
+#else
+#define PCAP_TS_PM_OPS NULL
+#endif
+
+static struct platform_driver pcap_ts_driver = {
+	.probe		= pcap_ts_probe,
+	.remove		= __devexit_p(pcap_ts_remove),
+	.driver		= {
+		.name	= "pcap-ts",
+		.owner	= THIS_MODULE,
+		.pm	= PCAP_TS_PM_OPS,
+	},
+};
+module_platform_driver(pcap_ts_driver);
+
+MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver");
+MODULE_AUTHOR("Daniel Ribeiro / Harald Welte");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcap_ts");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/penmount.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/penmount.c
new file mode 100644
index 0000000..4c012fb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/penmount.c
@@ -0,0 +1,335 @@
+/*
+ * Penmount serial touchscreen driver
+ *
+ * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
+ * Copyright (c) 2011 John Sung <penmount.touch@gmail.com>
+ *
+ * Based on ELO driver (drivers/input/touchscreen/elo.c)
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"PenMount serial touchscreen driver"
+
+MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
+MODULE_AUTHOR("John Sung <penmount.touch@gmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define	PM_MAX_LENGTH	6
+#define	PM_MAX_MTSLOT	16
+#define	PM_3000_MTSLOT	2
+#define	PM_6250_MTSLOT	12
+
+/*
+ * Multi-touch slot
+ */
+
+struct mt_slot {
+	unsigned short x, y;
+	bool active; /* is the touch valid? */
+};
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct pm {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[PM_MAX_LENGTH];
+	char phys[32];
+	unsigned char packetsize;
+	unsigned char maxcontacts;
+	struct mt_slot slots[PM_MAX_MTSLOT];
+	void (*parse_packet)(struct pm *);
+};
+
+/*
+ * pm_mtevent() sends mt events and also emulates pointer movement
+ */
+
+static void pm_mtevent(struct pm *pm, struct input_dev *input)
+{
+	int i;
+
+	for (i = 0; i < pm->maxcontacts; ++i) {
+		input_mt_slot(input, i);
+		input_mt_report_slot_state(input, MT_TOOL_FINGER,
+				pm->slots[i].active);
+		if (pm->slots[i].active) {
+			input_event(input, EV_ABS, ABS_MT_POSITION_X, pm->slots[i].x);
+			input_event(input, EV_ABS, ABS_MT_POSITION_Y, pm->slots[i].y);
+		}
+	}
+
+	input_mt_report_pointer_emulation(input, true);
+	input_sync(input);
+}
+
+/*
+ * pm_checkpacket() checks if data packet is valid
+ */
+
+static bool pm_checkpacket(unsigned char *packet)
+{
+	int total = 0;
+	int i;
+
+	for (i = 0; i < 5; i++)
+		total += packet[i];
+
+	return packet[5] == (unsigned char)~(total & 0xff);
+}
+
+static void pm_parse_9000(struct pm *pm)
+{
+	struct input_dev *dev = pm->dev;
+
+	if ((pm->data[0] & 0x80) && pm->packetsize == ++pm->idx) {
+		input_report_abs(dev, ABS_X, pm->data[1] * 128 + pm->data[2]);
+		input_report_abs(dev, ABS_Y, pm->data[3] * 128 + pm->data[4]);
+		input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
+		input_sync(dev);
+		pm->idx = 0;
+	}
+}
+
+static void pm_parse_6000(struct pm *pm)
+{
+	struct input_dev *dev = pm->dev;
+
+	if ((pm->data[0] & 0xbf) == 0x30 && pm->packetsize == ++pm->idx) {
+		if (pm_checkpacket(pm->data)) {
+			input_report_abs(dev, ABS_X,
+					pm->data[2] * 256 + pm->data[1]);
+			input_report_abs(dev, ABS_Y,
+					pm->data[4] * 256 + pm->data[3]);
+			input_report_key(dev, BTN_TOUCH, pm->data[0] & 0x40);
+			input_sync(dev);
+		}
+		pm->idx = 0;
+	}
+}
+
+static void pm_parse_3000(struct pm *pm)
+{
+	struct input_dev *dev = pm->dev;
+
+	if ((pm->data[0] & 0xce) == 0x40 && pm->packetsize == ++pm->idx) {
+		if (pm_checkpacket(pm->data)) {
+			int slotnum = pm->data[0] & 0x0f;
+			pm->slots[slotnum].active = pm->data[0] & 0x30;
+			pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
+			pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
+			pm_mtevent(pm, dev);
+		}
+		pm->idx = 0;
+	}
+}
+
+static void pm_parse_6250(struct pm *pm)
+{
+	struct input_dev *dev = pm->dev;
+
+	if ((pm->data[0] & 0xb0) == 0x30 && pm->packetsize == ++pm->idx) {
+		if (pm_checkpacket(pm->data)) {
+			int slotnum = pm->data[0] & 0x0f;
+			pm->slots[slotnum].active = pm->data[0] & 0x40;
+			pm->slots[slotnum].x = pm->data[2] * 256 + pm->data[1];
+			pm->slots[slotnum].y = pm->data[4] * 256 + pm->data[3];
+			pm_mtevent(pm, dev);
+		}
+		pm->idx = 0;
+	}
+}
+
+static irqreturn_t pm_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct pm *pm = serio_get_drvdata(serio);
+
+	pm->data[pm->idx] = data;
+
+	pm->parse_packet(pm);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * pm_disconnect() is the opposite of pm_connect()
+ */
+
+static void pm_disconnect(struct serio *serio)
+{
+	struct pm *pm = serio_get_drvdata(serio);
+
+	serio_close(serio);
+
+	input_unregister_device(pm->dev);
+	kfree(pm);
+
+	serio_set_drvdata(serio, NULL);
+}
+
+/*
+ * pm_connect() is the routine that is called when someone adds a
+ * new serio device that supports PenMount protocol and registers it as
+ * an input device.
+ */
+
+static int pm_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct pm *pm;
+	struct input_dev *input_dev;
+	int max_x, max_y;
+	int err;
+
+	pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!pm || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	pm->serio = serio;
+	pm->dev = input_dev;
+	snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
+	pm->maxcontacts = 1;
+
+	input_dev->name = "PenMount Serial TouchScreen";
+	input_dev->phys = pm->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_PENMOUNT;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	switch (serio->id.id) {
+	default:
+	case 0:
+		pm->packetsize = 5;
+		pm->parse_packet = pm_parse_9000;
+		input_dev->id.product = 0x9000;
+		max_x = max_y = 0x3ff;
+		break;
+
+	case 1:
+		pm->packetsize = 6;
+		pm->parse_packet = pm_parse_6000;
+		input_dev->id.product = 0x6000;
+		max_x = max_y = 0x3ff;
+		break;
+
+	case 2:
+		pm->packetsize = 6;
+		pm->parse_packet = pm_parse_3000;
+		input_dev->id.product = 0x3000;
+		max_x = max_y = 0x7ff;
+		pm->maxcontacts = PM_3000_MTSLOT;
+		break;
+
+	case 3:
+		pm->packetsize = 6;
+		pm->parse_packet = pm_parse_6250;
+		input_dev->id.product = 0x6250;
+		max_x = max_y = 0x3ff;
+		pm->maxcontacts = PM_6250_MTSLOT;
+		break;
+	}
+
+	input_set_abs_params(pm->dev, ABS_X, 0, max_x, 0, 0);
+	input_set_abs_params(pm->dev, ABS_Y, 0, max_y, 0, 0);
+
+	if (pm->maxcontacts > 1) {
+		input_mt_init_slots(pm->dev, pm->maxcontacts);
+		input_set_abs_params(pm->dev,
+				     ABS_MT_POSITION_X, 0, max_x, 0, 0);
+		input_set_abs_params(pm->dev,
+				     ABS_MT_POSITION_Y, 0, max_y, 0, 0);
+	}
+
+	serio_set_drvdata(serio, pm);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(pm->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(pm);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id pm_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_PENMOUNT,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, pm_serio_ids);
+
+static struct serio_driver pm_drv = {
+	.driver		= {
+		.name	= "serio-penmount",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= pm_serio_ids,
+	.interrupt	= pm_interrupt,
+	.connect	= pm_connect,
+	.disconnect	= pm_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init pm_init(void)
+{
+	return serio_register_driver(&pm_drv);
+}
+
+static void __exit pm_exit(void)
+{
+	serio_unregister_driver(&pm_drv);
+}
+
+module_init(pm_init);
+module_exit(pm_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/pixcir_i2c_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/pixcir_i2c_ts.c
new file mode 100644
index 0000000..72f6ba3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -0,0 +1,229 @@
+/*
+ * Driver for Pixcir I2C touchscreen controllers.
+ *
+ * Copyright (C) 2010-2011 Pixcir, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/pixcir_ts.h>
+
+struct pixcir_i2c_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input;
+	const struct pixcir_ts_platform_data *chip;
+	bool exiting;
+};
+
+static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+{
+	struct pixcir_i2c_ts_data *tsdata = data;
+	u8 rdbuf[10], wrbuf[1] = { 0 };
+	u8 touch;
+	int ret;
+
+	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
+	if (ret != sizeof(wrbuf)) {
+		dev_err(&tsdata->client->dev,
+			"%s: i2c_master_send failed(), ret=%d\n",
+			__func__, ret);
+		return;
+	}
+
+	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+	if (ret != sizeof(rdbuf)) {
+		dev_err(&tsdata->client->dev,
+			"%s: i2c_master_recv failed(), ret=%d\n",
+			__func__, ret);
+		return;
+	}
+
+	touch = rdbuf[0];
+	if (touch) {
+		u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
+		u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
+		u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
+		u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
+
+		input_report_key(tsdata->input, BTN_TOUCH, 1);
+		input_report_abs(tsdata->input, ABS_X, posx1);
+		input_report_abs(tsdata->input, ABS_Y, posy1);
+
+		input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
+		input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
+		input_mt_sync(tsdata->input);
+
+		if (touch == 2) {
+			input_report_abs(tsdata->input,
+					 ABS_MT_POSITION_X, posx2);
+			input_report_abs(tsdata->input,
+					 ABS_MT_POSITION_Y, posy2);
+			input_mt_sync(tsdata->input);
+		}
+	} else {
+		input_report_key(tsdata->input, BTN_TOUCH, 0);
+	}
+
+	input_sync(tsdata->input);
+}
+
+static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+{
+	struct pixcir_i2c_ts_data *tsdata = dev_id;
+
+	while (!tsdata->exiting) {
+		pixcir_ts_poscheck(tsdata);
+
+		if (tsdata->chip->attb_read_val())
+			break;
+
+		msleep(20);
+	}
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pixcir_i2c_ts_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(client->irq);
+
+	return 0;
+}
+
+static int pixcir_i2c_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(client->irq);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
+			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
+
+static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
+					 const struct i2c_device_id *id)
+{
+	const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
+	struct pixcir_i2c_ts_data *tsdata;
+	struct input_dev *input;
+	int error;
+
+	if (!pdata) {
+		dev_err(&client->dev, "platform data not defined\n");
+		return -EINVAL;
+	}
+
+	tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!tsdata || !input) {
+		dev_err(&client->dev, "Failed to allocate driver data!\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	tsdata->client = client;
+	tsdata->input = input;
+	tsdata->chip = pdata;
+
+	input->name = client->name;
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &client->dev;
+
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(BTN_TOUCH, input->keybit);
+	input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
+
+	input_set_drvdata(input, tsdata);
+
+	error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
+				     IRQF_TRIGGER_FALLING,
+				     client->name, tsdata);
+	if (error) {
+		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(input);
+	if (error)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, tsdata);
+	device_init_wakeup(&client->dev, 1);
+
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, tsdata);
+err_free_mem:
+	input_free_device(input);
+	kfree(tsdata);
+	return error;
+}
+
+static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client)
+{
+	struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
+
+	device_init_wakeup(&client->dev, 0);
+
+	tsdata->exiting = true;
+	mb();
+	free_irq(client->irq, tsdata);
+
+	input_unregister_device(tsdata->input);
+	kfree(tsdata);
+
+	return 0;
+}
+
+static const struct i2c_device_id pixcir_i2c_ts_id[] = {
+	{ "pixcir_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
+
+static struct i2c_driver pixcir_i2c_ts_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "pixcir_ts",
+		.pm	= &pixcir_dev_pm_ops,
+	},
+	.probe		= pixcir_i2c_ts_probe,
+	.remove		= __devexit_p(pixcir_i2c_ts_remove),
+	.id_table	= pixcir_i2c_ts_id,
+};
+
+module_i2c_driver(pixcir_i2c_ts_driver);
+
+MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
+MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/s3c2410_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/s3c2410_ts.c
new file mode 100644
index 0000000..bf1a064
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/s3c2410_ts.c
@@ -0,0 +1,441 @@
+/*
+ * Samsung S3C24XX touchscreen driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the term 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright 2008 Ben Dooks <ben-linux@fluff.org>
+ * Copyright 2009 Simtec Electronics <linux@simtec.co.uk>
+ *
+ * Additional work by Herbert Pötzl <herbert@13thfloor.at> and
+ * Harald Welte <laforge@openmoko.org>
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/adc.h>
+#include <plat/regs-adc.h>
+#include <plat/ts.h>
+
+#define TSC_SLEEP  (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
+
+#define INT_DOWN	(0)
+#define INT_UP		(1 << 8)
+
+#define WAIT4INT	(S3C2410_ADCTSC_YM_SEN | \
+			 S3C2410_ADCTSC_YP_SEN | \
+			 S3C2410_ADCTSC_XP_SEN | \
+			 S3C2410_ADCTSC_XY_PST(3))
+
+#define AUTOPST		(S3C2410_ADCTSC_YM_SEN | \
+			 S3C2410_ADCTSC_YP_SEN | \
+			 S3C2410_ADCTSC_XP_SEN | \
+			 S3C2410_ADCTSC_AUTO_PST | \
+			 S3C2410_ADCTSC_XY_PST(0))
+
+#define FEAT_PEN_IRQ	(1 << 0)	/* HAS ADCCLRINTPNDNUP */
+
+/* Per-touchscreen data. */
+
+/**
+ * struct s3c2410ts - driver touchscreen state.
+ * @client: The ADC client we registered with the core driver.
+ * @dev: The device we are bound to.
+ * @input: The input device we registered with the input subsystem.
+ * @clock: The clock for the adc.
+ * @io: Pointer to the IO base.
+ * @xp: The accumulated X position data.
+ * @yp: The accumulated Y position data.
+ * @irq_tc: The interrupt number for pen up/down interrupt
+ * @count: The number of samples collected.
+ * @shift: The log2 of the maximum count to read in one go.
+ * @features: The features supported by the TSADC MOdule.
+ */
+struct s3c2410ts {
+	struct s3c_adc_client *client;
+	struct device *dev;
+	struct input_dev *input;
+	struct clk *clock;
+	void __iomem *io;
+	unsigned long xp;
+	unsigned long yp;
+	int irq_tc;
+	int count;
+	int shift;
+	int features;
+};
+
+static struct s3c2410ts ts;
+
+/**
+ * get_down - return the down state of the pen
+ * @data0: The data read from ADCDAT0 register.
+ * @data1: The data read from ADCDAT1 register.
+ *
+ * Return non-zero if both readings show that the pen is down.
+ */
+static inline bool get_down(unsigned long data0, unsigned long data1)
+{
+	/* returns true if both data values show stylus down */
+	return (!(data0 & S3C2410_ADCDAT0_UPDOWN) &&
+		!(data1 & S3C2410_ADCDAT0_UPDOWN));
+}
+
+static void touch_timer_fire(unsigned long data)
+{
+	unsigned long data0;
+	unsigned long data1;
+	bool down;
+
+	data0 = readl(ts.io + S3C2410_ADCDAT0);
+	data1 = readl(ts.io + S3C2410_ADCDAT1);
+
+	down = get_down(data0, data1);
+
+	if (down) {
+		if (ts.count == (1 << ts.shift)) {
+			ts.xp >>= ts.shift;
+			ts.yp >>= ts.shift;
+
+			dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
+				__func__, ts.xp, ts.yp, ts.count);
+
+			input_report_abs(ts.input, ABS_X, ts.xp);
+			input_report_abs(ts.input, ABS_Y, ts.yp);
+
+			input_report_key(ts.input, BTN_TOUCH, 1);
+			input_sync(ts.input);
+
+			ts.xp = 0;
+			ts.yp = 0;
+			ts.count = 0;
+		}
+
+		s3c_adc_start(ts.client, 0, 1 << ts.shift);
+	} else {
+		ts.xp = 0;
+		ts.yp = 0;
+		ts.count = 0;
+
+		input_report_key(ts.input, BTN_TOUCH, 0);
+		input_sync(ts.input);
+
+		writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+	}
+}
+
+static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0);
+
+/**
+ * stylus_irq - touchscreen stylus event interrupt
+ * @irq: The interrupt number
+ * @dev_id: The device ID.
+ *
+ * Called when the IRQ_TC is fired for a pen up or down event.
+ */
+static irqreturn_t stylus_irq(int irq, void *dev_id)
+{
+	unsigned long data0;
+	unsigned long data1;
+	bool down;
+
+	data0 = readl(ts.io + S3C2410_ADCDAT0);
+	data1 = readl(ts.io + S3C2410_ADCDAT1);
+
+	down = get_down(data0, data1);
+
+	/* TODO we should never get an interrupt with down set while
+	 * the timer is running, but maybe we ought to verify that the
+	 * timer isn't running anyways. */
+
+	if (down)
+		s3c_adc_start(ts.client, 0, 1 << ts.shift);
+	else
+		dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);
+
+	if (ts.features & FEAT_PEN_IRQ) {
+		/* Clear pen down/up interrupt */
+		writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * s3c24xx_ts_conversion - ADC conversion callback
+ * @client: The client that was registered with the ADC core.
+ * @data0: The reading from ADCDAT0.
+ * @data1: The reading from ADCDAT1.
+ * @left: The number of samples left.
+ *
+ * Called when a conversion has finished.
+ */
+static void s3c24xx_ts_conversion(struct s3c_adc_client *client,
+				  unsigned data0, unsigned data1,
+				  unsigned *left)
+{
+	dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1);
+
+	ts.xp += data0;
+	ts.yp += data1;
+
+	ts.count++;
+
+	/* From tests, it seems that it is unlikely to get a pen-up
+	 * event during the conversion process which means we can
+	 * ignore any pen-up events with less than the requisite
+	 * count done.
+	 *
+	 * In several thousand conversions, no pen-ups where detected
+	 * before count completed.
+	 */
+}
+
+/**
+ * s3c24xx_ts_select - ADC selection callback.
+ * @client: The client that was registered with the ADC core.
+ * @select: The reason for select.
+ *
+ * Called when the ADC core selects (or deslects) us as a client.
+ */
+static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
+{
+	if (select) {
+		writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+		       ts.io + S3C2410_ADCTSC);
+	} else {
+		mod_timer(&touch_timer, jiffies+1);
+		writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
+	}
+}
+
+/**
+ * s3c2410ts_probe - device core probe entry point
+ * @pdev: The device we are being bound to.
+ *
+ * Initialise, find and allocate any resources we need to run and then
+ * register with the ADC and input systems.
+ */
+static int __devinit s3c2410ts_probe(struct platform_device *pdev)
+{
+	struct s3c2410_ts_mach_info *info;
+	struct device *dev = &pdev->dev;
+	struct input_dev *input_dev;
+	struct resource *res;
+	int ret = -EINVAL;
+
+	/* Initialise input stuff */
+	memset(&ts, 0, sizeof(struct s3c2410ts));
+
+	ts.dev = dev;
+
+	info = pdev->dev.platform_data;
+	if (!info) {
+		dev_err(dev, "no platform data, cannot attach\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "initialising touchscreen\n");
+
+	ts.clock = clk_get(dev, "adc");
+	if (IS_ERR(ts.clock)) {
+		dev_err(dev, "cannot get adc clock source\n");
+		return -ENOENT;
+	}
+
+	clk_enable(ts.clock);
+	dev_dbg(dev, "got and enabled clocks\n");
+
+	ts.irq_tc = ret = platform_get_irq(pdev, 0);
+	if (ret < 0) {
+		dev_err(dev, "no resource for interrupt\n");
+		goto err_clk;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no resource for registers\n");
+		ret = -ENOENT;
+		goto err_clk;
+	}
+
+	ts.io = ioremap(res->start, resource_size(res));
+	if (ts.io == NULL) {
+		dev_err(dev, "cannot map registers\n");
+		ret = -ENOMEM;
+		goto err_clk;
+	}
+
+	/* inititalise the gpio */
+	if (info->cfg_gpio)
+		info->cfg_gpio(to_platform_device(ts.dev));
+
+	ts.client = s3c_adc_register(pdev, s3c24xx_ts_select,
+				     s3c24xx_ts_conversion, 1);
+	if (IS_ERR(ts.client)) {
+		dev_err(dev, "failed to register adc client\n");
+		ret = PTR_ERR(ts.client);
+		goto err_iomap;
+	}
+
+	/* Initialise registers */
+	if ((info->delay & 0xffff) > 0)
+		writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
+
+	writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(dev, "Unable to allocate the input device !!\n");
+		ret = -ENOMEM;
+		goto err_iomap;
+	}
+
+	ts.input = input_dev;
+	ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
+	input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
+
+	ts.input->name = "S3C24XX TouchScreen";
+	ts.input->id.bustype = BUS_HOST;
+	ts.input->id.vendor = 0xDEAD;
+	ts.input->id.product = 0xBEEF;
+	ts.input->id.version = 0x0102;
+
+	ts.shift = info->oversampling_shift;
+	ts.features = platform_get_device_id(pdev)->driver_data;
+
+	ret = request_irq(ts.irq_tc, stylus_irq, 0,
+			  "s3c2410_ts_pen", ts.input);
+	if (ret) {
+		dev_err(dev, "cannot get TC interrupt\n");
+		goto err_inputdev;
+	}
+
+	dev_info(dev, "driver attached, registering input device\n");
+
+	/* All went ok, so register to the input system */
+	ret = input_register_device(ts.input);
+	if (ret < 0) {
+		dev_err(dev, "failed to register input device\n");
+		ret = -EIO;
+		goto err_tcirq;
+	}
+
+	return 0;
+
+ err_tcirq:
+	free_irq(ts.irq_tc, ts.input);
+ err_inputdev:
+	input_free_device(ts.input);
+ err_iomap:
+	iounmap(ts.io);
+ err_clk:
+	del_timer_sync(&touch_timer);
+	clk_put(ts.clock);
+	return ret;
+}
+
+/**
+ * s3c2410ts_remove - device core removal entry point
+ * @pdev: The device we are being removed from.
+ *
+ * Free up our state ready to be removed.
+ */
+static int __devexit s3c2410ts_remove(struct platform_device *pdev)
+{
+	free_irq(ts.irq_tc, ts.input);
+	del_timer_sync(&touch_timer);
+
+	clk_disable(ts.clock);
+	clk_put(ts.clock);
+
+	input_unregister_device(ts.input);
+	iounmap(ts.io);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c2410ts_suspend(struct device *dev)
+{
+	writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC);
+	disable_irq(ts.irq_tc);
+	clk_disable(ts.clock);
+
+	return 0;
+}
+
+static int s3c2410ts_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
+
+	clk_enable(ts.clock);
+	enable_irq(ts.irq_tc);
+
+	/* Initialise registers */
+	if ((info->delay & 0xffff) > 0)
+		writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
+
+	writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+
+	return 0;
+}
+
+static struct dev_pm_ops s3c_ts_pmops = {
+	.suspend	= s3c2410ts_suspend,
+	.resume		= s3c2410ts_resume,
+};
+#endif
+
+static struct platform_device_id s3cts_driver_ids[] = {
+	{ "s3c2410-ts", 0 },
+	{ "s3c2440-ts", 0 },
+	{ "s3c64xx-ts", FEAT_PEN_IRQ },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, s3cts_driver_ids);
+
+static struct platform_driver s3c_ts_driver = {
+	.driver         = {
+		.name   = "samsung-ts",
+		.owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &s3c_ts_pmops,
+#endif
+	},
+	.id_table	= s3cts_driver_ids,
+	.probe		= s3c2410ts_probe,
+	.remove		= __devexit_p(s3c2410ts_remove),
+};
+module_platform_driver(s3c_ts_driver);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
+	      "Ben Dooks <ben@simtec.co.uk>, "
+	      "Simtec Electronics <linux@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C24XX Touchscreen driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/st1232.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/st1232.c
new file mode 100644
index 0000000..cbbf71b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/st1232.c
@@ -0,0 +1,275 @@
+/*
+ * ST1232 Touchscreen Controller Driver
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ *	Tony SIM <chinyeow.sim.xt@renesas.com>
+ *
+ * Using code from:
+ *  - android.git.kernel.org: projects/kernel/common.git: synaptics_i2c_rmi.c
+ *	Copyright (C) 2007 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define ST1232_TS_NAME	"st1232-ts"
+
+#define MIN_X		0x00
+#define MIN_Y		0x00
+#define MAX_X		0x31f	/* (800 - 1) */
+#define MAX_Y		0x1df	/* (480 - 1) */
+#define MAX_AREA	0xff
+#define MAX_FINGERS	2
+
+struct st1232_ts_finger {
+	u16 x;
+	u16 y;
+	u8 t;
+	bool is_valid;
+};
+
+struct st1232_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct st1232_ts_finger finger[MAX_FINGERS];
+	struct dev_pm_qos_request low_latency_req;
+};
+
+static int st1232_ts_read_data(struct st1232_ts_data *ts)
+{
+	struct st1232_ts_finger *finger = ts->finger;
+	struct i2c_client *client = ts->client;
+	struct i2c_msg msg[2];
+	int error;
+	u8 start_reg;
+	u8 buf[10];
+
+	/* read touchscreen data from ST1232 */
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &start_reg;
+	start_reg = 0x10;
+
+	msg[1].addr = ts->client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = sizeof(buf);
+	msg[1].buf = buf;
+
+	error = i2c_transfer(client->adapter, msg, 2);
+	if (error < 0)
+		return error;
+
+	/* get "valid" bits */
+	finger[0].is_valid = buf[2] >> 7;
+	finger[1].is_valid = buf[5] >> 7;
+
+	/* get xy coordinate */
+	if (finger[0].is_valid) {
+		finger[0].x = ((buf[2] & 0x0070) << 4) | buf[3];
+		finger[0].y = ((buf[2] & 0x0007) << 8) | buf[4];
+		finger[0].t = buf[8];
+	}
+
+	if (finger[1].is_valid) {
+		finger[1].x = ((buf[5] & 0x0070) << 4) | buf[6];
+		finger[1].y = ((buf[5] & 0x0007) << 8) | buf[7];
+		finger[1].t = buf[9];
+	}
+
+	return 0;
+}
+
+static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
+{
+	struct st1232_ts_data *ts = dev_id;
+	struct st1232_ts_finger *finger = ts->finger;
+	struct input_dev *input_dev = ts->input_dev;
+	int count = 0;
+	int i, ret;
+
+	ret = st1232_ts_read_data(ts);
+	if (ret < 0)
+		goto end;
+
+	/* multi touch protocol */
+	for (i = 0; i < MAX_FINGERS; i++) {
+		if (!finger[i].is_valid)
+			continue;
+
+		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
+		input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
+		input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
+		input_mt_sync(input_dev);
+		count++;
+	}
+
+	/* SYN_MT_REPORT only if no contact */
+	if (!count) {
+		input_mt_sync(input_dev);
+		if (ts->low_latency_req.dev) {
+			dev_pm_qos_remove_request(&ts->low_latency_req);
+			ts->low_latency_req.dev = NULL;
+		}
+	} else if (!ts->low_latency_req.dev) {
+		/* First contact, request 100 us latency. */
+		dev_pm_qos_add_ancestor_request(&ts->client->dev,
+						&ts->low_latency_req, 100);
+	}
+
+	/* SYN_REPORT */
+	input_sync(input_dev);
+
+end:
+	return IRQ_HANDLED;
+}
+
+static int __devinit st1232_ts_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct st1232_ts_data *ts;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "need I2C_FUNC_I2C\n");
+		return -EIO;
+	}
+
+	if (!client->irq) {
+		dev_err(&client->dev, "no IRQ?\n");
+		return -EINVAL;
+	}
+
+
+	ts = kzalloc(sizeof(struct st1232_ts_data), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->client = client;
+	ts->input_dev = input_dev;
+
+	input_dev->name = "st1232-touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	__set_bit(EV_SYN, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(EV_ABS, input_dev->evbit);
+
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X, MIN_X, MAX_X, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, MIN_Y, MAX_Y, 0, 0);
+
+	error = request_threaded_irq(client->irq, NULL, st1232_ts_irq_handler,
+				     IRQF_ONESHOT, client->name, ts);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(ts->input_dev);
+	if (error) {
+		dev_err(&client->dev, "Unable to register %s input device\n",
+			input_dev->name);
+		goto err_free_irq;
+	}
+
+	i2c_set_clientdata(client, ts);
+	device_init_wakeup(&client->dev, 1);
+
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, ts);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	return error;
+}
+
+static int __devexit st1232_ts_remove(struct i2c_client *client)
+{
+	struct st1232_ts_data *ts = i2c_get_clientdata(client);
+
+	device_init_wakeup(&client->dev, 0);
+	free_irq(client->irq, ts);
+	input_unregister_device(ts->input_dev);
+	kfree(ts);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int st1232_ts_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(client->irq);
+	else
+		disable_irq(client->irq);
+
+	return 0;
+}
+
+static int st1232_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(client->irq);
+	else
+		enable_irq(client->irq);
+
+	return 0;
+}
+
+static const struct dev_pm_ops st1232_ts_pm_ops = {
+	.suspend	= st1232_ts_suspend,
+	.resume		= st1232_ts_resume,
+};
+#endif
+
+static const struct i2c_device_id st1232_ts_id[] = {
+	{ ST1232_TS_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
+
+static struct i2c_driver st1232_ts_driver = {
+	.probe		= st1232_ts_probe,
+	.remove		= __devexit_p(st1232_ts_remove),
+	.id_table	= st1232_ts_id,
+	.driver = {
+		.name	= ST1232_TS_NAME,
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &st1232_ts_pm_ops,
+#endif
+	},
+};
+
+module_i2c_driver(st1232_ts_driver);
+
+MODULE_AUTHOR("Tony SIM <chinyeow.sim.xt@renesas.com>");
+MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/stmpe-ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/stmpe-ts.c
new file mode 100644
index 0000000..692b685
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/stmpe-ts.c
@@ -0,0 +1,387 @@
+/* STMicroelectronics STMPE811 Touchscreen Driver
+ *
+ * (C) 2010 Luotao Fu <l.fu@pengutronix.de>
+ * All rights reserved.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/stmpe.h>
+
+/* Register layouts and functionalities are identical on all stmpexxx variants
+ * with touchscreen controller
+ */
+#define STMPE_REG_INT_STA		0x0B
+#define STMPE_REG_ADC_CTRL1		0x20
+#define STMPE_REG_ADC_CTRL2		0x21
+#define STMPE_REG_TSC_CTRL		0x40
+#define STMPE_REG_TSC_CFG		0x41
+#define STMPE_REG_FIFO_TH		0x4A
+#define STMPE_REG_FIFO_STA		0x4B
+#define STMPE_REG_FIFO_SIZE		0x4C
+#define STMPE_REG_TSC_DATA_XYZ		0x52
+#define STMPE_REG_TSC_FRACTION_Z	0x56
+#define STMPE_REG_TSC_I_DRIVE		0x58
+
+#define OP_MOD_XYZ			0
+
+#define STMPE_TSC_CTRL_TSC_EN		(1<<0)
+
+#define STMPE_FIFO_STA_RESET		(1<<0)
+
+#define STMPE_IRQ_TOUCH_DET		0
+
+#define SAMPLE_TIME(x)			((x & 0xf) << 4)
+#define MOD_12B(x)			((x & 0x1) << 3)
+#define REF_SEL(x)			((x & 0x1) << 1)
+#define ADC_FREQ(x)			(x & 0x3)
+#define AVE_CTRL(x)			((x & 0x3) << 6)
+#define DET_DELAY(x)			((x & 0x7) << 3)
+#define SETTLING(x)			(x & 0x7)
+#define FRACTION_Z(x)			(x & 0x7)
+#define I_DRIVE(x)			(x & 0x1)
+#define OP_MODE(x)			((x & 0x7) << 1)
+
+#define STMPE_TS_NAME			"stmpe-ts"
+#define XY_MASK				0xfff
+
+struct stmpe_touch {
+	struct stmpe *stmpe;
+	struct input_dev *idev;
+	struct delayed_work work;
+	struct device *dev;
+	u8 sample_time;
+	u8 mod_12b;
+	u8 ref_sel;
+	u8 adc_freq;
+	u8 ave_ctrl;
+	u8 touch_det_delay;
+	u8 settling;
+	u8 fraction_z;
+	u8 i_drive;
+};
+
+static int __stmpe_reset_fifo(struct stmpe *stmpe)
+{
+	int ret;
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_FIFO_STA,
+			STMPE_FIFO_STA_RESET, STMPE_FIFO_STA_RESET);
+	if (ret)
+		return ret;
+
+	return stmpe_set_bits(stmpe, STMPE_REG_FIFO_STA,
+			STMPE_FIFO_STA_RESET, 0);
+}
+
+static void stmpe_work(struct work_struct *work)
+{
+	int int_sta;
+	u32 timeout = 40;
+
+	struct stmpe_touch *ts =
+	    container_of(work, struct stmpe_touch, work.work);
+
+	int_sta = stmpe_reg_read(ts->stmpe, STMPE_REG_INT_STA);
+
+	/*
+	 * touch_det sometimes get desasserted or just get stuck. This appears
+	 * to be a silicon bug, We still have to clearify this with the
+	 * manufacture. As a workaround We release the key anyway if the
+	 * touch_det keeps coming in after 4ms, while the FIFO contains no value
+	 * during the whole time.
+	 */
+	while ((int_sta & (1 << STMPE_IRQ_TOUCH_DET)) && (timeout > 0)) {
+		timeout--;
+		int_sta = stmpe_reg_read(ts->stmpe, STMPE_REG_INT_STA);
+		udelay(100);
+	}
+
+	/* reset the FIFO before we report release event */
+	__stmpe_reset_fifo(ts->stmpe);
+
+	input_report_abs(ts->idev, ABS_PRESSURE, 0);
+	input_sync(ts->idev);
+}
+
+static irqreturn_t stmpe_ts_handler(int irq, void *data)
+{
+	u8 data_set[4];
+	int x, y, z;
+	struct stmpe_touch *ts = data;
+
+	/*
+	 * Cancel scheduled polling for release if we have new value
+	 * available. Wait if the polling is already running.
+	 */
+	cancel_delayed_work_sync(&ts->work);
+
+	/*
+	 * The FIFO sometimes just crashes and stops generating interrupts. This
+	 * appears to be a silicon bug. We still have to clearify this with
+	 * the manufacture. As a workaround we disable the TSC while we are
+	 * collecting data and flush the FIFO after reading
+	 */
+	stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+				STMPE_TSC_CTRL_TSC_EN, 0);
+
+	stmpe_block_read(ts->stmpe, STMPE_REG_TSC_DATA_XYZ, 4, data_set);
+
+	x = (data_set[0] << 4) | (data_set[1] >> 4);
+	y = ((data_set[1] & 0xf) << 8) | data_set[2];
+	z = data_set[3];
+
+	input_report_abs(ts->idev, ABS_X, x);
+	input_report_abs(ts->idev, ABS_Y, y);
+	input_report_abs(ts->idev, ABS_PRESSURE, z);
+	input_sync(ts->idev);
+
+       /* flush the FIFO after we have read out our values. */
+	__stmpe_reset_fifo(ts->stmpe);
+
+	/* reenable the tsc */
+	stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+			STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
+
+	/* start polling for touch_det to detect release */
+	schedule_delayed_work(&ts->work, HZ / 50);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit stmpe_init_hw(struct stmpe_touch *ts)
+{
+	int ret;
+	u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask;
+	struct stmpe *stmpe = ts->stmpe;
+	struct device *dev = ts->dev;
+
+	ret = stmpe_enable(stmpe, STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC);
+	if (ret) {
+		dev_err(dev, "Could not enable clock for ADC and TS\n");
+		return ret;
+	}
+
+	adc_ctrl1 = SAMPLE_TIME(ts->sample_time) | MOD_12B(ts->mod_12b) |
+		REF_SEL(ts->ref_sel);
+	adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff);
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1,
+			adc_ctrl1_mask, adc_ctrl1);
+	if (ret) {
+		dev_err(dev, "Could not setup ADC\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2,
+			ADC_FREQ(0xff), ADC_FREQ(ts->adc_freq));
+	if (ret) {
+		dev_err(dev, "Could not setup ADC\n");
+		return ret;
+	}
+
+	tsc_cfg = AVE_CTRL(ts->ave_ctrl) | DET_DELAY(ts->touch_det_delay) |
+			SETTLING(ts->settling);
+	tsc_cfg_mask = AVE_CTRL(0xff) | DET_DELAY(0xff) | SETTLING(0xff);
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CFG, tsc_cfg_mask, tsc_cfg);
+	if (ret) {
+		dev_err(dev, "Could not config touch\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_FRACTION_Z,
+			FRACTION_Z(0xff), FRACTION_Z(ts->fraction_z));
+	if (ret) {
+		dev_err(dev, "Could not config touch\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_I_DRIVE,
+			I_DRIVE(0xff), I_DRIVE(ts->i_drive));
+	if (ret) {
+		dev_err(dev, "Could not config touch\n");
+		return ret;
+	}
+
+	/* set FIFO to 1 for single point reading */
+	ret = stmpe_reg_write(stmpe, STMPE_REG_FIFO_TH, 1);
+	if (ret) {
+		dev_err(dev, "Could not set FIFO\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CTRL,
+			OP_MODE(0xff), OP_MODE(OP_MOD_XYZ));
+	if (ret) {
+		dev_err(dev, "Could not set mode\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int stmpe_ts_open(struct input_dev *dev)
+{
+	struct stmpe_touch *ts = input_get_drvdata(dev);
+	int ret = 0;
+
+	ret = __stmpe_reset_fifo(ts->stmpe);
+	if (ret)
+		return ret;
+
+	return stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+			STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
+}
+
+static void stmpe_ts_close(struct input_dev *dev)
+{
+	struct stmpe_touch *ts = input_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&ts->work);
+
+	stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+			STMPE_TSC_CTRL_TSC_EN, 0);
+}
+
+static int __devinit stmpe_input_probe(struct platform_device *pdev)
+{
+	struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+	struct stmpe_platform_data *pdata = stmpe->pdata;
+	struct stmpe_touch *ts;
+	struct input_dev *idev;
+	struct stmpe_ts_platform_data *ts_pdata = NULL;
+	int ret;
+	int ts_irq;
+
+	ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
+	if (ts_irq < 0)
+		return ts_irq;
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+
+	idev = input_allocate_device();
+	if (!idev) {
+		ret = -ENOMEM;
+		goto err_free_ts;
+	}
+
+	platform_set_drvdata(pdev, ts);
+	ts->stmpe = stmpe;
+	ts->idev = idev;
+	ts->dev = &pdev->dev;
+
+	if (pdata)
+		ts_pdata = pdata->ts;
+
+	if (ts_pdata) {
+		ts->sample_time = ts_pdata->sample_time;
+		ts->mod_12b = ts_pdata->mod_12b;
+		ts->ref_sel = ts_pdata->ref_sel;
+		ts->adc_freq = ts_pdata->adc_freq;
+		ts->ave_ctrl = ts_pdata->ave_ctrl;
+		ts->touch_det_delay = ts_pdata->touch_det_delay;
+		ts->settling = ts_pdata->settling;
+		ts->fraction_z = ts_pdata->fraction_z;
+		ts->i_drive = ts_pdata->i_drive;
+	}
+
+	INIT_DELAYED_WORK(&ts->work, stmpe_work);
+
+	ret = request_threaded_irq(ts_irq, NULL, stmpe_ts_handler,
+			IRQF_ONESHOT, STMPE_TS_NAME, ts);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request IRQ %d\n", ts_irq);
+		goto err_free_input;
+	}
+
+	ret = stmpe_init_hw(ts);
+	if (ret)
+		goto err_free_irq;
+
+	idev->name = STMPE_TS_NAME;
+	idev->id.bustype = BUS_I2C;
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	idev->open = stmpe_ts_open;
+	idev->close = stmpe_ts_close;
+
+	input_set_drvdata(idev, ts);
+
+	input_set_abs_params(idev, ABS_X, 0, XY_MASK, 0, 0);
+	input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
+	input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
+
+	ret = input_register_device(idev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register input device\n");
+		goto err_free_irq;
+	}
+
+	return ret;
+
+err_free_irq:
+	free_irq(ts_irq, ts);
+err_free_input:
+	input_free_device(idev);
+	platform_set_drvdata(pdev, NULL);
+err_free_ts:
+	kfree(ts);
+err_out:
+	return ret;
+}
+
+static int __devexit stmpe_ts_remove(struct platform_device *pdev)
+{
+	struct stmpe_touch *ts = platform_get_drvdata(pdev);
+	unsigned int ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
+
+	stmpe_disable(ts->stmpe, STMPE_BLOCK_TOUCHSCREEN);
+
+	free_irq(ts_irq, ts);
+
+	platform_set_drvdata(pdev, NULL);
+
+	input_unregister_device(ts->idev);
+
+	kfree(ts);
+
+	return 0;
+}
+
+static struct platform_driver stmpe_ts_driver = {
+	.driver = {
+		   .name = STMPE_TS_NAME,
+		   .owner = THIS_MODULE,
+		   },
+	.probe = stmpe_input_probe,
+	.remove = __devexit_p(stmpe_ts_remove),
+};
+module_platform_driver(stmpe_ts_driver);
+
+MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
+MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" STMPE_TS_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ti_tscadc.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ti_tscadc.c
new file mode 100644
index 0000000..d229c74
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ti_tscadc.c
@@ -0,0 +1,486 @@
+/*
+ * TI Touch Screen driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/input/ti_tscadc.h>
+#include <linux/delay.h>
+
+#define REG_IRQEOI		0x020
+#define REG_RAWIRQSTATUS	0x024
+#define REG_IRQSTATUS		0x028
+#define REG_IRQENABLE		0x02C
+#define REG_IRQWAKEUP		0x034
+#define REG_CTRL		0x040
+#define REG_ADCFSM		0x044
+#define REG_CLKDIV		0x04C
+#define REG_SE			0x054
+#define REG_IDLECONFIG		0x058
+#define REG_CHARGECONFIG	0x05C
+#define REG_CHARGEDELAY		0x060
+#define REG_STEPCONFIG(n)	(0x64 + ((n - 1) * 8))
+#define REG_STEPDELAY(n)	(0x68 + ((n - 1) * 8))
+#define REG_STEPCONFIG13	0x0C4
+#define REG_STEPDELAY13		0x0C8
+#define REG_STEPCONFIG14	0x0CC
+#define REG_STEPDELAY14		0x0D0
+#define REG_FIFO0CNT		0xE4
+#define REG_FIFO1THR		0xF4
+#define REG_FIFO0		0x100
+#define REG_FIFO1		0x200
+
+/*	Register Bitfields	*/
+#define IRQWKUP_ENB		BIT(0)
+#define STPENB_STEPENB		0x7FFF
+#define IRQENB_FIFO1THRES	BIT(5)
+#define IRQENB_PENUP		BIT(9)
+#define STEPCONFIG_MODE_HWSYNC	0x2
+#define STEPCONFIG_SAMPLES_AVG	(1 << 4)
+#define STEPCONFIG_XPP		(1 << 5)
+#define STEPCONFIG_XNN		(1 << 6)
+#define STEPCONFIG_YPP		(1 << 7)
+#define STEPCONFIG_YNN		(1 << 8)
+#define STEPCONFIG_XNP		(1 << 9)
+#define STEPCONFIG_YPN		(1 << 10)
+#define STEPCONFIG_INM		(1 << 18)
+#define STEPCONFIG_INP		(1 << 20)
+#define STEPCONFIG_INP_5	(1 << 21)
+#define STEPCONFIG_FIFO1	(1 << 26)
+#define STEPCONFIG_OPENDLY	0xff
+#define STEPCONFIG_Z1		(3 << 19)
+#define STEPIDLE_INP		(1 << 22)
+#define STEPCHARGE_RFP		(1 << 12)
+#define STEPCHARGE_INM		(1 << 15)
+#define STEPCHARGE_INP		(1 << 19)
+#define STEPCHARGE_RFM		(1 << 23)
+#define STEPCHARGE_DELAY	0x1
+#define CNTRLREG_TSCSSENB	(1 << 0)
+#define CNTRLREG_STEPID		(1 << 1)
+#define CNTRLREG_STEPCONFIGWRT	(1 << 2)
+#define CNTRLREG_4WIRE		(1 << 5)
+#define CNTRLREG_5WIRE		(1 << 6)
+#define CNTRLREG_8WIRE		(3 << 5)
+#define CNTRLREG_TSCENB		(1 << 7)
+#define ADCFSM_STEPID		0x10
+
+#define SEQ_SETTLE		275
+#define ADC_CLK			3000000
+#define MAX_12BIT		((1 << 12) - 1)
+#define TSCADC_DELTA_X		15
+#define TSCADC_DELTA_Y		15
+
+struct tscadc {
+	struct input_dev	*input;
+	struct clk		*tsc_ick;
+	void __iomem		*tsc_base;
+	unsigned int		irq;
+	unsigned int		wires;
+	unsigned int		x_plate_resistance;
+	bool			pen_down;
+};
+
+static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
+{
+	return readl(ts->tsc_base + reg);
+}
+
+static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
+					unsigned int val)
+{
+	writel(val, tsc->tsc_base + reg);
+}
+
+static void tscadc_step_config(struct tscadc *ts_dev)
+{
+	unsigned int	config;
+	int i;
+
+	/* Configure the Step registers */
+
+	config = STEPCONFIG_MODE_HWSYNC |
+			STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP;
+	switch (ts_dev->wires) {
+	case 4:
+		config |= STEPCONFIG_INP | STEPCONFIG_XNN;
+		break;
+	case 5:
+		config |= STEPCONFIG_YNN |
+				STEPCONFIG_INP_5 | STEPCONFIG_XNN |
+				STEPCONFIG_YPP;
+		break;
+	case 8:
+		config |= STEPCONFIG_INP | STEPCONFIG_XNN;
+		break;
+	}
+
+	for (i = 1; i < 7; i++) {
+		tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+		tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+	}
+
+	config = 0;
+	config = STEPCONFIG_MODE_HWSYNC |
+			STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN |
+			STEPCONFIG_INM | STEPCONFIG_FIFO1;
+	switch (ts_dev->wires) {
+	case 4:
+		config |= STEPCONFIG_YPP;
+		break;
+	case 5:
+		config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 |
+				STEPCONFIG_XNP | STEPCONFIG_YPN;
+		break;
+	case 8:
+		config |= STEPCONFIG_YPP;
+		break;
+	}
+
+	for (i = 7; i < 13; i++) {
+		tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+		tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+	}
+
+	config = 0;
+	/* Charge step configuration */
+	config = STEPCONFIG_XPP | STEPCONFIG_YNN |
+			STEPCHARGE_RFP | STEPCHARGE_RFM |
+			STEPCHARGE_INM | STEPCHARGE_INP;
+
+	tscadc_writel(ts_dev, REG_CHARGECONFIG, config);
+	tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY);
+
+	config = 0;
+	/* Configure to calculate pressure */
+	config = STEPCONFIG_MODE_HWSYNC |
+			STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP |
+			STEPCONFIG_XNN | STEPCONFIG_INM;
+	tscadc_writel(ts_dev, REG_STEPCONFIG13, config);
+	tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY);
+
+	config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1;
+	tscadc_writel(ts_dev, REG_STEPCONFIG14, config);
+	tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY);
+
+	tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+}
+
+static void tscadc_idle_config(struct tscadc *ts_config)
+{
+	unsigned int idleconfig;
+
+	idleconfig = STEPCONFIG_YNN |
+			STEPCONFIG_INM |
+			STEPCONFIG_YPN | STEPIDLE_INP;
+	tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig);
+}
+
+static void tscadc_read_coordinates(struct tscadc *ts_dev,
+				    unsigned int *x, unsigned int *y)
+{
+	unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
+	unsigned int prev_val_x = ~0, prev_val_y = ~0;
+	unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
+	unsigned int read, diff;
+	unsigned int i;
+
+	/*
+	 * Delta filter is used to remove large variations in sampled
+	 * values from ADC. The filter tries to predict where the next
+	 * coordinate could be. This is done by taking a previous
+	 * coordinate and subtracting it form current one. Further the
+	 * algorithm compares the difference with that of a present value,
+	 * if true the value is reported to the sub system.
+	 */
+	for (i = 0; i < fifocount - 1; i++) {
+		read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+		diff = abs(read - prev_val_x);
+		if (diff < prev_diff_x) {
+			prev_diff_x = diff;
+			*x = read;
+		}
+		prev_val_x = read;
+
+		read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+		diff = abs(read - prev_val_y);
+		if (diff < prev_diff_y) {
+			prev_diff_y = diff;
+			*y = read;
+		}
+		prev_val_y = read;
+	}
+}
+
+static irqreturn_t tscadc_irq(int irq, void *dev)
+{
+	struct tscadc *ts_dev = dev;
+	struct input_dev *input_dev = ts_dev->input;
+	unsigned int status, irqclr = 0;
+	unsigned int x = 0, y = 0;
+	unsigned int z1, z2, z;
+	unsigned int fsm;
+
+	status = tscadc_readl(ts_dev, REG_IRQSTATUS);
+	if (status & IRQENB_FIFO1THRES) {
+		tscadc_read_coordinates(ts_dev, &x, &y);
+
+		z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+		z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+
+		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
+			/*
+			 * Calculate pressure using formula
+			 * Resistance(touch) = x plate resistance *
+			 * x postion/4096 * ((z2 / z1) - 1)
+			 */
+			z = z2 - z1;
+			z *= x;
+			z *= ts_dev->x_plate_resistance;
+			z /= z1;
+			z = (z + 2047) >> 12;
+
+			if (z <= MAX_12BIT) {
+				input_report_abs(input_dev, ABS_X, x);
+				input_report_abs(input_dev, ABS_Y, y);
+				input_report_abs(input_dev, ABS_PRESSURE, z);
+				input_report_key(input_dev, BTN_TOUCH, 1);
+				input_sync(input_dev);
+			}
+		}
+		irqclr |= IRQENB_FIFO1THRES;
+	}
+
+	/*
+	 * Time for sequencer to settle, to read
+	 * correct state of the sequencer.
+	 */
+	udelay(SEQ_SETTLE);
+
+	status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS);
+	if (status & IRQENB_PENUP) {
+		/* Pen up event */
+		fsm = tscadc_readl(ts_dev, REG_ADCFSM);
+		if (fsm == ADCFSM_STEPID) {
+			ts_dev->pen_down = false;
+			input_report_key(input_dev, BTN_TOUCH, 0);
+			input_report_abs(input_dev, ABS_PRESSURE, 0);
+			input_sync(input_dev);
+		} else {
+			ts_dev->pen_down = true;
+		}
+		irqclr |= IRQENB_PENUP;
+	}
+
+	tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+	/* check pending interrupts */
+	tscadc_writel(ts_dev, REG_IRQEOI, 0x0);
+
+	tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+	return IRQ_HANDLED;
+}
+
+/*
+ * The functions for inserting/removing driver as a module.
+ */
+
+static int __devinit tscadc_probe(struct platform_device *pdev)
+{
+	const struct tsc_data *pdata = pdev->dev.platform_data;
+	struct resource *res;
+	struct tscadc *ts_dev;
+	struct input_dev *input_dev;
+	struct clk *clk;
+	int err;
+	int clk_value, ctrl, irq;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform data.\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no memory resource defined.\n");
+		return -EINVAL;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq ID is specified.\n");
+		return -EINVAL;
+	}
+
+	/* Allocate memory for device */
+	ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts_dev || !input_dev) {
+		dev_err(&pdev->dev, "failed to allocate memory.\n");
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts_dev->input = input_dev;
+	ts_dev->irq = irq;
+	ts_dev->wires = pdata->wires;
+	ts_dev->x_plate_resistance = pdata->x_plate_resistance;
+
+	res = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to reserve registers.\n");
+		err = -EBUSY;
+		goto err_free_mem;
+	}
+
+	ts_dev->tsc_base = ioremap(res->start, resource_size(res));
+	if (!ts_dev->tsc_base) {
+		dev_err(&pdev->dev, "failed to map registers.\n");
+		err = -ENOMEM;
+		goto err_release_mem_region;
+	}
+
+	err = request_irq(ts_dev->irq, tscadc_irq,
+			  0, pdev->dev.driver->name, ts_dev);
+	if (err) {
+		dev_err(&pdev->dev, "failed to allocate irq.\n");
+		goto err_unmap_regs;
+	}
+
+	ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick");
+	if (IS_ERR(ts_dev->tsc_ick)) {
+		dev_err(&pdev->dev, "failed to get TSC ick\n");
+		goto err_free_irq;
+	}
+	clk_enable(ts_dev->tsc_ick);
+
+	clk = clk_get(&pdev->dev, "adc_tsc_fck");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "failed to get TSC fck\n");
+		err = PTR_ERR(clk);
+		goto err_disable_clk;
+	}
+
+	clk_value = clk_get_rate(clk) / ADC_CLK;
+	clk_put(clk);
+
+	if (clk_value < 7) {
+		dev_err(&pdev->dev, "clock input less than min clock requirement\n");
+		goto err_disable_clk;
+	}
+	/* CLKDIV needs to be configured to the value minus 1 */
+	tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1);
+
+	 /* Enable wake-up of the SoC using touchscreen */
+	tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
+
+	ctrl = CNTRLREG_STEPCONFIGWRT |
+			CNTRLREG_TSCENB |
+			CNTRLREG_STEPID;
+	switch (ts_dev->wires) {
+	case 4:
+		ctrl |= CNTRLREG_4WIRE;
+		break;
+	case 5:
+		ctrl |= CNTRLREG_5WIRE;
+		break;
+	case 8:
+		ctrl |= CNTRLREG_8WIRE;
+		break;
+	}
+	tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+	tscadc_idle_config(ts_dev);
+	tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
+	tscadc_step_config(ts_dev);
+	tscadc_writel(ts_dev, REG_FIFO1THR, 6);
+
+	ctrl |= CNTRLREG_TSCSSENB;
+	tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+	input_dev->name = "ti-tsc-adc";
+	input_dev->dev.parent = &pdev->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
+
+	/* register to the input system */
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_disable_clk;
+
+	platform_set_drvdata(pdev, ts_dev);
+	return 0;
+
+err_disable_clk:
+	clk_disable(ts_dev->tsc_ick);
+	clk_put(ts_dev->tsc_ick);
+err_free_irq:
+	free_irq(ts_dev->irq, ts_dev);
+err_unmap_regs:
+	iounmap(ts_dev->tsc_base);
+err_release_mem_region:
+	release_mem_region(res->start, resource_size(res));
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts_dev);
+	return err;
+}
+
+static int __devexit tscadc_remove(struct platform_device *pdev)
+{
+	struct tscadc *ts_dev = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	free_irq(ts_dev->irq, ts_dev);
+
+	input_unregister_device(ts_dev->input);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap(ts_dev->tsc_base);
+	release_mem_region(res->start, resource_size(res));
+
+	clk_disable(ts_dev->tsc_ick);
+	clk_put(ts_dev->tsc_ick);
+
+	kfree(ts_dev);
+
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver ti_tsc_driver = {
+	.probe	= tscadc_probe,
+	.remove	= __devexit_p(tscadc_remove),
+	.driver	= {
+		.name   = "tsc",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(ti_tsc_driver);
+
+MODULE_DESCRIPTION("TI touchscreen controller driver");
+MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tnetv107x-ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tnetv107x-ts.c
new file mode 100644
index 0000000..7e74880
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tnetv107x-ts.c
@@ -0,0 +1,386 @@
+/*
+ * Texas Instruments TNETV107X Touchscreen Driver
+ *
+ * Copyright (C) 2010 Texas Instruments
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <mach/tnetv107x.h>
+
+#define TSC_PENUP_POLL		(HZ / 5)
+#define IDLE_TIMEOUT		100 /* msec */
+
+/*
+ * The first and last samples of a touch interval are usually garbage and need
+ * to be filtered out with these devices.  The following definitions control
+ * the number of samples skipped.
+ */
+#define TSC_HEAD_SKIP		1
+#define TSC_TAIL_SKIP		1
+#define TSC_SKIP		(TSC_HEAD_SKIP + TSC_TAIL_SKIP + 1)
+#define TSC_SAMPLES		(TSC_SKIP + 1)
+
+/* Register Offsets */
+struct tsc_regs {
+	u32	rev;
+	u32	tscm;
+	u32	bwcm;
+	u32	swc;
+	u32	adcchnl;
+	u32	adcdata;
+	u32	chval[4];
+};
+
+/* TSC Mode Configuration Register (tscm) bits */
+#define WMODE		BIT(0)
+#define TSKIND		BIT(1)
+#define ZMEASURE_EN	BIT(2)
+#define IDLE		BIT(3)
+#define TSC_EN		BIT(4)
+#define STOP		BIT(5)
+#define ONE_SHOT	BIT(6)
+#define SINGLE		BIT(7)
+#define AVG		BIT(8)
+#define AVGNUM(x)	(((x) & 0x03) <<  9)
+#define PVSTC(x)	(((x) & 0x07) << 11)
+#define PON		BIT(14)
+#define PONBG		BIT(15)
+#define AFERST		BIT(16)
+
+/* ADC DATA Capture Register bits */
+#define DATA_VALID	BIT(16)
+
+/* Register Access Macros */
+#define tsc_read(ts, reg)		__raw_readl(&(ts)->regs->reg)
+#define tsc_write(ts, reg, val)		__raw_writel(val, &(ts)->regs->reg);
+#define tsc_set_bits(ts, reg, val)	\
+	tsc_write(ts, reg, tsc_read(ts, reg) | (val))
+#define tsc_clr_bits(ts, reg, val)	\
+	tsc_write(ts, reg, tsc_read(ts, reg) & ~(val))
+
+struct sample {
+	int x, y, p;
+};
+
+struct tsc_data {
+	struct input_dev		*input_dev;
+	struct resource			*res;
+	struct tsc_regs __iomem		*regs;
+	struct timer_list		timer;
+	spinlock_t			lock;
+	struct clk			*clk;
+	struct device			*dev;
+	int				sample_count;
+	struct sample			samples[TSC_SAMPLES];
+	int				tsc_irq;
+};
+
+static int tsc_read_sample(struct tsc_data *ts, struct sample* sample)
+{
+	int	x, y, z1, z2, t, p = 0;
+	u32	val;
+
+	val = tsc_read(ts, chval[0]);
+	if (val & DATA_VALID)
+		x = val & 0xffff;
+	else
+		return -EINVAL;
+
+	y  = tsc_read(ts, chval[1]) & 0xffff;
+	z1 = tsc_read(ts, chval[2]) & 0xffff;
+	z2 = tsc_read(ts, chval[3]) & 0xffff;
+
+	if (z1) {
+		t = ((600 * x) * (z2 - z1));
+		p = t / (u32) (z1 << 12);
+		if (p < 0)
+			p = 0;
+	}
+
+	sample->x  = x;
+	sample->y  = y;
+	sample->p  = p;
+
+	return 0;
+}
+
+static void tsc_poll(unsigned long data)
+{
+	struct tsc_data *ts = (struct tsc_data *)data;
+	unsigned long flags;
+	int i, val, x, y, p;
+
+	spin_lock_irqsave(&ts->lock, flags);
+
+	if (ts->sample_count >= TSC_SKIP) {
+		input_report_abs(ts->input_dev, ABS_PRESSURE, 0);
+		input_report_key(ts->input_dev, BTN_TOUCH, 0);
+		input_sync(ts->input_dev);
+	} else if (ts->sample_count > 0) {
+		/*
+		 * A touch event lasted less than our skip count.  Salvage and
+		 * report anyway.
+		 */
+		for (i = 0, val = 0; i < ts->sample_count; i++)
+			val += ts->samples[i].x;
+		x = val / ts->sample_count;
+
+		for (i = 0, val = 0; i < ts->sample_count; i++)
+			val += ts->samples[i].y;
+		y = val / ts->sample_count;
+
+		for (i = 0, val = 0; i < ts->sample_count; i++)
+			val += ts->samples[i].p;
+		p = val / ts->sample_count;
+
+		input_report_abs(ts->input_dev, ABS_X, x);
+		input_report_abs(ts->input_dev, ABS_Y, y);
+		input_report_abs(ts->input_dev, ABS_PRESSURE, p);
+		input_report_key(ts->input_dev, BTN_TOUCH, 1);
+		input_sync(ts->input_dev);
+	}
+
+	ts->sample_count = 0;
+
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static irqreturn_t tsc_irq(int irq, void *dev_id)
+{
+	struct tsc_data *ts = (struct tsc_data *)dev_id;
+	struct sample *sample;
+	int index;
+
+	spin_lock(&ts->lock);
+
+	index = ts->sample_count % TSC_SAMPLES;
+	sample = &ts->samples[index];
+	if (tsc_read_sample(ts, sample) < 0)
+		goto out;
+
+	if (++ts->sample_count >= TSC_SKIP) {
+		index = (ts->sample_count - TSC_TAIL_SKIP - 1) % TSC_SAMPLES;
+		sample = &ts->samples[index];
+
+		input_report_abs(ts->input_dev, ABS_X, sample->x);
+		input_report_abs(ts->input_dev, ABS_Y, sample->y);
+		input_report_abs(ts->input_dev, ABS_PRESSURE, sample->p);
+		if (ts->sample_count == TSC_SKIP)
+			input_report_key(ts->input_dev, BTN_TOUCH, 1);
+		input_sync(ts->input_dev);
+	}
+	mod_timer(&ts->timer, jiffies + TSC_PENUP_POLL);
+out:
+	spin_unlock(&ts->lock);
+	return IRQ_HANDLED;
+}
+
+static int tsc_start(struct input_dev *dev)
+{
+	struct tsc_data *ts = input_get_drvdata(dev);
+	unsigned long timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT);
+	u32 val;
+
+	clk_enable(ts->clk);
+
+	/* Go to idle mode, before any initialization */
+	while (time_after(timeout, jiffies)) {
+		if (tsc_read(ts, tscm) & IDLE)
+			break;
+	}
+
+	if (time_before(timeout, jiffies)) {
+		dev_warn(ts->dev, "timeout waiting for idle\n");
+		clk_disable(ts->clk);
+		return -EIO;
+	}
+
+	/* Configure TSC Control register*/
+	val = (PONBG | PON | PVSTC(4) | ONE_SHOT | ZMEASURE_EN);
+	tsc_write(ts, tscm, val);
+
+	/* Bring TSC out of reset: Clear AFE reset bit */
+	val &= ~(AFERST);
+	tsc_write(ts, tscm, val);
+
+	/* Configure all pins for hardware control*/
+	tsc_write(ts, bwcm, 0);
+
+	/* Finally enable the TSC */
+	tsc_set_bits(ts, tscm, TSC_EN);
+
+	return 0;
+}
+
+static void tsc_stop(struct input_dev *dev)
+{
+	struct tsc_data *ts = input_get_drvdata(dev);
+
+	tsc_clr_bits(ts, tscm, TSC_EN);
+	synchronize_irq(ts->tsc_irq);
+	del_timer_sync(&ts->timer);
+	clk_disable(ts->clk);
+}
+
+static int __devinit tsc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tsc_data *ts;
+	int error = 0;
+	u32 rev = 0;
+
+	ts = kzalloc(sizeof(struct tsc_data), GFP_KERNEL);
+	if (!ts) {
+		dev_err(dev, "cannot allocate device info\n");
+		return -ENOMEM;
+	}
+
+	ts->dev = dev;
+	spin_lock_init(&ts->lock);
+	setup_timer(&ts->timer, tsc_poll, (unsigned long)ts);
+	platform_set_drvdata(pdev, ts);
+
+	ts->tsc_irq = platform_get_irq(pdev, 0);
+	if (ts->tsc_irq < 0) {
+		dev_err(dev, "cannot determine device interrupt\n");
+		error = -ENODEV;
+		goto error_res;
+	}
+
+	ts->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!ts->res) {
+		dev_err(dev, "cannot determine register area\n");
+		error = -ENODEV;
+		goto error_res;
+	}
+
+	if (!request_mem_region(ts->res->start, resource_size(ts->res),
+				pdev->name)) {
+		dev_err(dev, "cannot claim register memory\n");
+		ts->res = NULL;
+		error = -EINVAL;
+		goto error_res;
+	}
+
+	ts->regs = ioremap(ts->res->start, resource_size(ts->res));
+	if (!ts->regs) {
+		dev_err(dev, "cannot map register memory\n");
+		error = -ENOMEM;
+		goto error_map;
+	}
+
+	ts->clk = clk_get(dev, NULL);
+	if (IS_ERR(ts->clk)) {
+		dev_err(dev, "cannot claim device clock\n");
+		error = PTR_ERR(ts->clk);
+		goto error_clk;
+	}
+
+	error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, 0,
+				     dev_name(dev), ts);
+	if (error < 0) {
+		dev_err(ts->dev, "Could not allocate ts irq\n");
+		goto error_irq;
+	}
+
+	ts->input_dev = input_allocate_device();
+	if (!ts->input_dev) {
+		dev_err(dev, "cannot allocate input device\n");
+		error = -ENOMEM;
+		goto error_input;
+	}
+	input_set_drvdata(ts->input_dev, ts);
+
+	ts->input_dev->name       = pdev->name;
+	ts->input_dev->id.bustype = BUS_HOST;
+	ts->input_dev->dev.parent = &pdev->dev;
+	ts->input_dev->open	  = tsc_start;
+	ts->input_dev->close	  = tsc_stop;
+
+	clk_enable(ts->clk);
+	rev = tsc_read(ts, rev);
+	ts->input_dev->id.product = ((rev >>  8) & 0x07);
+	ts->input_dev->id.version = ((rev >> 16) & 0xfff);
+	clk_disable(ts->clk);
+
+	__set_bit(EV_KEY,    ts->input_dev->evbit);
+	__set_bit(EV_ABS,    ts->input_dev->evbit);
+	__set_bit(BTN_TOUCH, ts->input_dev->keybit);
+
+	input_set_abs_params(ts->input_dev, ABS_X, 0, 0xffff, 5, 0);
+	input_set_abs_params(ts->input_dev, ABS_Y, 0, 0xffff, 5, 0);
+	input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 4095, 128, 0);
+
+	error = input_register_device(ts->input_dev);
+	if (error < 0) {
+		dev_err(dev, "failed input device registration\n");
+		goto error_reg;
+	}
+
+	return 0;
+
+error_reg:
+	input_free_device(ts->input_dev);
+error_input:
+	free_irq(ts->tsc_irq, ts);
+error_irq:
+	clk_put(ts->clk);
+error_clk:
+	iounmap(ts->regs);
+error_map:
+	release_mem_region(ts->res->start, resource_size(ts->res));
+error_res:
+	platform_set_drvdata(pdev, NULL);
+	kfree(ts);
+
+	return error;
+}
+
+static int __devexit tsc_remove(struct platform_device *pdev)
+{
+	struct tsc_data *ts = platform_get_drvdata(pdev);
+
+	input_unregister_device(ts->input_dev);
+	free_irq(ts->tsc_irq, ts);
+	clk_put(ts->clk);
+	iounmap(ts->regs);
+	release_mem_region(ts->res->start, resource_size(ts->res));
+	platform_set_drvdata(pdev, NULL);
+	kfree(ts);
+
+	return 0;
+}
+
+static struct platform_driver tsc_driver = {
+	.probe		= tsc_probe,
+	.remove		= __devexit_p(tsc_remove),
+	.driver.name	= "tnetv107x-ts",
+	.driver.owner	= THIS_MODULE,
+};
+module_platform_driver(tsc_driver);
+
+MODULE_AUTHOR("Cyril Chemparathy");
+MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
+MODULE_ALIAS("platform:tnetv107x-ts");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchit213.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchit213.c
new file mode 100644
index 0000000..d1297ba
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchit213.c
@@ -0,0 +1,234 @@
+/*
+ * Sahara TouchIT-213 serial touchscreen driver
+ *
+ * Copyright (c) 2007-2008 Claudio Nieder <private@claudio.ch>
+ *
+ * Based on Touchright driver (drivers/input/touchscreen/touchright.c)
+ * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
+ * Copyright (c) 2004 Vojtech Pavlik
+ * and Dan Streetman <ddstreet@ieee.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Sahara TouchIT-213 serial touchscreen driver"
+
+MODULE_AUTHOR("Claudio Nieder <private@claudio.ch>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+/*
+ * Data is received through COM1 at 9600bit/s,8bit,no parity in packets
+ * of 5 byte each.
+ *
+ *   +--------+   +--------+   +--------+   +--------+   +--------+
+ *   |1000000p|   |0xxxxxxx|   |0xxxxxxx|   |0yyyyyyy|   |0yyyyyyy|
+ *   +--------+   +--------+   +--------+   +--------+   +--------+
+ *                    MSB          LSB          MSB          LSB
+ *
+ * The value of p is 1 as long as the screen is touched and 0 when
+ * reporting the location where touching stopped, e.g. where the pen was
+ * lifted from the screen.
+ *
+ * When holding the screen in landscape mode as the BIOS text output is
+ * presented, x is the horizontal axis with values growing from left to
+ * right and y is the vertical axis with values growing from top to
+ * bottom.
+ *
+ * When holding the screen in portrait mode with the Sahara logo in its
+ * correct position, x ist the vertical axis with values growing from
+ * top to bottom and y is the horizontal axis with values growing from
+ * right to left.
+ */
+
+#define T213_FORMAT_TOUCH_BIT	0x01
+#define T213_FORMAT_STATUS_BYTE	0x80
+#define T213_FORMAT_STATUS_MASK	~T213_FORMAT_TOUCH_BIT
+
+/*
+ * On my Sahara Touch-IT 213 I have observed x values from 0 to 0x7f0
+ * and y values from 0x1d to 0x7e9, so the actual measurement is
+ * probably done with an 11 bit precision.
+ */
+#define T213_MIN_XC 0
+#define T213_MAX_XC 0x07ff
+#define T213_MIN_YC 0
+#define T213_MAX_YC 0x07ff
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct touchit213 {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char csum;
+	unsigned char data[5];
+	char phys[32];
+};
+
+static irqreturn_t touchit213_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct touchit213 *touchit213 = serio_get_drvdata(serio);
+	struct input_dev *dev = touchit213->dev;
+
+	touchit213->data[touchit213->idx] = data;
+
+	switch (touchit213->idx++) {
+	case 0:
+		if ((touchit213->data[0] & T213_FORMAT_STATUS_MASK) !=
+				T213_FORMAT_STATUS_BYTE) {
+			pr_debug("unsynchronized data: 0x%02x\n", data);
+			touchit213->idx = 0;
+		}
+		break;
+
+	case 4:
+		touchit213->idx = 0;
+		input_report_abs(dev, ABS_X,
+			(touchit213->data[1] << 7) | touchit213->data[2]);
+		input_report_abs(dev, ABS_Y,
+			(touchit213->data[3] << 7) | touchit213->data[4]);
+		input_report_key(dev, BTN_TOUCH,
+			touchit213->data[0] & T213_FORMAT_TOUCH_BIT);
+		input_sync(dev);
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * touchit213_disconnect() is the opposite of touchit213_connect()
+ */
+
+static void touchit213_disconnect(struct serio *serio)
+{
+	struct touchit213 *touchit213 = serio_get_drvdata(serio);
+
+	input_get_device(touchit213->dev);
+	input_unregister_device(touchit213->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(touchit213->dev);
+	kfree(touchit213);
+}
+
+/*
+ * touchit213_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Touchright protocol and registers it as
+ * an input device.
+ */
+
+static int touchit213_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct touchit213 *touchit213;
+	struct input_dev *input_dev;
+	int err;
+
+	touchit213 = kzalloc(sizeof(struct touchit213), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!touchit213 || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	touchit213->serio = serio;
+	touchit213->dev = input_dev;
+	snprintf(touchit213->phys, sizeof(touchit213->phys),
+		 "%s/input0", serio->phys);
+
+	input_dev->name = "Sahara Touch-iT213 Serial TouchScreen";
+	input_dev->phys = touchit213->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_TOUCHIT213;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(touchit213->dev, ABS_X,
+			     T213_MIN_XC, T213_MAX_XC, 0, 0);
+	input_set_abs_params(touchit213->dev, ABS_Y,
+			     T213_MIN_YC, T213_MAX_YC, 0, 0);
+
+	serio_set_drvdata(serio, touchit213);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(touchit213->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(touchit213);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id touchit213_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_TOUCHIT213,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, touchit213_serio_ids);
+
+static struct serio_driver touchit213_drv = {
+	.driver		= {
+		.name	= "touchit213",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= touchit213_serio_ids,
+	.interrupt	= touchit213_interrupt,
+	.connect	= touchit213_connect,
+	.disconnect	= touchit213_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init touchit213_init(void)
+{
+	return serio_register_driver(&touchit213_drv);
+}
+
+static void __exit touchit213_exit(void)
+{
+	serio_unregister_driver(&touchit213_drv);
+}
+
+module_init(touchit213_init);
+module_exit(touchit213_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchright.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchright.c
new file mode 100644
index 0000000..3a5c142
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchright.c
@@ -0,0 +1,194 @@
+/*
+ * Touchright serial touchscreen driver
+ *
+ * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
+ *
+ * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
+ * Copyright (c) 2004 Vojtech Pavlik
+ * and Dan Streetman <ddstreet@ieee.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Touchright serial touchscreen driver"
+
+MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define TR_FORMAT_TOUCH_BIT	0x01
+#define TR_FORMAT_STATUS_BYTE	0x40
+#define TR_FORMAT_STATUS_MASK	~TR_FORMAT_TOUCH_BIT
+
+#define TR_LENGTH 5
+
+#define TR_MIN_XC 0
+#define TR_MAX_XC 0x1ff
+#define TR_MIN_YC 0
+#define TR_MAX_YC 0x1ff
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct tr {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	unsigned char data[TR_LENGTH];
+	char phys[32];
+};
+
+static irqreturn_t tr_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct tr *tr = serio_get_drvdata(serio);
+	struct input_dev *dev = tr->dev;
+
+	tr->data[tr->idx] = data;
+
+	if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) {
+		if (++tr->idx == TR_LENGTH) {
+			input_report_abs(dev, ABS_X,
+				(tr->data[1] << 5) | (tr->data[2] >> 1));
+			input_report_abs(dev, ABS_Y,
+				(tr->data[3] << 5) | (tr->data[4] >> 1));
+			input_report_key(dev, BTN_TOUCH,
+				tr->data[0] & TR_FORMAT_TOUCH_BIT);
+			input_sync(dev);
+			tr->idx = 0;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * tr_disconnect() is the opposite of tr_connect()
+ */
+
+static void tr_disconnect(struct serio *serio)
+{
+	struct tr *tr = serio_get_drvdata(serio);
+
+	input_get_device(tr->dev);
+	input_unregister_device(tr->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(tr->dev);
+	kfree(tr);
+}
+
+/*
+ * tr_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Touchright protocol and registers it as
+ * an input device.
+ */
+
+static int tr_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct tr *tr;
+	struct input_dev *input_dev;
+	int err;
+
+	tr = kzalloc(sizeof(struct tr), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!tr || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	tr->serio = serio;
+	tr->dev = input_dev;
+	snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "Touchright Serial TouchScreen";
+	input_dev->phys = tr->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_TOUCHRIGHT;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
+	input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0);
+
+	serio_set_drvdata(serio, tr);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(tr->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(tr);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id tr_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_TOUCHRIGHT,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, tr_serio_ids);
+
+static struct serio_driver tr_drv = {
+	.driver		= {
+		.name	= "touchright",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= tr_serio_ids,
+	.interrupt	= tr_interrupt,
+	.connect	= tr_connect,
+	.disconnect	= tr_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init tr_init(void)
+{
+	return serio_register_driver(&tr_drv);
+}
+
+static void __exit tr_exit(void)
+{
+	serio_unregister_driver(&tr_drv);
+}
+
+module_init(tr_init);
+module_exit(tr_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchscreen.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchscreen.c
new file mode 100644
index 0000000..062727b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchscreen.c
@@ -0,0 +1,550 @@
+/* drivers/input/touchscreen/touchscreen.c 

+* 

+* TouchScreen driver. 

+* 

+* Copyright (c) 

+* 

+* This software is licensed under the terms of the GNU General Public 

+* License version 2, as published by the Free Software Foundation, and 

+* may be copied, distributed, and modified under those terms. 

+* 

+* This program is distributed in the hope that it will be useful, 

+* but WITHOUT ANY WARRANTY; without even the implied warranty of 

+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

+* GNU General Public License for more details. 

+* 

+*/ 

+#include <linux/i2c.h> 

+#include <linux/input.h> 

+#include <linux/delay.h> 

+#include <linux/slab.h> 

+#include <linux/interrupt.h> 

+#include <mach/irqs.h> 

+#include <linux/kernel.h> 

+#include <linux/semaphore.h> 

+#include <linux/mutex.h> 

+#include <linux/module.h> 

+#include <linux/gpio.h> 

+#include <linux/syscalls.h> 

+#include <linux/unistd.h> 

+#include <linux/uaccess.h> 

+#include <linux/fs.h> 

+#include <linux/string.h> 

+#include <linux/timer.h> 

+#include <linux/of.h> 

+#include <linux/of_gpio.h> 

+#include <linux/irq.h>

+#include <mach/gpio_cfg.h>

+#include <linux/input/touchscreen.h> 

+

+static struct mutex i2c_rw_access;

+static u8 s_pmode = 0;

+static struct input_dev *tp_input_dev; 

+static struct touchscreen_operations *ts_operations[MAX_TOUCHSCREEN_DEV_TYPE] = { NULL };

+static struct touchscreen_register *touchscreen_dev_register_tbl[MAX_TOUCHSCREEN_DEV_TYPE]  = { NULL };

+static struct ts_data *s_touchscreen_data = NULL;

+

+enum touchscreen_type touchscreen_detected_type = MAX_TOUCHSCREEN_DEV_TYPE;

+

+void touchscreen_set_operations(enum touchscreen_type id, struct touchscreen_operations *pt_operations)

+{

+    ts_operations[id] = pt_operations;

+}

+

+void touchscreen_register(enum touchscreen_type id, struct touchscreen_register *pt_register)

+{

+    touchscreen_dev_register_tbl[id] = pt_register;

+}

+

+int tp_i2c_read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen)

+{

+    int ret = 0;

+

+    if (client == NULL)

+    {

+		dev_err(&client->dev, "[IIC][%s]i2c_client==NULL!\n", __func__); 

+        return -1;

+    }

+

+    mutex_lock(&i2c_rw_access);

+	

+    if (readlen > 0)

+    {

+        if (writelen > 0)

+        {

+            struct i2c_msg msgs[] =

+            {

+                {

+                    .addr = client->addr,

+                    .flags = 0,

+                    .len = writelen,

+                    .buf = writebuf,

+                },

+                {

+                    .addr = client->addr,

+                    .flags = I2C_M_RD,

+                    .len = readlen,

+                    .buf = readbuf,

+                },

+            };

+            ret = i2c_transfer(client->adapter, msgs, 2);

+            if (ret < 0)

+            {

+				dev_err(&client->dev, "%s [IIC]: i2c_transfer(write) error, ret=%d!!\n", __func__,ret); 

+            }

+        }

+        else

+        {

+            struct i2c_msg msgs[] =

+            {

+                {

+                    .addr = client->addr,

+                    .flags = I2C_M_RD,

+                    .len = readlen,

+                    .buf = readbuf,

+                },

+            };

+            ret = i2c_transfer(client->adapter, msgs, 1);

+            if (ret < 0)

+            {

+			   dev_err(&client->dev, "%s IIC]: i2c_transfer(read) error, ret=%d!!\n", __func__,ret); 

+            }

+        }

+    }

+

+    mutex_unlock(&i2c_rw_access);

+	

+    return ret;

+}

+

+int tp_i2c_write(struct i2c_client *client, char *writebuf, int writelen)

+{

+    int ret = 0;

+

+    if (client == NULL)

+    {

+		dev_err(&client->dev, "[IIC][%s]i2c_client==NULL!\n", __func__); 

+        return -1;

+    }

+

+    mutex_lock(&i2c_rw_access);

+	

+    if (writelen > 0)

+    {

+        struct i2c_msg msgs[] =

+        {

+            {

+                .addr = client->addr,

+                .flags = 0,

+                .len = writelen,

+                .buf = writebuf,

+            },

+        };

+        ret = i2c_transfer(client->adapter, msgs, 1);

+        if (ret < 0)

+        {

+           dev_err(&client->dev, "%s [IIC]: i2c_transfer(write) error, ret=%d!!.\n", __func__,ret); 

+        }

+    }

+	

+    mutex_unlock(&i2c_rw_access);

+

+    return ret;

+}

+

+int tp_read(struct i2c_client *client, u8 regaddr, u8 len, u8 *regvalue) //len:1 hyn_i2c_read_reg

+{

+    return tp_i2c_read(client, &regaddr, 1, regvalue, len);

+}

+

+int tp_write(struct i2c_client *client, u8 regaddr, u8 regvalue) //len: 2( any value) hyn_i2c_write_reg

+{

+    u8 buf[2] = {0};

+

+    buf[0] = regaddr;

+    buf[1] = regvalue;

+    return tp_i2c_write(client, buf, sizeof(buf));

+}

+

+static int tp_read_touchdata(struct ts_data *data) 

+{ 

+	int ret = -1; 

+

+	if (NULL == ts_operations[touchscreen_detected_type]) {

+		return -1;

+	}

+

+	if (NULL == ts_operations[touchscreen_detected_type]->ts_read_touchdata) {   

+		return -1;

+	}

+	

+	ret = ts_operations[touchscreen_detected_type]->ts_read_touchdata(data);

+

+	if (ret >= 0)

+	{

+		return 0;

+	}

+	return ret; 

+	

+}

+

+static void tp_report_values(struct ts_data *data) 

+{ 

+	struct ts_event *event = data->events; 

+

+	if (data->touch_points > 0) { 

+		input_report_abs(data->input_dev, ABS_X, event[0].x); 

+		input_report_abs(data->input_dev, ABS_Y, event[0].y); 

+		input_report_key(data->input_dev, BTN_TOUCH, 1); 

+

+		input_sync(data->input_dev); 

+	} else if (data->touch_points == 0) { 

+		input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0); 

+		input_report_key(data->input_dev, BTN_TOUCH, 0); /*Up*/

+		input_sync(data->input_dev); 

+	} 

+} 

+

+static irqreturn_t tp_ts_interrupt(int irq, void *dev_id) 

+{ 

+	struct ts_data *touchscreen_data = dev_id; 

+	int ret = 0; 

+       //printk("[TP]tp_ts_interrupt happen \n");

+	ret = tp_read_touchdata(touchscreen_data); 

+	

+	if (ret == 0) 

+		tp_report_values(touchscreen_data); 

+

+	return IRQ_HANDLED; 

+} 

+

+#ifdef CONFIG_SYSFS

+static ssize_t tp_sysfs_show(struct device *dev,

+		struct device_attribute *attr, char *buf);

+static ssize_t tp_sysfs_store(struct device *dev,

+		struct device_attribute *attr, const char *buf, size_t count);

+

+

+DEVICE_ATTR(tp_mode, S_IWUSR | S_IRUGO, tp_sysfs_show, tp_sysfs_store);

+

+static struct attribute * tp_sysfs_attrs[] = {

+	&dev_attr_tp_mode.attr,

+	NULL

+};

+

+static const struct attribute_group tp_sysfs_attr_group = {

+	.attrs = tp_sysfs_attrs,

+};

+

+static int tp_sysfs_create_group(struct ts_data *touchscreen_data)

+{

+	return sysfs_create_group(&touchscreen_data->input_dev->dev.kobj, &tp_sysfs_attr_group);

+}

+

+static void tp_sysfs_remove_group(struct ts_data *touchscreen_data)

+{

+	sysfs_remove_group(&touchscreen_data->client->dev.kobj, &tp_sysfs_attr_group);

+}

+

+static ssize_t tp_sysfs_show(struct device *dev,

+		struct device_attribute *attr, char *buf)

+{

+	u8 val = 0;

+	int ret = 0;

+	

+	ret = tp_read(s_touchscreen_data->client, TP_REG_ID_PMODE, 1, &val);

+	if(ret < 0)

+		val = 0xff;

+

+	return scnprintf(buf, PAGE_SIZE, "%d",val);

+}

+

+static ssize_t tp_sysfs_store(struct device *dev,

+		struct device_attribute *attr, const char *buf, size_t count)

+{

+	u8 pmode_sleep  = 0x03;

+	unsigned long pmode = 0;

+	u8 read_val = 0xff;

+	if(strict_strtoul(buf, 0, &pmode))

+		return -EINVAL;

+	

+	if (pmode) {

+		if(TP_SLEEP_OFF == s_touchscreen_data->pmode)

+			return count;

+		gpio_set_value(PIN_TP_RST, 0); 

+		msleep(20); 

+		gpio_set_value(PIN_TP_RST, 1); 

+		msleep(200); 

+		s_touchscreen_data->pmode = TP_SLEEP_OFF;

+		//tp_write(s_touchscreen_data->client, TP_REG_ID_PMODE, &s_pmode);

+		//printk("tp_sysfs_store sleep out read_val =  %d, pmode = %d ,s_pmode = %d\n",read_val,pmode,s_pmode);

+	} else {

+		if(TP_SLEEP_ON == s_touchscreen_data->pmode)

+			return count;

+		tp_write(s_touchscreen_data->client, TP_REG_ID_PMODE, pmode_sleep);

+		s_touchscreen_data->pmode = TP_SLEEP_ON;

+		//printk("tp_sysfs_store sleep in  read_val =  %d, pmode = %d ,s_pmode = %d\n",read_val,pmode,s_pmode);

+	}

+	

+	return count;

+}

+#else

+static int tp_sysfs_create_group(struct ts_data *touchscreen_data)

+{

+	return 0;

+}

+

+static void tp_sysfs_remove_group(struct ts_data *touchscreen_data)

+{

+	return;

+}

+#endif

+

+static int ts_init_gpio(void)

+{

+       int err;

+	/* ÅäÖô¥ÃþÆÁʹÓõÄirq reset GPIO Òý½Å*/

+	err = gpio_request(PIN_TP_IRQ, "touchscreen_irq");

+	if (err) { 

+		printk( "[TP]request touchscreen irq gpio failed\n"); 

+		return -1;

+	}

+	zx29_gpio_config(PIN_TP_IRQ, TP_IRQ_FUN_SEL);

+	zx29_gpio_set_inttype(PIN_TP_IRQ, IRQ_TYPE_EDGE_FALLING);

+	zx29_gpio_pd_pu_set(PIN_TP_IRQ,  IO_CFG_PULL_DISABLE);

+

+	err = gpio_request(PIN_TP_RST, "touchscreen_reset");

+ 	if (err) { 

+		printk( "[TP]request touchscreen reset gpio failed\n"); 

+		return -1;

+	}

+	zx29_gpio_config(PIN_TP_RST, TP_RST_GPIO_SEL);

+	gpio_direction_output(PIN_TP_RST, GPIO_OUT);

+	

+	gpio_set_value(PIN_TP_RST, 0); 

+	msleep(20); 

+	gpio_set_value(PIN_TP_RST, 1); 

+	msleep(200); 

+

+	return 0;

+}

+

+static int touchscreen_dev_detect(struct i2c_client *client)

+{

+	int ret = 0;

+	u32 dev_index = 0;

+	

+	ret = ts_init_gpio();

+	if(ret < 0)

+	{

+		return -1;

+	}

+

+	for (dev_index =0; dev_index < MAX_TOUCHSCREEN_DEV_TYPE; dev_index++) {

+		if (touchscreen_detected_type !=  MAX_TOUCHSCREEN_DEV_TYPE) {

+			printk(KERN_ERR "[TP]touchscreen_dev_detect:touchscreen_type=%d have been detected!\n",touchscreen_detected_type);	

+			return 0;

+		}

+		

+		if ( NULL == touchscreen_dev_register_tbl[dev_index]) {

+			printk(KERN_ERR "[TP]touchscreen_dev_detect:touchscreen_type=%d have been detected!\n",touchscreen_detected_type);	

+			return -1;

+		}

+		

+		if (touchscreen_dev_register_tbl[dev_index]->ts_id_detect != NULL) {

+			ret = touchscreen_dev_register_tbl[dev_index]->ts_id_detect(client);

+			printk("[TP]touchscreen_dev_detect dev_index = 0x%x, ret = 0x%x\n",dev_index,ret);

+			if (ret != 0) {

+			}

+			else{

+				break;

+			}

+		}	

+	}

+	

+	if (touchscreen_detected_type ==  MAX_TOUCHSCREEN_DEV_TYPE) {

+		printk(KERN_ERR "[TP]touchscreen_dev_detect:do not have the driver for this touchscreen type!\n");

+		return -ENXIO;

+	}

+	return 0;

+}

+

+static int ts_probe(struct i2c_client *client, 

+const struct i2c_device_id *id) 

+{ 

+	struct ts_data *touchscreen_data; 

+	struct input_dev *input_dev; 

+	int err = 0; 

+	int ret = -1;

+	

+	mutex_init(&i2c_rw_access);

+	

+	ret = touchscreen_dev_detect(client);

+	if(ret < 0)

+	{

+		dev_err(&client->dev, "[TP]%s: touchscreen_dev_detect irq failed\n", __func__); 

+		return -1;

+	}

+

+	touchscreen_data = kzalloc(sizeof(struct ts_data), GFP_KERNEL); 

+	s_touchscreen_data = touchscreen_data;

+	

+	if (!touchscreen_data) { 

+		err = -ENOMEM; 

+		goto exit_alloc_data_failed; 

+	} 

+	

+	i2c_set_clientdata(client, touchscreen_data); 

+	touchscreen_data->client = client; 

+	touchscreen_data->x_max = 4095; 

+	touchscreen_data->y_max = 4095; 

+	/* ×¢²á¶ÁÈ¡ÖÐ¶Ï */

+	err = devm_request_threaded_irq(&client->dev, gpio_to_irq(PIN_TP_IRQ), 

+				NULL, tp_ts_interrupt, IRQF_ONESHOT, 

+				client->dev.driver->name, touchscreen_data); 

+	

+	if (err < 0) { 

+		dev_err(&client->dev, "[TP]%s: request irq failed\n", __func__); 

+		goto exit_irq_request_failed; 

+	} 

+	/* ·ÖÅäÒ»¸öʼþÉϱ¨½á¹¹Ìå */

+	input_dev = input_allocate_device(); 

+	if (!input_dev) { 

+		err = -ENOMEM; 

+		dev_err(&client->dev, "[TP]failed to allocate input device\n"); 

+		goto exit_input_dev_alloc_failed; 

+	} 

+

+	touchscreen_data->input_dev = input_dev; 

+	/* ×¢²áÉ豸֧³ÖµÄevent ÀàÐÍ */

+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 

+

+	set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit); 

+	set_bit(ABS_MT_POSITION_X, input_dev->absbit); 

+	set_bit(ABS_MT_POSITION_Y, input_dev->absbit); 

+	set_bit(ABS_MT_PRESSURE, input_dev->absbit); 

+

+	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, touchscreen_data->x_max, 0, 0); 

+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, touchscreen_data->y_max, 0, 0); 

+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0); 

+	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, PRESS_MAX, 0, 0); 

+	input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, CFG_MAX_TOUCH_POINTS, 0, 0); 

+	input_set_abs_params(input_dev, ABS_X, 0, touchscreen_data->x_max, 0, 0); 

+	input_set_abs_params(input_dev, ABS_Y, 0, touchscreen_data->y_max, 0, 0); 

+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, PRESS_MAX, 0, 0); 

+	

+	/* EV KEY °´¼üʼþ EV_ABS ¾ø¶Ô×ø±ê£¬Èç´¥ÃþÆÁÉϱ¨µÄ×ø±ê */

+	set_bit(EV_KEY, input_dev->evbit); 

+	set_bit(EV_ABS, input_dev->evbit); 

+       

+	input_dev->name = TOUCHSCREEN_NAME; 

+	/* ×¢²áÕâ¸öinput É豸 */

+	err = input_register_device(input_dev); 

+	if (err) { 

+		dev_err(&client->dev, 

+		"[TP]ts_probe: failed to register input device: %s\n", 

+		dev_name(&client->dev)); 

+		goto exit_input_register_device_failed; 

+	} 

+		

+	tp_sysfs_create_group(touchscreen_data);

+	

+	return 0; 

+

+	exit_input_register_device_failed: 

+	input_free_device(input_dev); 

+

+	exit_input_dev_alloc_failed: 

+	exit_irq_request_failed: 

+	i2c_set_clientdata(client, NULL); 

+	kfree(touchscreen_data); 

+

+	exit_alloc_data_failed: 

+	return err; 

+} 

+

+#ifdef CONFIG_PM 

+static int ts_suspend(struct i2c_client *client, pm_message_t mesg) 

+{ 

+	u8 pmode_sleep	= 0x03;

+	struct ts_data *ts = i2c_get_clientdata(client); 

+	dev_dbg(&ts->client->dev, "[TP]ts_suspend \n"); 

+	disable_irq(PIN_TP_IRQ); 

+	

+	tp_write(s_touchscreen_data->client, TP_REG_ID_PMODE, pmode_sleep);

+	

+	return 0; 

+} 

+

+static int ts_resume(struct i2c_client *client) 

+{ 

+	struct ts_data *ts = i2c_get_clientdata(client); 

+	dev_dbg(&ts->client->dev, "[TP]ts_resume.\n"); 

+	if (gpio_is_valid(PIN_TP_RST)) { 

+		gpio_set_value(PIN_TP_RST, 0); 

+		msleep(20); 

+		gpio_set_value(PIN_TP_RST, 1); 

+		msleep(200); 

+	} 

+	enable_irq(PIN_TP_IRQ); 

+	return 0; 

+} 

+#endif 

+

+static int ts_remove(struct i2c_client *client) 

+{ 

+	struct ts_data *touchscreen_data; 

+	touchscreen_data = i2c_get_clientdata(client); 

+	tp_sysfs_remove_group(touchscreen_data);

+	input_unregister_device(touchscreen_data->input_dev); 

+	kfree(touchscreen_data); 

+	i2c_set_clientdata(client, NULL); 

+	return 0; 

+} 

+

+static const struct i2c_device_id ts_id[] = { 

+	{TOUCHSCREEN_NAME, 0}, 

+	{} 

+}; 

+

+MODULE_DEVICE_TABLE(i2c, ts_id); 

+

+#define ts_match_table NULL 

+

+static struct i2c_driver ts_driver = { 

+	.probe = ts_probe, 

+	.remove = ts_remove, 

+	.id_table = ts_id, 

+	.driver = { 

+		.name = TOUCHSCREEN_NAME, 

+		.owner = THIS_MODULE, 

+		.of_match_table = ts_match_table, 

+	}, 

+#ifdef CONFIG_PM

+	.suspend = ts_suspend, 

+	.resume = ts_resume, 

+#endif

+}; 

+

+static int __init ts_init(void) 

+{ 

+	int ret; 

+	ret = i2c_add_driver(&ts_driver); 

+	if (ret) 

+		pr_err("[TP]Adding touchscreen driver failed (errno = %d)\n", ret); 

+

+	return ret; 

+} 

+

+static void __exit ts_exit(void) 

+{ 

+	i2c_del_driver(&ts_driver); 

+} 

+

+module_init(ts_init); 

+module_exit(ts_exit); 

+

+MODULE_AUTHOR("Dyy"); 

+MODULE_DESCRIPTION("TouchScreen driver"); 

+MODULE_LICENSE("GPL");

+

diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchwin.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchwin.c
new file mode 100644
index 0000000..763a656
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/touchwin.c
@@ -0,0 +1,201 @@
+/*
+ * Touchwindow serial touchscreen driver
+ *
+ * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
+ *
+ * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
+ * Copyright (c) 2004 Vojtech Pavlik
+ * and Dan Streetman <ddstreet@ieee.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+/*
+ * 2005/02/19 Rick Koch:
+ *   The Touchwindow I used is made by Edmark Corp. and
+ *   constantly outputs a stream of 0's unless it is touched.
+ *   It then outputs 3 bytes: X, Y, and a copy of Y.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC	"Touchwindow serial touchscreen driver"
+
+MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define TW_LENGTH 3
+
+#define TW_MIN_XC 0
+#define TW_MAX_XC 0xff
+#define TW_MIN_YC 0
+#define TW_MAX_YC 0xff
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct tw {
+	struct input_dev *dev;
+	struct serio *serio;
+	int idx;
+	int touched;
+	unsigned char data[TW_LENGTH];
+	char phys[32];
+};
+
+static irqreturn_t tw_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct tw *tw = serio_get_drvdata(serio);
+	struct input_dev *dev = tw->dev;
+
+	if (data) {		/* touch */
+		tw->touched = 1;
+		tw->data[tw->idx++] = data;
+		/* verify length and that the two Y's are the same */
+		if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) {
+			input_report_abs(dev, ABS_X, tw->data[0]);
+			input_report_abs(dev, ABS_Y, tw->data[1]);
+			input_report_key(dev, BTN_TOUCH, 1);
+			input_sync(dev);
+			tw->idx = 0;
+		}
+	} else if (tw->touched) {	/* untouch */
+		input_report_key(dev, BTN_TOUCH, 0);
+		input_sync(dev);
+		tw->idx = 0;
+		tw->touched = 0;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * tw_disconnect() is the opposite of tw_connect()
+ */
+
+static void tw_disconnect(struct serio *serio)
+{
+	struct tw *tw = serio_get_drvdata(serio);
+
+	input_get_device(tw->dev);
+	input_unregister_device(tw->dev);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	input_put_device(tw->dev);
+	kfree(tw);
+}
+
+/*
+ * tw_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Touchwin protocol and registers it as
+ * an input device.
+ */
+
+static int tw_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct tw *tw;
+	struct input_dev *input_dev;
+	int err;
+
+	tw = kzalloc(sizeof(struct tw), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!tw || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	tw->serio = serio;
+	tw->dev = input_dev;
+	snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "Touchwindow Serial TouchScreen";
+	input_dev->phys = tw->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_TOUCHWIN;
+	input_dev->id.product = 0;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
+	input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0);
+
+	serio_set_drvdata(serio, tw);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = input_register_device(tw->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	serio_close(serio);
+ fail2:	serio_set_drvdata(serio, NULL);
+ fail1:	input_free_device(input_dev);
+	kfree(tw);
+	return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id tw_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_TOUCHWIN,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, tw_serio_ids);
+
+static struct serio_driver tw_drv = {
+	.driver		= {
+		.name	= "touchwin",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= tw_serio_ids,
+	.interrupt	= tw_interrupt,
+	.connect	= tw_connect,
+	.disconnect	= tw_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init tw_init(void)
+{
+	return serio_register_driver(&tw_drv);
+}
+
+static void __exit tw_exit(void)
+{
+	serio_unregister_driver(&tw_drv);
+}
+
+module_init(tw_init);
+module_exit(tw_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tps6507x-ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tps6507x-ts.c
new file mode 100644
index 0000000..f7eda3d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tps6507x-ts.c
@@ -0,0 +1,377 @@
+/*
+ * Touchscreen driver for the tps6507x chip.
+ *
+ * Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com)
+ *
+ * Credits:
+ *
+ *    Using code from tsc2007, MtekVision Co., Ltd.
+ *
+ * For licencing details see kernel-base/COPYING
+ *
+ * TPS65070, TPS65073, TPS650731, and TPS650732 support
+ * 10 bit touch screen interface.
+ */
+
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/tps6507x.h>
+#include <linux/input/tps6507x-ts.h>
+#include <linux/delay.h>
+
+#define TSC_DEFAULT_POLL_PERIOD 30 /* ms */
+#define TPS_DEFAULT_MIN_PRESSURE 0x30
+#define MAX_10BIT ((1 << 10) - 1)
+
+#define	TPS6507X_ADCONFIG_CONVERT_TS (TPS6507X_ADCONFIG_AD_ENABLE | \
+					 TPS6507X_ADCONFIG_START_CONVERSION | \
+					 TPS6507X_ADCONFIG_INPUT_REAL_TSC)
+#define	TPS6507X_ADCONFIG_POWER_DOWN_TS (TPS6507X_ADCONFIG_INPUT_REAL_TSC)
+
+struct ts_event {
+	u16	x;
+	u16	y;
+	u16	pressure;
+};
+
+struct tps6507x_ts {
+	struct input_dev	*input_dev;
+	struct device		*dev;
+	char			phys[32];
+	struct delayed_work	work;
+	unsigned		polling;	/* polling is active */
+	struct ts_event		tc;
+	struct tps6507x_dev	*mfd;
+	u16			model;
+	unsigned		pendown;
+	int			irq;
+	void			(*clear_penirq)(void);
+	unsigned long		poll_period;	/* ms */
+	u16			min_pressure;
+	int			vref;		/* non-zero to leave vref on */
+};
+
+static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
+{
+	int err;
+
+	err = tsc->mfd->read_dev(tsc->mfd, reg, 1, data);
+
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data)
+{
+	return tsc->mfd->write_dev(tsc->mfd, reg, 1, &data);
+}
+
+static s32 tps6507x_adc_conversion(struct tps6507x_ts *tsc,
+				   u8 tsc_mode, u16 *value)
+{
+	s32 ret;
+	u8 adc_status;
+	u8 result;
+
+	/* Route input signal to A/D converter */
+
+	ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, tsc_mode);
+	if (ret) {
+		dev_err(tsc->dev, "TSC mode read failed\n");
+		goto err;
+	}
+
+	/* Start A/D conversion */
+
+	ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG,
+				TPS6507X_ADCONFIG_CONVERT_TS);
+	if (ret) {
+		dev_err(tsc->dev, "ADC config write failed\n");
+		return ret;
+	}
+
+	do {
+		ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADCONFIG,
+				       &adc_status);
+		if (ret) {
+			dev_err(tsc->dev, "ADC config read failed\n");
+			goto err;
+		}
+	} while (adc_status & TPS6507X_ADCONFIG_START_CONVERSION);
+
+	ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_2, &result);
+	if (ret) {
+		dev_err(tsc->dev, "ADC result 2 read failed\n");
+		goto err;
+	}
+
+	*value = (result & TPS6507X_REG_ADRESULT_2_MASK) << 8;
+
+	ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_1, &result);
+	if (ret) {
+		dev_err(tsc->dev, "ADC result 1 read failed\n");
+		goto err;
+	}
+
+	*value |= result;
+
+	dev_dbg(tsc->dev, "TSC channel %d = 0x%X\n", tsc_mode, *value);
+
+err:
+	return ret;
+}
+
+/* Need to call tps6507x_adc_standby() after using A/D converter for the
+ * touch screen interrupt to work properly.
+ */
+
+static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc)
+{
+	s32 ret;
+	s32 loops = 0;
+	u8 val;
+
+	ret = tps6507x_write_u8(tsc,  TPS6507X_REG_ADCONFIG,
+				TPS6507X_ADCONFIG_INPUT_TSC);
+	if (ret)
+		return ret;
+
+	ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE,
+				TPS6507X_TSCMODE_STANDBY);
+	if (ret)
+		return ret;
+
+	ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
+	if (ret)
+		return ret;
+
+	while (val & TPS6507X_REG_TSC_INT) {
+		mdelay(10);
+		ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val);
+		if (ret)
+			return ret;
+		loops++;
+	}
+
+	return ret;
+}
+
+static void tps6507x_ts_handler(struct work_struct *work)
+{
+	struct tps6507x_ts *tsc =  container_of(work,
+				struct tps6507x_ts, work.work);
+	struct input_dev *input_dev = tsc->input_dev;
+	int pendown;
+	int schd;
+	int poll = 0;
+	s32 ret;
+
+	ret =  tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
+				       &tsc->tc.pressure);
+	if (ret)
+		goto done;
+
+	pendown = tsc->tc.pressure > tsc->min_pressure;
+
+	if (unlikely(!pendown && tsc->pendown)) {
+		dev_dbg(tsc->dev, "UP\n");
+		input_report_key(input_dev, BTN_TOUCH, 0);
+		input_report_abs(input_dev, ABS_PRESSURE, 0);
+		input_sync(input_dev);
+		tsc->pendown = 0;
+	}
+
+	if (pendown) {
+
+		if (!tsc->pendown) {
+			dev_dbg(tsc->dev, "DOWN\n");
+			input_report_key(input_dev, BTN_TOUCH, 1);
+		} else
+			dev_dbg(tsc->dev, "still down\n");
+
+		ret =  tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_X_POSITION,
+					       &tsc->tc.x);
+		if (ret)
+			goto done;
+
+		ret =  tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_Y_POSITION,
+					       &tsc->tc.y);
+		if (ret)
+			goto done;
+
+		input_report_abs(input_dev, ABS_X, tsc->tc.x);
+		input_report_abs(input_dev, ABS_Y, tsc->tc.y);
+		input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
+		input_sync(input_dev);
+		tsc->pendown = 1;
+		poll = 1;
+	}
+
+done:
+	/* always poll if not using interrupts */
+	poll = 1;
+
+	if (poll) {
+		schd = schedule_delayed_work(&tsc->work,
+					msecs_to_jiffies(tsc->poll_period));
+		if (schd)
+			tsc->polling = 1;
+		else {
+			tsc->polling = 0;
+			dev_err(tsc->dev, "re-schedule failed");
+		}
+	} else
+		tsc->polling = 0;
+
+	ret = tps6507x_adc_standby(tsc);
+}
+
+static int tps6507x_ts_probe(struct platform_device *pdev)
+{
+	int error;
+	struct tps6507x_ts *tsc;
+	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
+	struct touchscreen_init_data *init_data;
+	struct input_dev *input_dev;
+	struct tps6507x_board *tps_board;
+	int schd;
+
+	/**
+	 * tps_board points to pmic related constants
+	 * coming from the board-evm file.
+	 */
+
+	tps_board = (struct tps6507x_board *)tps6507x_dev->dev->platform_data;
+
+	if (!tps_board) {
+		dev_err(tps6507x_dev->dev,
+			"Could not find tps6507x platform data\n");
+		return -EIO;
+	}
+
+	/**
+	 * init_data points to array of regulator_init structures
+	 * coming from the board-evm file.
+	 */
+
+	init_data = tps_board->tps6507x_ts_init_data;
+
+	tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL);
+	if (!tsc) {
+		dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
+		error = -ENOMEM;
+		goto err0;
+	}
+
+	tps6507x_dev->ts = tsc;
+	tsc->mfd = tps6507x_dev;
+	tsc->dev = tps6507x_dev->dev;
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(tsc->dev, "Failed to allocate input device.\n");
+		error = -ENOMEM;
+		goto err1;
+	}
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);
+
+	input_dev->name = "TPS6507x Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = tsc->dev;
+
+	snprintf(tsc->phys, sizeof(tsc->phys),
+		 "%s/input0", dev_name(tsc->dev));
+	input_dev->phys = tsc->phys;
+
+	dev_dbg(tsc->dev, "device: %s\n", input_dev->phys);
+
+	input_set_drvdata(input_dev, tsc);
+
+	tsc->input_dev = input_dev;
+
+	INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler);
+
+	if (init_data) {
+		tsc->poll_period = init_data->poll_period;
+		tsc->vref = init_data->vref;
+		tsc->min_pressure = init_data->min_pressure;
+		input_dev->id.vendor = init_data->vendor;
+		input_dev->id.product = init_data->product;
+		input_dev->id.version = init_data->version;
+	} else {
+		tsc->poll_period = TSC_DEFAULT_POLL_PERIOD;
+		tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE;
+	}
+
+	error = tps6507x_adc_standby(tsc);
+	if (error)
+		goto err2;
+
+	error = input_register_device(input_dev);
+	if (error)
+		goto err2;
+
+	schd = schedule_delayed_work(&tsc->work,
+				     msecs_to_jiffies(tsc->poll_period));
+
+	if (schd)
+		tsc->polling = 1;
+	else {
+		tsc->polling = 0;
+		dev_err(tsc->dev, "schedule failed");
+		goto err2;
+	 }
+	platform_set_drvdata(pdev, tps6507x_dev);
+
+	return 0;
+
+err2:
+	cancel_delayed_work_sync(&tsc->work);
+	input_free_device(input_dev);
+err1:
+	kfree(tsc);
+	tps6507x_dev->ts = NULL;
+err0:
+	return error;
+}
+
+static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
+{
+	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
+	struct tps6507x_ts *tsc = tps6507x_dev->ts;
+	struct input_dev *input_dev = tsc->input_dev;
+
+	cancel_delayed_work_sync(&tsc->work);
+
+	input_unregister_device(input_dev);
+
+	tps6507x_dev->ts = NULL;
+	kfree(tsc);
+
+	return 0;
+}
+
+static struct platform_driver tps6507x_ts_driver = {
+	.driver = {
+		.name = "tps6507x-ts",
+		.owner = THIS_MODULE,
+	},
+	.probe = tps6507x_ts_probe,
+	.remove = __devexit_p(tps6507x_ts_remove),
+};
+module_platform_driver(tps6507x_ts_driver);
+
+MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>");
+MODULE_DESCRIPTION("TPS6507x - TouchScreen driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps6507x-ts");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc2005.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc2005.c
new file mode 100644
index 0000000..b6adeae
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc2005.c
@@ -0,0 +1,754 @@
+/*
+ * TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ *
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2005.h>
+
+/*
+ * The touchscreen interface operates as follows:
+ *
+ * 1) Pen is pressed against the touchscreen.
+ * 2) TSC2005 performs AD conversion.
+ * 3) After the conversion is done TSC2005 drives DAV line down.
+ * 4) GPIO IRQ is received and tsc2005_irq_thread() is scheduled.
+ * 5) tsc2005_irq_thread() queues up an spi transfer to fetch the x, y, z1, z2
+ *    values.
+ * 6) tsc2005_irq_thread() reports coordinates to input layer and sets up
+ *    tsc2005_penup_timer() to be called after TSC2005_PENUP_TIME_MS (40ms).
+ * 7) When the penup timer expires, there have not been touch or DAV interrupts
+ *    during the last 40ms which means the pen has been lifted.
+ *
+ * ESD recovery via a hardware reset is done if the TSC2005 doesn't respond
+ * after a configurable period (in ms) of activity. If esd_timeout is 0, the
+ * watchdog is disabled.
+ */
+
+/* control byte 1 */
+#define TSC2005_CMD			0x80
+#define TSC2005_CMD_NORMAL		0x00
+#define TSC2005_CMD_STOP		0x01
+#define TSC2005_CMD_12BIT		0x04
+
+/* control byte 0 */
+#define TSC2005_REG_READ		0x0001
+#define TSC2005_REG_PND0		0x0002
+#define TSC2005_REG_X			0x0000
+#define TSC2005_REG_Y			0x0008
+#define TSC2005_REG_Z1			0x0010
+#define TSC2005_REG_Z2			0x0018
+#define TSC2005_REG_TEMP_HIGH		0x0050
+#define TSC2005_REG_CFR0		0x0060
+#define TSC2005_REG_CFR1		0x0068
+#define TSC2005_REG_CFR2		0x0070
+
+/* configuration register 0 */
+#define TSC2005_CFR0_PRECHARGE_276US	0x0040
+#define TSC2005_CFR0_STABTIME_1MS	0x0300
+#define TSC2005_CFR0_CLOCK_1MHZ		0x1000
+#define TSC2005_CFR0_RESOLUTION12	0x2000
+#define TSC2005_CFR0_PENMODE		0x8000
+#define TSC2005_CFR0_INITVALUE		(TSC2005_CFR0_STABTIME_1MS    | \
+					 TSC2005_CFR0_CLOCK_1MHZ      | \
+					 TSC2005_CFR0_RESOLUTION12    | \
+					 TSC2005_CFR0_PRECHARGE_276US | \
+					 TSC2005_CFR0_PENMODE)
+
+/* bits common to both read and write of configuration register 0 */
+#define	TSC2005_CFR0_RW_MASK		0x3fff
+
+/* configuration register 1 */
+#define TSC2005_CFR1_BATCHDELAY_4MS	0x0003
+#define TSC2005_CFR1_INITVALUE		TSC2005_CFR1_BATCHDELAY_4MS
+
+/* configuration register 2 */
+#define TSC2005_CFR2_MAVE_Z		0x0004
+#define TSC2005_CFR2_MAVE_Y		0x0008
+#define TSC2005_CFR2_MAVE_X		0x0010
+#define TSC2005_CFR2_AVG_7		0x0800
+#define TSC2005_CFR2_MEDIUM_15		0x3000
+#define TSC2005_CFR2_INITVALUE		(TSC2005_CFR2_MAVE_X	| \
+					 TSC2005_CFR2_MAVE_Y	| \
+					 TSC2005_CFR2_MAVE_Z	| \
+					 TSC2005_CFR2_MEDIUM_15	| \
+					 TSC2005_CFR2_AVG_7)
+
+#define MAX_12BIT			0xfff
+#define TSC2005_SPI_MAX_SPEED_HZ	10000000
+#define TSC2005_PENUP_TIME_MS		40
+
+struct tsc2005_spi_rd {
+	struct spi_transfer	spi_xfer;
+	u32			spi_tx;
+	u32			spi_rx;
+};
+
+struct tsc2005 {
+	struct spi_device	*spi;
+
+	struct spi_message      spi_read_msg;
+	struct tsc2005_spi_rd	spi_x;
+	struct tsc2005_spi_rd	spi_y;
+	struct tsc2005_spi_rd	spi_z1;
+	struct tsc2005_spi_rd	spi_z2;
+
+	struct input_dev	*idev;
+	char			phys[32];
+
+	struct mutex		mutex;
+
+	/* raw copy of previous x,y,z */
+	int			in_x;
+	int			in_y;
+	int                     in_z1;
+	int			in_z2;
+
+	spinlock_t		lock;
+	struct timer_list	penup_timer;
+
+	unsigned int		esd_timeout;
+	struct delayed_work	esd_work;
+	unsigned long		last_valid_interrupt;
+
+	unsigned int		x_plate_ohm;
+
+	bool			opened;
+	bool			suspended;
+
+	bool			pen_down;
+
+	void			(*set_reset)(bool enable);
+};
+
+static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
+{
+	u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd;
+	struct spi_transfer xfer = {
+		.tx_buf		= &tx,
+		.len		= 1,
+		.bits_per_word	= 8,
+	};
+	struct spi_message msg;
+	int error;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	error = spi_sync(ts->spi, &msg);
+	if (error) {
+		dev_err(&ts->spi->dev, "%s: failed, command: %x, error: %d\n",
+			__func__, cmd, error);
+		return error;
+	}
+
+	return 0;
+}
+
+static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
+{
+	u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value;
+	struct spi_transfer xfer = {
+		.tx_buf		= &tx,
+		.len		= 4,
+		.bits_per_word	= 24,
+	};
+	struct spi_message msg;
+	int error;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	error = spi_sync(ts->spi, &msg);
+	if (error) {
+		dev_err(&ts->spi->dev,
+			"%s: failed, register: %x, value: %x, error: %d\n",
+			__func__, reg, value, error);
+		return error;
+	}
+
+	return 0;
+}
+
+static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last)
+{
+	memset(rd, 0, sizeof(*rd));
+
+	rd->spi_tx		   = (reg | TSC2005_REG_READ) << 16;
+	rd->spi_xfer.tx_buf	   = &rd->spi_tx;
+	rd->spi_xfer.rx_buf	   = &rd->spi_rx;
+	rd->spi_xfer.len	   = 4;
+	rd->spi_xfer.bits_per_word = 24;
+	rd->spi_xfer.cs_change	   = !last;
+}
+
+static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value)
+{
+	struct tsc2005_spi_rd spi_rd;
+	struct spi_message msg;
+	int error;
+
+	tsc2005_setup_read(&spi_rd, reg, true);
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&spi_rd.spi_xfer, &msg);
+
+	error = spi_sync(ts->spi, &msg);
+	if (error)
+		return error;
+
+	*value = spi_rd.spi_rx;
+	return 0;
+}
+
+static void tsc2005_update_pen_state(struct tsc2005 *ts,
+				     int x, int y, int pressure)
+{
+	if (pressure) {
+		input_report_abs(ts->idev, ABS_X, x);
+		input_report_abs(ts->idev, ABS_Y, y);
+		input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+		if (!ts->pen_down) {
+			input_report_key(ts->idev, BTN_TOUCH, !!pressure);
+			ts->pen_down = true;
+		}
+	} else {
+		input_report_abs(ts->idev, ABS_PRESSURE, 0);
+		if (ts->pen_down) {
+			input_report_key(ts->idev, BTN_TOUCH, 0);
+			ts->pen_down = false;
+		}
+	}
+	input_sync(ts->idev);
+	dev_dbg(&ts->spi->dev, "point(%4d,%4d), pressure (%4d)\n", x, y,
+		pressure);
+}
+
+static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
+{
+	struct tsc2005 *ts = _ts;
+	unsigned long flags;
+	unsigned int pressure;
+	u32 x, y;
+	u32 z1, z2;
+	int error;
+
+	/* read the coordinates */
+	error = spi_sync(ts->spi, &ts->spi_read_msg);
+	if (unlikely(error))
+		goto out;
+
+	x = ts->spi_x.spi_rx;
+	y = ts->spi_y.spi_rx;
+	z1 = ts->spi_z1.spi_rx;
+	z2 = ts->spi_z2.spi_rx;
+
+	/* validate position */
+	if (unlikely(x > MAX_12BIT || y > MAX_12BIT))
+		goto out;
+
+	/* Skip reading if the pressure components are out of range */
+	if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2))
+		goto out;
+
+       /*
+	* Skip point if this is a pen down with the exact same values as
+	* the value before pen-up - that implies SPI fed us stale data
+	*/
+	if (!ts->pen_down &&
+	    ts->in_x == x && ts->in_y == y &&
+	    ts->in_z1 == z1 && ts->in_z2 == z2) {
+		goto out;
+	}
+
+	/*
+	 * At this point we are happy we have a valid and useful reading.
+	 * Remember it for later comparisons. We may now begin downsampling.
+	 */
+	ts->in_x = x;
+	ts->in_y = y;
+	ts->in_z1 = z1;
+	ts->in_z2 = z2;
+
+	/* Compute touch pressure resistance using equation #1 */
+	pressure = x * (z2 - z1) / z1;
+	pressure = pressure * ts->x_plate_ohm / 4096;
+	if (unlikely(pressure > MAX_12BIT))
+		goto out;
+
+	spin_lock_irqsave(&ts->lock, flags);
+
+	tsc2005_update_pen_state(ts, x, y, pressure);
+	mod_timer(&ts->penup_timer,
+		  jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS));
+
+	spin_unlock_irqrestore(&ts->lock, flags);
+
+	ts->last_valid_interrupt = jiffies;
+out:
+	return IRQ_HANDLED;
+}
+
+static void tsc2005_penup_timer(unsigned long data)
+{
+	struct tsc2005 *ts = (struct tsc2005 *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ts->lock, flags);
+	tsc2005_update_pen_state(ts, 0, 0, 0);
+	spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static void tsc2005_start_scan(struct tsc2005 *ts)
+{
+	tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
+	tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
+	tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
+	tsc2005_cmd(ts, TSC2005_CMD_NORMAL);
+}
+
+static void tsc2005_stop_scan(struct tsc2005 *ts)
+{
+	tsc2005_cmd(ts, TSC2005_CMD_STOP);
+}
+
+/* must be called with ts->mutex held */
+static void __tsc2005_disable(struct tsc2005 *ts)
+{
+	tsc2005_stop_scan(ts);
+
+	disable_irq(ts->spi->irq);
+	del_timer_sync(&ts->penup_timer);
+
+	cancel_delayed_work_sync(&ts->esd_work);
+
+	enable_irq(ts->spi->irq);
+}
+
+/* must be called with ts->mutex held */
+static void __tsc2005_enable(struct tsc2005 *ts)
+{
+	tsc2005_start_scan(ts);
+
+	if (ts->esd_timeout && ts->set_reset) {
+		ts->last_valid_interrupt = jiffies;
+		schedule_delayed_work(&ts->esd_work,
+				round_jiffies_relative(
+					msecs_to_jiffies(ts->esd_timeout)));
+	}
+
+}
+
+static ssize_t tsc2005_selftest_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct tsc2005 *ts = spi_get_drvdata(spi);
+	u16 temp_high;
+	u16 temp_high_orig;
+	u16 temp_high_test;
+	bool success = true;
+	int error;
+
+	mutex_lock(&ts->mutex);
+
+	/*
+	 * Test TSC2005 communications via temp high register.
+	 */
+	__tsc2005_disable(ts);
+
+	error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig);
+	if (error) {
+		dev_warn(dev, "selftest failed: read error %d\n", error);
+		success = false;
+		goto out;
+	}
+
+	temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
+
+	error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test);
+	if (error) {
+		dev_warn(dev, "selftest failed: write error %d\n", error);
+		success = false;
+		goto out;
+	}
+
+	error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
+	if (error) {
+		dev_warn(dev, "selftest failed: read error %d after write\n",
+			 error);
+		success = false;
+		goto out;
+	}
+
+	if (temp_high != temp_high_test) {
+		dev_warn(dev, "selftest failed: %d != %d\n",
+			 temp_high, temp_high_test);
+		success = false;
+	}
+
+	/* hardware reset */
+	ts->set_reset(false);
+	usleep_range(100, 500); /* only 10us required */
+	ts->set_reset(true);
+
+	if (!success)
+		goto out;
+
+	/* test that the reset really happened */
+	error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high);
+	if (error) {
+		dev_warn(dev, "selftest failed: read error %d after reset\n",
+			 error);
+		success = false;
+		goto out;
+	}
+
+	if (temp_high != temp_high_orig) {
+		dev_warn(dev, "selftest failed after reset: %d != %d\n",
+			 temp_high, temp_high_orig);
+		success = false;
+	}
+
+out:
+	__tsc2005_enable(ts);
+	mutex_unlock(&ts->mutex);
+
+	return sprintf(buf, "%d\n", success);
+}
+
+static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL);
+
+static struct attribute *tsc2005_attrs[] = {
+	&dev_attr_selftest.attr,
+	NULL
+};
+
+static umode_t tsc2005_attr_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int n)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct spi_device *spi = to_spi_device(dev);
+	struct tsc2005 *ts = spi_get_drvdata(spi);
+	umode_t mode = attr->mode;
+
+	if (attr == &dev_attr_selftest.attr) {
+		if (!ts->set_reset)
+			mode = 0;
+	}
+
+	return mode;
+}
+
+static const struct attribute_group tsc2005_attr_group = {
+	.is_visible	= tsc2005_attr_is_visible,
+	.attrs		= tsc2005_attrs,
+};
+
+static void tsc2005_esd_work(struct work_struct *work)
+{
+	struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work);
+	int error;
+	u16 r;
+
+	if (!mutex_trylock(&ts->mutex)) {
+		/*
+		 * If the mutex is taken, it means that disable or enable is in
+		 * progress. In that case just reschedule the work. If the work
+		 * is not needed, it will be canceled by disable.
+		 */
+		goto reschedule;
+	}
+
+	if (time_is_after_jiffies(ts->last_valid_interrupt +
+				  msecs_to_jiffies(ts->esd_timeout)))
+		goto out;
+
+	/* We should be able to read register without disabling interrupts. */
+	error = tsc2005_read(ts, TSC2005_REG_CFR0, &r);
+	if (!error &&
+	    !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) {
+		goto out;
+	}
+
+	/*
+	 * If we could not read our known value from configuration register 0
+	 * then we should reset the controller as if from power-up and start
+	 * scanning again.
+	 */
+	dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n");
+
+	disable_irq(ts->spi->irq);
+	del_timer_sync(&ts->penup_timer);
+
+	tsc2005_update_pen_state(ts, 0, 0, 0);
+
+	ts->set_reset(false);
+	usleep_range(100, 500); /* only 10us required */
+	ts->set_reset(true);
+
+	enable_irq(ts->spi->irq);
+	tsc2005_start_scan(ts);
+
+out:
+	mutex_unlock(&ts->mutex);
+reschedule:
+	/* re-arm the watchdog */
+	schedule_delayed_work(&ts->esd_work,
+			      round_jiffies_relative(
+					msecs_to_jiffies(ts->esd_timeout)));
+}
+
+static int tsc2005_open(struct input_dev *input)
+{
+	struct tsc2005 *ts = input_get_drvdata(input);
+
+	mutex_lock(&ts->mutex);
+
+	if (!ts->suspended)
+		__tsc2005_enable(ts);
+
+	ts->opened = true;
+
+	mutex_unlock(&ts->mutex);
+
+	return 0;
+}
+
+static void tsc2005_close(struct input_dev *input)
+{
+	struct tsc2005 *ts = input_get_drvdata(input);
+
+	mutex_lock(&ts->mutex);
+
+	if (!ts->suspended)
+		__tsc2005_disable(ts);
+
+	ts->opened = false;
+
+	mutex_unlock(&ts->mutex);
+}
+
+static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts)
+{
+	tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false);
+	tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false);
+	tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false);
+	tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true);
+
+	spi_message_init(&ts->spi_read_msg);
+	spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg);
+	spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg);
+	spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg);
+	spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg);
+}
+
+static int __devinit tsc2005_probe(struct spi_device *spi)
+{
+	const struct tsc2005_platform_data *pdata = spi->dev.platform_data;
+	struct tsc2005 *ts;
+	struct input_dev *input_dev;
+	unsigned int max_x, max_y, max_p;
+	unsigned int fudge_x, fudge_y, fudge_p;
+	int error;
+
+	if (!pdata) {
+		dev_dbg(&spi->dev, "no platform data\n");
+		return -ENODEV;
+	}
+
+	fudge_x	= pdata->ts_x_fudge	   ? : 4;
+	fudge_y	= pdata->ts_y_fudge	   ? : 8;
+	fudge_p	= pdata->ts_pressure_fudge ? : 2;
+	max_x	= pdata->ts_x_max	   ? : MAX_12BIT;
+	max_y	= pdata->ts_y_max	   ? : MAX_12BIT;
+	max_p	= pdata->ts_pressure_max   ? : MAX_12BIT;
+
+	if (spi->irq <= 0) {
+		dev_dbg(&spi->dev, "no irq\n");
+		return -ENODEV;
+	}
+
+	spi->mode = SPI_MODE_0;
+	spi->bits_per_word = 8;
+	if (!spi->max_speed_hz)
+		spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ;
+
+	error = spi_setup(spi);
+	if (error)
+		return error;
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->spi = spi;
+	ts->idev = input_dev;
+
+	ts->x_plate_ohm	= pdata->ts_x_plate_ohm	? : 280;
+	ts->esd_timeout	= pdata->esd_timeout_ms;
+	ts->set_reset	= pdata->set_reset;
+
+	mutex_init(&ts->mutex);
+
+	spin_lock_init(&ts->lock);
+	setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts);
+
+	INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work);
+
+	tsc2005_setup_spi_xfer(ts);
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input-ts", dev_name(&spi->dev));
+
+	input_dev->name = "TSC2005 touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_SPI;
+	input_dev->dev.parent = &spi->dev;
+	input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
+
+	input_dev->open = tsc2005_open;
+	input_dev->close = tsc2005_close;
+
+	input_set_drvdata(input_dev, ts);
+
+	/* Ensure the touchscreen is off */
+	tsc2005_stop_scan(ts);
+
+	error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
+				     IRQF_TRIGGER_RISING, "tsc2005", ts);
+	if (error) {
+		dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
+		goto err_free_mem;
+	}
+
+	spi_set_drvdata(spi, ts);
+	error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group);
+	if (error) {
+		dev_err(&spi->dev,
+			"Failed to create sysfs attributes, err: %d\n", error);
+		goto err_clear_drvdata;
+	}
+
+	error = input_register_device(ts->idev);
+	if (error) {
+		dev_err(&spi->dev,
+			"Failed to register input device, err: %d\n", error);
+		goto err_remove_sysfs;
+	}
+
+	irq_set_irq_wake(spi->irq, 1);
+	return 0;
+
+err_remove_sysfs:
+	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
+err_clear_drvdata:
+	spi_set_drvdata(spi, NULL);
+	free_irq(spi->irq, ts);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	return error;
+}
+
+static int __devexit tsc2005_remove(struct spi_device *spi)
+{
+	struct tsc2005 *ts = spi_get_drvdata(spi);
+
+	sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
+
+	free_irq(ts->spi->irq, ts);
+	input_unregister_device(ts->idev);
+	kfree(ts);
+
+	spi_set_drvdata(spi, NULL);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tsc2005_suspend(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct tsc2005 *ts = spi_get_drvdata(spi);
+
+	mutex_lock(&ts->mutex);
+
+	if (!ts->suspended && ts->opened)
+		__tsc2005_disable(ts);
+
+	ts->suspended = true;
+
+	mutex_unlock(&ts->mutex);
+
+	return 0;
+}
+
+static int tsc2005_resume(struct device *dev)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct tsc2005 *ts = spi_get_drvdata(spi);
+
+	mutex_lock(&ts->mutex);
+
+	if (ts->suspended && ts->opened)
+		__tsc2005_enable(ts);
+
+	ts->suspended = false;
+
+	mutex_unlock(&ts->mutex);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume);
+
+static struct spi_driver tsc2005_driver = {
+	.driver	= {
+		.name	= "tsc2005",
+		.owner	= THIS_MODULE,
+		.pm	= &tsc2005_pm_ops,
+	},
+	.probe	= tsc2005_probe,
+	.remove	= __devexit_p(tsc2005_remove),
+};
+
+module_spi_driver(tsc2005_driver);
+
+MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
+MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc2007.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc2007.c
new file mode 100644
index 0000000..1473d23
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc2007.c
@@ -0,0 +1,406 @@
+/*
+ * drivers/input/touchscreen/tsc2007.c
+ *
+ * Copyright (c) 2008 MtekVision Co., Ltd.
+ *	Kwangwoo Lee <kwlee@mtekvision.com>
+ *
+ * Using code from:
+ *  - ads7846.c
+ *	Copyright (c) 2005 David Brownell
+ *	Copyright (c) 2006 Nokia Corporation
+ *  - corgi_ts.c
+ *	Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *	Copyright (C) 2002 MontaVista Software
+ *	Copyright (C) 2004 Texas Instruments
+ *	Copyright (C) 2005 Dirk Behme
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/i2c/tsc2007.h>
+
+#define TSC2007_MEASURE_TEMP0		(0x0 << 4)
+#define TSC2007_MEASURE_AUX		(0x2 << 4)
+#define TSC2007_MEASURE_TEMP1		(0x4 << 4)
+#define TSC2007_ACTIVATE_XN		(0x8 << 4)
+#define TSC2007_ACTIVATE_YN		(0x9 << 4)
+#define TSC2007_ACTIVATE_YP_XN		(0xa << 4)
+#define TSC2007_SETUP			(0xb << 4)
+#define TSC2007_MEASURE_X		(0xc << 4)
+#define TSC2007_MEASURE_Y		(0xd << 4)
+#define TSC2007_MEASURE_Z1		(0xe << 4)
+#define TSC2007_MEASURE_Z2		(0xf << 4)
+
+#define TSC2007_POWER_OFF_IRQ_EN	(0x0 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS0		(0x1 << 2)
+#define TSC2007_ADC_OFF_IRQ_EN		(0x2 << 2)
+#define TSC2007_ADC_ON_IRQ_DIS1		(0x3 << 2)
+
+#define TSC2007_12BIT			(0x0 << 1)
+#define TSC2007_8BIT			(0x1 << 1)
+
+#define	MAX_12BIT			((1 << 12) - 1)
+
+#define ADC_ON_12BIT	(TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
+
+#define READ_Y		(ADC_ON_12BIT | TSC2007_MEASURE_Y)
+#define READ_Z1		(ADC_ON_12BIT | TSC2007_MEASURE_Z1)
+#define READ_Z2		(ADC_ON_12BIT | TSC2007_MEASURE_Z2)
+#define READ_X		(ADC_ON_12BIT | TSC2007_MEASURE_X)
+#define PWRDOWN		(TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
+
+struct ts_event {
+	u16	x;
+	u16	y;
+	u16	z1, z2;
+};
+
+struct tsc2007 {
+	struct input_dev	*input;
+	char			phys[32];
+
+	struct i2c_client	*client;
+
+	u16			model;
+	u16			x_plate_ohms;
+	u16			max_rt;
+	unsigned long		poll_delay;
+	unsigned long		poll_period;
+
+	int			irq;
+
+	wait_queue_head_t	wait;
+	bool			stopped;
+
+	int			(*get_pendown_state)(void);
+	void			(*clear_penirq)(void);
+};
+
+static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
+{
+	s32 data;
+	u16 val;
+
+	data = i2c_smbus_read_word_data(tsc->client, cmd);
+	if (data < 0) {
+		dev_err(&tsc->client->dev, "i2c io error: %d\n", data);
+		return data;
+	}
+
+	/* The protocol and raw data format from i2c interface:
+	 * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
+	 * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit].
+	 */
+	val = swab16(data) >> 4;
+
+	dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val);
+
+	return val;
+}
+
+static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
+{
+	/* y- still on; turn on only y+ (and ADC) */
+	tc->y = tsc2007_xfer(tsc, READ_Y);
+
+	/* turn y- off, x+ on, then leave in lowpower */
+	tc->x = tsc2007_xfer(tsc, READ_X);
+
+	/* turn y+ off, x- on; we'll use formula #1 */
+	tc->z1 = tsc2007_xfer(tsc, READ_Z1);
+	tc->z2 = tsc2007_xfer(tsc, READ_Z2);
+
+	/* Prepare for next touch reading - power down ADC, enable PENIRQ */
+	tsc2007_xfer(tsc, PWRDOWN);
+}
+
+static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
+{
+	u32 rt = 0;
+
+	/* range filtering */
+	if (tc->x == MAX_12BIT)
+		tc->x = 0;
+
+	if (likely(tc->x && tc->z1)) {
+		/* compute touch pressure resistance using equation #1 */
+		rt = tc->z2 - tc->z1;
+		rt *= tc->x;
+		rt *= tsc->x_plate_ohms;
+		rt /= tc->z1;
+		rt = (rt + 2047) >> 12;
+	}
+
+	return rt;
+}
+
+static bool tsc2007_is_pen_down(struct tsc2007 *ts)
+{
+	/*
+	 * NOTE: We can't rely on the pressure to determine the pen down
+	 * state, even though this controller has a pressure sensor.
+	 * The pressure value can fluctuate for quite a while after
+	 * lifting the pen and in some cases may not even settle at the
+	 * expected value.
+	 *
+	 * The only safe way to check for the pen up condition is in the
+	 * work function by reading the pen signal state (it's a GPIO
+	 * and IRQ). Unfortunately such callback is not always available,
+	 * in that case we assume that the pen is down and expect caller
+	 * to fall back on the pressure reading.
+	 */
+
+	if (!ts->get_pendown_state)
+		return true;
+
+	return ts->get_pendown_state();
+}
+
+static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
+{
+	struct tsc2007 *ts = handle;
+	struct input_dev *input = ts->input;
+	struct ts_event tc;
+	u32 rt;
+
+	while (!ts->stopped && tsc2007_is_pen_down(ts)) {
+
+		/* pen is down, continue with the measurement */
+		tsc2007_read_values(ts, &tc);
+
+		rt = tsc2007_calculate_pressure(ts, &tc);
+
+		if (rt == 0 && !ts->get_pendown_state) {
+			/*
+			 * If pressure reported is 0 and we don't have
+			 * callback to check pendown state, we have to
+			 * assume that pen was lifted up.
+			 */
+			break;
+		}
+
+		if (rt <= ts->max_rt) {
+			dev_dbg(&ts->client->dev,
+				"DOWN point(%4d,%4d), pressure (%4u)\n",
+				tc.x, tc.y, rt);
+
+			input_report_key(input, BTN_TOUCH, 1);
+			input_report_abs(input, ABS_X, tc.x);
+			input_report_abs(input, ABS_Y, tc.y);
+			input_report_abs(input, ABS_PRESSURE, rt);
+
+			input_sync(input);
+
+		} else {
+			/*
+			 * Sample found inconsistent by debouncing or pressure is
+			 * beyond the maximum. Don't report it to user space,
+			 * repeat at least once more the measurement.
+			 */
+			dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
+		}
+
+		wait_event_timeout(ts->wait, ts->stopped,
+				   msecs_to_jiffies(ts->poll_period));
+	}
+
+	dev_dbg(&ts->client->dev, "UP\n");
+
+	input_report_key(input, BTN_TOUCH, 0);
+	input_report_abs(input, ABS_PRESSURE, 0);
+	input_sync(input);
+
+	if (ts->clear_penirq)
+		ts->clear_penirq();
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
+{
+	struct tsc2007 *ts = handle;
+
+	if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
+		return IRQ_WAKE_THREAD;
+
+	if (ts->clear_penirq)
+		ts->clear_penirq();
+
+	return IRQ_HANDLED;
+}
+
+static void tsc2007_stop(struct tsc2007 *ts)
+{
+	ts->stopped = true;
+	mb();
+	wake_up(&ts->wait);
+
+	disable_irq(ts->irq);
+}
+
+static int tsc2007_open(struct input_dev *input_dev)
+{
+	struct tsc2007 *ts = input_get_drvdata(input_dev);
+	int err;
+
+	ts->stopped = false;
+	mb();
+
+	enable_irq(ts->irq);
+
+	/* Prepare for touch readings - power down ADC and enable PENIRQ */
+	err = tsc2007_xfer(ts, PWRDOWN);
+	if (err < 0) {
+		tsc2007_stop(ts);
+		return err;
+	}
+
+	return 0;
+}
+
+static void tsc2007_close(struct input_dev *input_dev)
+{
+	struct tsc2007 *ts = input_get_drvdata(input_dev);
+
+	tsc2007_stop(ts);
+}
+
+static int __devinit tsc2007_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	struct tsc2007 *ts;
+	struct tsc2007_platform_data *pdata = client->dev.platform_data;
+	struct input_dev *input_dev;
+	int err;
+
+	if (!pdata) {
+		dev_err(&client->dev, "platform data is required!\n");
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EIO;
+
+	ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->client = client;
+	ts->irq = client->irq;
+	ts->input = input_dev;
+	init_waitqueue_head(&ts->wait);
+
+	ts->model             = pdata->model;
+	ts->x_plate_ohms      = pdata->x_plate_ohms;
+	ts->max_rt            = pdata->max_rt ? : MAX_12BIT;
+	ts->poll_delay        = pdata->poll_delay ? : 1;
+	ts->poll_period       = pdata->poll_period ? : 1;
+	ts->get_pendown_state = pdata->get_pendown_state;
+	ts->clear_penirq      = pdata->clear_penirq;
+
+	if (pdata->x_plate_ohms == 0) {
+		dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
+		err = -EINVAL;
+		goto err_free_mem;
+	}
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input0", dev_name(&client->dev));
+
+	input_dev->name = "TSC2007 Touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_I2C;
+
+	input_dev->open = tsc2007_open;
+	input_dev->close = tsc2007_close;
+
+	input_set_drvdata(input_dev, ts);
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
+			pdata->fuzzz, 0);
+
+	if (pdata->init_platform_hw)
+		pdata->init_platform_hw();
+
+	err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq,
+				   IRQF_ONESHOT, client->dev.driver->name, ts);
+	if (err < 0) {
+		dev_err(&client->dev, "irq %d busy?\n", ts->irq);
+		goto err_free_mem;
+	}
+
+	tsc2007_stop(ts);
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+
+ err_free_irq:
+	free_irq(ts->irq, ts);
+	if (pdata->exit_platform_hw)
+		pdata->exit_platform_hw();
+ err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	return err;
+}
+
+static int __devexit tsc2007_remove(struct i2c_client *client)
+{
+	struct tsc2007	*ts = i2c_get_clientdata(client);
+	struct tsc2007_platform_data *pdata = client->dev.platform_data;
+
+	free_irq(ts->irq, ts);
+
+	if (pdata->exit_platform_hw)
+		pdata->exit_platform_hw();
+
+	input_unregister_device(ts->input);
+	kfree(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id tsc2007_idtable[] = {
+	{ "tsc2007", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
+
+static struct i2c_driver tsc2007_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "tsc2007"
+	},
+	.id_table	= tsc2007_idtable,
+	.probe		= tsc2007_probe,
+	.remove		= __devexit_p(tsc2007_remove),
+};
+
+module_i2c_driver(tsc2007_driver);
+
+MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");
+MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc40.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc40.c
new file mode 100644
index 0000000..80d4610
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/tsc40.c
@@ -0,0 +1,183 @@
+/*
+ * TSC-40 serial touchscreen driver. It should be compatible with
+ * TSC-10 and 25.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ * License: GPLv2 as published by the FSF.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define PACKET_LENGTH  5
+struct tsc_ser {
+	struct input_dev *dev;
+	struct serio *serio;
+	u32 idx;
+	unsigned char data[PACKET_LENGTH];
+	char phys[32];
+};
+
+static void tsc_process_data(struct tsc_ser *ptsc)
+{
+	struct input_dev *dev = ptsc->dev;
+	u8 *data = ptsc->data;
+	u32 x;
+	u32 y;
+
+	x = ((data[1] & 0x03) << 8) | data[2];
+	y = ((data[3] & 0x03) << 8) | data[4];
+
+	input_report_abs(dev, ABS_X, x);
+	input_report_abs(dev, ABS_Y, y);
+	input_report_key(dev, BTN_TOUCH, 1);
+
+	input_sync(dev);
+}
+
+static irqreturn_t tsc_interrupt(struct serio *serio,
+		unsigned char data, unsigned int flags)
+{
+	struct tsc_ser *ptsc = serio_get_drvdata(serio);
+	struct input_dev *dev = ptsc->dev;
+
+	ptsc->data[ptsc->idx] = data;
+	switch (ptsc->idx++) {
+	case 0:
+		if (unlikely((data & 0x3e) != 0x10)) {
+			dev_dbg(&serio->dev,
+				"unsynchronized packet start (0x%02x)\n", data);
+			ptsc->idx = 0;
+		} else if (!(data & 0x01)) {
+			input_report_key(dev, BTN_TOUCH, 0);
+			input_sync(dev);
+			ptsc->idx = 0;
+		}
+		break;
+
+	case 1:
+	case 3:
+		if (unlikely(data & 0xfc)) {
+			dev_dbg(&serio->dev,
+				"unsynchronized data 0x%02x at offset %d\n",
+				data, ptsc->idx - 1);
+			ptsc->idx = 0;
+		}
+		break;
+
+	case 4:
+		tsc_process_data(ptsc);
+		ptsc->idx = 0;
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int tsc_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct tsc_ser *ptsc;
+	struct input_dev *input_dev;
+	int error;
+
+	ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ptsc || !input_dev) {
+		error = -ENOMEM;
+		goto fail1;
+	}
+
+	ptsc->serio = serio;
+	ptsc->dev = input_dev;
+	snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
+
+	input_dev->name = "TSC-10/25/40 Serial TouchScreen";
+	input_dev->phys = ptsc->phys;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = SERIO_TSC40;
+	input_dev->id.product = 40;
+	input_dev->id.version = 0x0001;
+	input_dev->dev.parent = &serio->dev;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
+	input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
+
+	serio_set_drvdata(serio, ptsc);
+
+	error = serio_open(serio, drv);
+	if (error)
+		goto fail2;
+
+	error = input_register_device(ptsc->dev);
+	if (error)
+		goto fail3;
+
+	return 0;
+
+fail3:
+	serio_close(serio);
+fail2:
+	serio_set_drvdata(serio, NULL);
+fail1:
+	input_free_device(input_dev);
+	kfree(ptsc);
+	return error;
+}
+
+static void tsc_disconnect(struct serio *serio)
+{
+	struct tsc_ser *ptsc = serio_get_drvdata(serio);
+
+	serio_close(serio);
+
+	input_unregister_device(ptsc->dev);
+	kfree(ptsc);
+
+	serio_set_drvdata(serio, NULL);
+}
+
+static struct serio_device_id tsc_serio_ids[] = {
+	{
+		.type   = SERIO_RS232,
+		.proto  = SERIO_TSC40,
+		.id     = SERIO_ANY,
+		.extra  = SERIO_ANY,
+	},
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
+
+#define DRIVER_DESC    "TSC-10/25/40 serial touchscreen driver"
+
+static struct serio_driver tsc_drv = {
+	.driver	= {
+		.name   = "tsc40",
+	},
+	.description    = DRIVER_DESC,
+	.id_table	= tsc_serio_ids,
+	.interrupt      = tsc_interrupt,
+	.connect	= tsc_connect,
+	.disconnect     = tsc_disconnect,
+};
+
+static int __init tsc_ser_init(void)
+{
+	return serio_register_driver(&tsc_drv);
+}
+module_init(tsc_ser_init);
+
+static void __exit tsc_exit(void)
+{
+	serio_unregister_driver(&tsc_drv);
+}
+module_exit(tsc_exit);
+
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ucb1400_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ucb1400_ts.c
new file mode 100644
index 0000000..46e83ad
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/ucb1400_ts.c
@@ -0,0 +1,467 @@
+/*
+ *  Philips UCB1400 touchscreen driver
+ *
+ *  Author:	Nicolas Pitre
+ *  Created:	September 25, 2006
+ *  Copyright:	MontaVista Software, Inc.
+ *
+ * Spliting done by: Marek Vasut <marek.vasut@gmail.com>
+ * If something doesn't work and it worked before spliting, e-mail me,
+ * dont bother Nicolas please ;-)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This code is heavily based on ucb1x00-*.c copyrighted by Russell King
+ * covering the UCB1100, UCB1200 and UCB1300..  Support for the UCB1400 has
+ * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/ucb1400.h>
+
+#define UCB1400_TS_POLL_PERIOD	10 /* ms */
+
+static bool adcsync;
+static int ts_delay = 55; /* us */
+static int ts_delay_pressure;	/* us */
+
+/* Switch to interrupt mode. */
+static void ucb1400_ts_mode_int(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+			UCB_TS_CR_MODE_INT);
+}
+
+/*
+ * Switch to pressure mode, and read pressure.  We don't need to wait
+ * here, since both plates are being driven.
+ */
+static unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+
+	udelay(ts_delay_pressure);
+
+	return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
+}
+
+/*
+ * Switch to X position mode and measure Y plate.  We switch the plate
+ * configuration in pressure mode, then switch to position mode.  This
+ * gives a faster response time.  Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+
+	udelay(ts_delay);
+
+	return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
+}
+
+/*
+ * Switch to Y position mode and measure X plate.  We switch the plate
+ * configuration in pressure mode, then switch to position mode.  This
+ * gives a faster response time.  Even so, we need to wait about 55us
+ * for things to stabilise.
+ */
+static int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+
+	udelay(ts_delay);
+
+	return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPX, adcsync);
+}
+
+/*
+ * Switch to X plate resistance mode.  Set MX to ground, PX to
+ * supply.  Measure current.
+ */
+static unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+	return ucb1400_adc_read(ucb->ac97, 0, adcsync);
+}
+
+/*
+ * Switch to Y plate resistance mode.  Set MY to ground, PY to
+ * supply.  Measure current.
+ */
+static unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
+			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+	return ucb1400_adc_read(ucb->ac97, 0, adcsync);
+}
+
+static int ucb1400_ts_pen_up(struct ucb1400_ts *ucb)
+{
+	unsigned short val = ucb1400_reg_read(ucb->ac97, UCB_TS_CR);
+
+	return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
+}
+
+static void ucb1400_ts_irq_enable(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, UCB_IE_TSPX);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_TSPX);
+}
+
+static void ucb1400_ts_irq_disable(struct ucb1400_ts *ucb)
+{
+	ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0);
+}
+
+static void ucb1400_ts_report_event(struct input_dev *idev, u16 pressure, u16 x, u16 y)
+{
+	input_report_abs(idev, ABS_X, x);
+	input_report_abs(idev, ABS_Y, y);
+	input_report_abs(idev, ABS_PRESSURE, pressure);
+	input_report_key(idev, BTN_TOUCH, 1);
+	input_sync(idev);
+}
+
+static void ucb1400_ts_event_release(struct input_dev *idev)
+{
+	input_report_abs(idev, ABS_PRESSURE, 0);
+	input_report_key(idev, BTN_TOUCH, 0);
+	input_sync(idev);
+}
+
+static void ucb1400_clear_pending_irq(struct ucb1400_ts *ucb)
+{
+	unsigned int isr;
+
+	isr = ucb1400_reg_read(ucb->ac97, UCB_IE_STATUS);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, isr);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
+
+	if (isr & UCB_IE_TSPX)
+		ucb1400_ts_irq_disable(ucb);
+	else
+		dev_dbg(&ucb->ts_idev->dev,
+			"ucb1400: unexpected IE_STATUS = %#x\n", isr);
+}
+
+/*
+ * A restriction with interrupts exists when using the ucb1400, as
+ * the codec read/write routines may sleep while waiting for codec
+ * access completion and uses semaphores for access control to the
+ * AC97 bus. Therefore the driver is forced to use threaded interrupt
+ * handler.
+ */
+static irqreturn_t ucb1400_irq(int irqnr, void *devid)
+{
+	struct ucb1400_ts *ucb = devid;
+	unsigned int x, y, p;
+	bool penup;
+
+	if (unlikely(irqnr != ucb->irq))
+		return IRQ_NONE;
+
+	ucb1400_clear_pending_irq(ucb);
+
+	/* Start with a small delay before checking pendown state */
+	msleep(UCB1400_TS_POLL_PERIOD);
+
+	while (!ucb->stopped && !(penup = ucb1400_ts_pen_up(ucb))) {
+
+		ucb1400_adc_enable(ucb->ac97);
+		x = ucb1400_ts_read_xpos(ucb);
+		y = ucb1400_ts_read_ypos(ucb);
+		p = ucb1400_ts_read_pressure(ucb);
+		ucb1400_adc_disable(ucb->ac97);
+
+		ucb1400_ts_report_event(ucb->ts_idev, p, x, y);
+
+		wait_event_timeout(ucb->ts_wait, ucb->stopped,
+				   msecs_to_jiffies(UCB1400_TS_POLL_PERIOD));
+	}
+
+	ucb1400_ts_event_release(ucb->ts_idev);
+
+	if (!ucb->stopped) {
+		/* Switch back to interrupt mode. */
+		ucb1400_ts_mode_int(ucb);
+		ucb1400_ts_irq_enable(ucb);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void ucb1400_ts_stop(struct ucb1400_ts *ucb)
+{
+	/* Signal IRQ thread to stop polling and disable the handler. */
+	ucb->stopped = true;
+	mb();
+	wake_up(&ucb->ts_wait);
+	disable_irq(ucb->irq);
+
+	ucb1400_ts_irq_disable(ucb);
+	ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0);
+}
+
+/* Must be called with ts->lock held */
+static void ucb1400_ts_start(struct ucb1400_ts *ucb)
+{
+	/* Tell IRQ thread that it may poll the device. */
+	ucb->stopped = false;
+	mb();
+
+	ucb1400_ts_mode_int(ucb);
+	ucb1400_ts_irq_enable(ucb);
+
+	enable_irq(ucb->irq);
+}
+
+static int ucb1400_ts_open(struct input_dev *idev)
+{
+	struct ucb1400_ts *ucb = input_get_drvdata(idev);
+
+	ucb1400_ts_start(ucb);
+
+	return 0;
+}
+
+static void ucb1400_ts_close(struct input_dev *idev)
+{
+	struct ucb1400_ts *ucb = input_get_drvdata(idev);
+
+	ucb1400_ts_stop(ucb);
+}
+
+#ifndef NO_IRQ
+#define NO_IRQ	0
+#endif
+
+/*
+ * Try to probe our interrupt, rather than relying on lots of
+ * hard-coded machine dependencies.
+ */
+static int __devinit ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,
+					   struct platform_device *pdev)
+{
+	unsigned long mask, timeout;
+
+	mask = probe_irq_on();
+
+	/* Enable the ADC interrupt. */
+	ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, UCB_IE_ADC);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_ADC);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
+
+	/* Cause an ADC interrupt. */
+	ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA);
+	ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
+
+	/* Wait for the conversion to complete. */
+	timeout = jiffies + HZ/2;
+	while (!(ucb1400_reg_read(ucb->ac97, UCB_ADC_DATA) &
+						UCB_ADC_DAT_VALID)) {
+		cpu_relax();
+		if (time_after(jiffies, timeout)) {
+			dev_err(&pdev->dev, "timed out in IRQ probe\n");
+			probe_irq_off(mask);
+			return -ENODEV;
+		}
+	}
+	ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, 0);
+
+	/* Disable and clear interrupt. */
+	ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, 0);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff);
+	ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
+
+	/* Read triggered interrupt. */
+	ucb->irq = probe_irq_off(mask);
+	if (ucb->irq < 0 || ucb->irq == NO_IRQ)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int __devinit ucb1400_ts_probe(struct platform_device *pdev)
+{
+	struct ucb1400_ts *ucb = pdev->dev.platform_data;
+	int error, x_res, y_res;
+	u16 fcsr;
+
+	ucb->ts_idev = input_allocate_device();
+	if (!ucb->ts_idev) {
+		error = -ENOMEM;
+		goto err;
+	}
+
+	/* Only in case the IRQ line wasn't supplied, try detecting it */
+	if (ucb->irq < 0) {
+		error = ucb1400_ts_detect_irq(ucb, pdev);
+		if (error) {
+			dev_err(&pdev->dev, "IRQ probe failed\n");
+			goto err_free_devs;
+		}
+	}
+	dev_dbg(&pdev->dev, "found IRQ %d\n", ucb->irq);
+
+	init_waitqueue_head(&ucb->ts_wait);
+
+	input_set_drvdata(ucb->ts_idev, ucb);
+
+	ucb->ts_idev->dev.parent	= &pdev->dev;
+	ucb->ts_idev->name		= "UCB1400 touchscreen interface";
+	ucb->ts_idev->id.vendor		= ucb1400_reg_read(ucb->ac97,
+						AC97_VENDOR_ID1);
+	ucb->ts_idev->id.product	= ucb->id;
+	ucb->ts_idev->open		= ucb1400_ts_open;
+	ucb->ts_idev->close		= ucb1400_ts_close;
+	ucb->ts_idev->evbit[0]		= BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
+	ucb->ts_idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	/*
+	 * Enable ADC filter to prevent horrible jitter on Colibri.
+	 * This also further reduces jitter on boards where ADCSYNC
+	 * pin is connected.
+	 */
+	fcsr = ucb1400_reg_read(ucb->ac97, UCB_FCSR);
+	ucb1400_reg_write(ucb->ac97, UCB_FCSR, fcsr | UCB_FCSR_AVE);
+
+	ucb1400_adc_enable(ucb->ac97);
+	x_res = ucb1400_ts_read_xres(ucb);
+	y_res = ucb1400_ts_read_yres(ucb);
+	ucb1400_adc_disable(ucb->ac97);
+	dev_dbg(&pdev->dev, "x/y = %d/%d\n", x_res, y_res);
+
+	input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0);
+	input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0);
+	input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0);
+
+	ucb1400_ts_stop(ucb);
+
+	error = request_threaded_irq(ucb->irq, NULL, ucb1400_irq,
+				     IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				     "UCB1400", ucb);
+	if (error) {
+		dev_err(&pdev->dev,
+			"unable to grab irq%d: %d\n", ucb->irq, error);
+		goto err_free_devs;
+	}
+
+	error = input_register_device(ucb->ts_idev);
+	if (error)
+		goto err_free_irq;
+
+	return 0;
+
+err_free_irq:
+	free_irq(ucb->irq, ucb);
+err_free_devs:
+	input_free_device(ucb->ts_idev);
+err:
+	return error;
+}
+
+static int __devexit ucb1400_ts_remove(struct platform_device *pdev)
+{
+	struct ucb1400_ts *ucb = pdev->dev.platform_data;
+
+	free_irq(ucb->irq, ucb);
+	input_unregister_device(ucb->ts_idev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ucb1400_ts_suspend(struct device *dev)
+{
+	struct ucb1400_ts *ucb = dev->platform_data;
+	struct input_dev *idev = ucb->ts_idev;
+
+	mutex_lock(&idev->mutex);
+
+	if (idev->users)
+		ucb1400_ts_start(ucb);
+
+	mutex_unlock(&idev->mutex);
+	return 0;
+}
+
+static int ucb1400_ts_resume(struct device *dev)
+{
+	struct ucb1400_ts *ucb = dev->platform_data;
+	struct input_dev *idev = ucb->ts_idev;
+
+	mutex_lock(&idev->mutex);
+
+	if (idev->users)
+		ucb1400_ts_stop(ucb);
+
+	mutex_unlock(&idev->mutex);
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops,
+			 ucb1400_ts_suspend, ucb1400_ts_resume);
+
+static struct platform_driver ucb1400_ts_driver = {
+	.probe	= ucb1400_ts_probe,
+	.remove	= __devexit_p(ucb1400_ts_remove),
+	.driver	= {
+		.name	= "ucb1400_ts",
+		.owner	= THIS_MODULE,
+		.pm	= &ucb1400_ts_pm_ops,
+	},
+};
+module_platform_driver(ucb1400_ts_driver);
+
+module_param(adcsync, bool, 0444);
+MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
+
+module_param(ts_delay, int, 0444);
+MODULE_PARM_DESC(ts_delay, "Delay between panel setup and"
+			    " position read. Default = 55us.");
+
+module_param(ts_delay_pressure, int, 0444);
+MODULE_PARM_DESC(ts_delay_pressure,
+		"delay between panel setup and pressure read."
+		"  Default = 0us.");
+
+MODULE_DESCRIPTION("Philips UCB1400 touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/usbtouchscreen.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/usbtouchscreen.c
new file mode 100644
index 0000000..ce384a4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/usbtouchscreen.c
@@ -0,0 +1,1704 @@
+/******************************************************************************
+ * usbtouchscreen.c
+ * Driver for USB Touchscreens, supporting those devices:
+ *  - eGalax Touchkit
+ *    includes eTurboTouch CT-410/510/700
+ *  - 3M/Microtouch  EX II series
+ *  - ITM
+ *  - PanJit TouchSet
+ *  - eTurboTouch
+ *  - Gunze AHL61
+ *  - DMC TSC-10/25
+ *  - IRTOUCHSYSTEMS/UNITOP
+ *  - IdealTEK URTC1000
+ *  - General Touch
+ *  - GoTop Super_Q2/GogoPen/PenPower tablets
+ *  - JASTEC USB touch controller/DigiTech DTR-02U
+ *  - Zytronic capacitive touchscreen
+ *  - NEXIO/iNexio
+ *  - Elo TouchSystems 2700 IntelliTouch
+ *  - EasyTouch USB Dual/Multi touch controller from Data Modul
+ *
+ * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
+ * Copyright (C) by Todd E. Johnson (mtouchusb.c)
+ *
+ * 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.
+ *
+ * Driver is based on touchkitusb.c
+ * - ITM parts are from itmtouch.c
+ * - 3M parts are from mtouchusb.c
+ * - PanJit parts are from an unmerged driver by Lanslott Gish
+ * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged
+ *   driver from Marius Vollmer
+ *
+ *****************************************************************************/
+
+//#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <linux/hid.h>
+
+
+#define DRIVER_VERSION		"v0.6"
+#define DRIVER_AUTHOR		"Daniel Ritz <daniel.ritz@gmx.ch>"
+#define DRIVER_DESC		"USB Touchscreen Driver"
+
+static bool swap_xy;
+module_param(swap_xy, bool, 0644);
+MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
+
+static bool hwcalib_xy;
+module_param(hwcalib_xy, bool, 0644);
+MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available");
+
+/* device specifc data/functions */
+struct usbtouch_usb;
+struct usbtouch_device_info {
+	int min_xc, max_xc;
+	int min_yc, max_yc;
+	int min_press, max_press;
+	int rept_size;
+
+	/*
+	 * Always service the USB devices irq not just when the input device is
+	 * open. This is useful when devices have a watchdog which prevents us
+	 * from periodically polling the device. Leave this unset unless your
+	 * touchscreen device requires it, as it does consume more of the USB
+	 * bandwidth.
+	 */
+	bool irq_always;
+
+	void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
+
+	/*
+	 * used to get the packet len. possible return values:
+	 * > 0: packet len
+	 * = 0: skip one byte
+	 * < 0: -return value more bytes needed
+	 */
+	int  (*get_pkt_len) (unsigned char *pkt, int len);
+
+	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
+	int  (*alloc)       (struct usbtouch_usb *usbtouch);
+	int  (*init)        (struct usbtouch_usb *usbtouch);
+	void (*exit)	    (struct usbtouch_usb *usbtouch);
+};
+
+/* a usbtouch device */
+struct usbtouch_usb {
+	unsigned char *data;
+	dma_addr_t data_dma;
+	int data_size;
+	unsigned char *buffer;
+	int buf_len;
+	struct urb *irq;
+	struct usb_interface *interface;
+	struct input_dev *input;
+	struct usbtouch_device_info *type;
+	char name[128];
+	char phys[64];
+	void *priv;
+
+	int x, y;
+	int touch, press;
+};
+
+
+/* device types */
+enum {
+	DEVTYPE_IGNORE = -1,
+	DEVTYPE_EGALAX,
+	DEVTYPE_PANJIT,
+	DEVTYPE_3M,
+	DEVTYPE_ITM,
+	DEVTYPE_ETURBO,
+	DEVTYPE_GUNZE,
+	DEVTYPE_DMC_TSC10,
+	DEVTYPE_IRTOUCH,
+	DEVTYPE_IDEALTEK,
+	DEVTYPE_GENERAL_TOUCH,
+	DEVTYPE_GOTOP,
+	DEVTYPE_JASTEC,
+	DEVTYPE_E2I,
+	DEVTYPE_ZYTRONIC,
+	DEVTYPE_TC45USB,
+	DEVTYPE_NEXIO,
+	DEVTYPE_ELO,
+	DEVTYPE_ETOUCH,
+};
+
+#define USB_DEVICE_HID_CLASS(vend, prod) \
+	.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
+		| USB_DEVICE_ID_MATCH_INT_PROTOCOL \
+		| USB_DEVICE_ID_MATCH_DEVICE, \
+	.idVendor = (vend), \
+	.idProduct = (prod), \
+	.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
+	.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
+
+static const struct usb_device_id usbtouch_devices[] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
+	/* ignore the HID capable devices, handled by usbhid */
+	{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
+	{USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
+
+	/* normal device IDs */
+	{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
+	{USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
+	{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
+	{USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
+	{USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
+	{USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
+	{USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
+	{USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
+	{USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
+	{USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
+	{USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_3M
+	{USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ITM
+	{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
+	{USB_DEVICE(0x16e3, 0xf9e9), .driver_info = DEVTYPE_ITM},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
+	{USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
+	{USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
+	{USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+	{USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
+	{USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+	{USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+	{USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+	{USB_DEVICE(0x08f2, 0x007f), .driver_info = DEVTYPE_GOTOP},
+	{USB_DEVICE(0x08f2, 0x00ce), .driver_info = DEVTYPE_GOTOP},
+	{USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+	{USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+	{USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+	{USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+	/* TC5UH */
+	{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC45USB},
+	/* TC4UM */
+	{USB_DEVICE(0x0664, 0x0306), .driver_info = DEVTYPE_TC45USB},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+	/* data interface only */
+	{USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
+		.driver_info = DEVTYPE_NEXIO},
+	{USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
+		.driver_info = DEVTYPE_NEXIO},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ELO
+	{USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+	{USB_DEVICE(0x7374, 0x0001), .driver_info = DEVTYPE_ETOUCH},
+#endif
+
+	{}
+};
+
+
+/*****************************************************************************
+ * e2i Part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+static int e2i_init(struct usbtouch_usb *usbtouch)
+{
+	int ret;
+	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+	                      0x01, 0x02, 0x0000, 0x0081,
+	                      NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+	dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
+	    __func__, ret);
+	return ret;
+}
+
+static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	int tmp = (pkt[0] << 8) | pkt[1];
+	dev->x  = (pkt[2] << 8) | pkt[3];
+	dev->y  = (pkt[4] << 8) | pkt[5];
+
+	tmp = tmp - 0xA000;
+	dev->touch = (tmp > 0);
+	dev->press = (tmp > 0 ? tmp : 0);
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * eGalax part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
+
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
+
+#define EGALAX_PKT_TYPE_MASK		0xFE
+#define EGALAX_PKT_TYPE_REPT		0x80
+#define EGALAX_PKT_TYPE_DIAG		0x0A
+
+static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
+		return 0;
+
+	dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
+	dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+
+static int egalax_get_pkt_len(unsigned char *buf, int len)
+{
+	switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
+	case EGALAX_PKT_TYPE_REPT:
+		return 5;
+
+	case EGALAX_PKT_TYPE_DIAG:
+		if (len < 2)
+			return -1;
+
+		return buf[1] + 2;
+	}
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * EasyTouch part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
+
+#define ETOUCH_PKT_TYPE_MASK		0xFE
+#define ETOUCH_PKT_TYPE_REPT		0x80
+#define ETOUCH_PKT_TYPE_REPT2		0xB0
+#define ETOUCH_PKT_TYPE_DIAG		0x0A
+
+static int etouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	if ((pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT &&
+		(pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT2)
+		return 0;
+
+	dev->x = ((pkt[1] & 0x1F) << 7) | (pkt[2] & 0x7F);
+	dev->y = ((pkt[3] & 0x1F) << 7) | (pkt[4] & 0x7F);
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+
+static int etouch_get_pkt_len(unsigned char *buf, int len)
+{
+	switch (buf[0] & ETOUCH_PKT_TYPE_MASK) {
+	case ETOUCH_PKT_TYPE_REPT:
+	case ETOUCH_PKT_TYPE_REPT2:
+		return 5;
+
+	case ETOUCH_PKT_TYPE_DIAG:
+		if (len < 2)
+			return -1;
+
+		return buf[1] + 2;
+	}
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * PanJit Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
+static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
+	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * 3M/Microtouch Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_3M
+
+#define MTOUCHUSB_ASYNC_REPORT          1
+#define MTOUCHUSB_RESET                 7
+#define MTOUCHUSB_REQ_CTRLLR_ID         10
+
+static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	if (hwcalib_xy) {
+		dev->x = (pkt[4] << 8) | pkt[3];
+		dev->y = 0xffff - ((pkt[6] << 8) | pkt[5]);
+	} else {
+		dev->x = (pkt[8] << 8) | pkt[7];
+		dev->y = (pkt[10] << 8) | pkt[9];
+	}
+	dev->touch = (pkt[2] & 0x40) ? 1 : 0;
+
+	return 1;
+}
+
+static int mtouch_init(struct usbtouch_usb *usbtouch)
+{
+	int ret, i;
+	struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+	                      MTOUCHUSB_RESET,
+	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+	dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
+	    __func__, ret);
+	if (ret < 0)
+		return ret;
+	msleep(150);
+
+	for (i = 0; i < 3; i++) {
+		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				      MTOUCHUSB_ASYNC_REPORT,
+				      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+				      1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
+		dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
+		    __func__, ret);
+		if (ret >= 0)
+			break;
+		if (ret != -EPIPE)
+			return ret;
+	}
+
+	/* Default min/max xy are the raw values, override if using hw-calib */
+	if (hwcalib_xy) {
+		input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);
+		input_set_abs_params(usbtouch->input, ABS_Y, 0, 0xffff, 0, 0);
+	}
+
+	return 0;
+}
+#endif
+
+
+/*****************************************************************************
+ * ITM Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_ITM
+static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	int touch;
+	/*
+	 * ITM devices report invalid x/y data if not touched.
+	 * if the screen was touched before but is not touched any more
+	 * report touch as 0 with the last valid x/y data once. then stop
+	 * reporting data until touched again.
+	 */
+	dev->press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
+
+	touch = ~pkt[7] & 0x20;
+	if (!touch) {
+		if (dev->touch) {
+			dev->touch = 0;
+			return 1;
+		}
+
+		return 0;
+	}
+
+	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
+	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
+	dev->touch = touch;
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * eTurboTouch part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
+static int eturbo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	unsigned int shift;
+
+	/* packets should start with sync */
+	if (!(pkt[0] & 0x80))
+		return 0;
+
+	shift = (6 - (pkt[0] & 0x03));
+	dev->x = ((pkt[3] << 7) | pkt[4]) >> shift;
+	dev->y = ((pkt[1] << 7) | pkt[2]) >> shift;
+	dev->touch = (pkt[0] & 0x10) ? 1 : 0;
+
+	return 1;
+}
+
+static int eturbo_get_pkt_len(unsigned char *buf, int len)
+{
+	if (buf[0] & 0x80)
+		return 5;
+	if (buf[0] == 0x01)
+		return 3;
+	return 0;
+}
+#endif
+
+
+/*****************************************************************************
+ * Gunze part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
+static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
+		return 0;
+
+	dev->x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
+	dev->y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
+	dev->touch = pkt[0] & 0x20;
+
+	return 1;
+}
+#endif
+
+/*****************************************************************************
+ * DMC TSC-10/25 Part
+ *
+ * Documentation about the controller and it's protocol can be found at
+ *   http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf
+ *   http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
+
+/* supported data rates. currently using 130 */
+#define TSC10_RATE_POINT	0x50
+#define TSC10_RATE_30		0x40
+#define TSC10_RATE_50		0x41
+#define TSC10_RATE_80		0x42
+#define TSC10_RATE_100		0x43
+#define TSC10_RATE_130		0x44
+#define TSC10_RATE_150		0x45
+
+/* commands */
+#define TSC10_CMD_RESET		0x55
+#define TSC10_CMD_RATE		0x05
+#define TSC10_CMD_DATA1		0x01
+
+static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
+{
+	struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
+	int ret = -ENOMEM;
+	unsigned char *buf;
+
+	buf = kmalloc(2, GFP_NOIO);
+	if (!buf)
+		goto err_nobuf;
+	/* reset */
+	buf[0] = buf[1] = 0xFF;
+	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+	                      TSC10_CMD_RESET,
+	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+	if (ret < 0)
+		goto err_out;
+	if (buf[0] != 0x06) {
+		ret = -ENODEV;
+		goto err_out;
+	}
+
+	/* set coordinate output rate */
+	buf[0] = buf[1] = 0xFF;
+	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+	                      TSC10_CMD_RATE,
+	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+	if (ret < 0)
+		goto err_out;
+	if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {
+		ret = -ENODEV;
+		goto err_out;
+	}
+
+	/* start sending data */
+	ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
+	                      TSC10_CMD_DATA1,
+	                      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+err_out:
+	kfree(buf);
+err_nobuf:
+	return ret;
+}
+
+
+static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
+	dev->y = ((pkt[4] & 0x03) << 8) | pkt[3];
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * IRTOUCH Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = (pkt[3] << 8) | pkt[2];
+	dev->y = (pkt[5] << 8) | pkt[4];
+	dev->touch = (pkt[1] & 0x03) ? 1 : 0;
+
+	return 1;
+}
+#endif
+
+/*****************************************************************************
+ * ET&T TC5UH/TC4UM part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
+	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+#endif
+
+/*****************************************************************************
+ * IdealTEK URTC1000 Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+#ifndef MULTI_PACKET
+#define MULTI_PACKET
+#endif
+static int idealtek_get_pkt_len(unsigned char *buf, int len)
+{
+	if (buf[0] & 0x80)
+		return 5;
+	if (buf[0] == 0x01)
+		return len;
+	return 0;
+}
+
+static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	switch (pkt[0] & 0x98) {
+	case 0x88:
+		/* touch data in IdealTEK mode */
+		dev->x = (pkt[1] << 5) | (pkt[2] >> 2);
+		dev->y = (pkt[3] << 5) | (pkt[4] >> 2);
+		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
+		return 1;
+
+	case 0x98:
+		/* touch data in MT emulation mode */
+		dev->x = (pkt[2] << 5) | (pkt[1] >> 2);
+		dev->y = (pkt[4] << 5) | (pkt[3] >> 2);
+		dev->touch = (pkt[0] & 0x40) ? 1 : 0;
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+#endif
+
+/*****************************************************************************
+ * General Touch Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = (pkt[2] << 8) | pkt[1];
+	dev->y = (pkt[4] << 8) | pkt[3];
+	dev->press = pkt[5] & 0xff;
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+#endif
+
+/*****************************************************************************
+ * GoTop Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
+	dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
+	dev->touch = pkt[0] & 0x01;
+
+	return 1;
+}
+#endif
+
+/*****************************************************************************
+ * JASTEC Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
+	dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
+	dev->touch = (pkt[0] & 0x40) >> 6;
+
+	return 1;
+}
+#endif
+
+/*****************************************************************************
+ * Zytronic Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	switch (pkt[0]) {
+	case 0x3A: /* command response */
+		dbg("%s: Command response %d", __func__, pkt[1]);
+		break;
+
+	case 0xC0: /* down */
+		dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
+		dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
+		dev->touch = 1;
+		dbg("%s: down %d,%d", __func__, dev->x, dev->y);
+		return 1;
+
+	case 0x80: /* up */
+		dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
+		dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
+		dev->touch = 0;
+		dbg("%s: up %d,%d", __func__, dev->x, dev->y);
+		return 1;
+
+	default:
+		dbg("%s: Unknown return %d", __func__, pkt[0]);
+		break;
+	}
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * NEXIO Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+
+#define NEXIO_TIMEOUT	5000
+#define NEXIO_BUFSIZE	1024
+#define NEXIO_THRESHOLD	50
+
+struct nexio_priv {
+	struct urb *ack;
+	unsigned char *ack_buf;
+};
+
+struct nexio_touch_packet {
+	u8	flags;		/* 0xe1 = touch, 0xe1 = release */
+	__be16	data_len;	/* total bytes of touch data */
+	__be16	x_len;		/* bytes for X axis */
+	__be16	y_len;		/* bytes for Y axis */
+	u8	data[];
+} __attribute__ ((packed));
+
+static unsigned char nexio_ack_pkt[2] = { 0xaa, 0x02 };
+static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f };
+
+static void nexio_ack_complete(struct urb *urb)
+{
+}
+
+static int nexio_alloc(struct usbtouch_usb *usbtouch)
+{
+	struct nexio_priv *priv;
+	int ret = -ENOMEM;
+
+	usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
+	if (!usbtouch->priv)
+		goto out_buf;
+
+	priv = usbtouch->priv;
+
+	priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
+				GFP_KERNEL);
+	if (!priv->ack_buf)
+		goto err_priv;
+
+	priv->ack = usb_alloc_urb(0, GFP_KERNEL);
+	if (!priv->ack) {
+		dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+		goto err_ack_buf;
+	}
+
+	return 0;
+
+err_ack_buf:
+	kfree(priv->ack_buf);
+err_priv:
+	kfree(priv);
+out_buf:
+	return ret;
+}
+
+static int nexio_init(struct usbtouch_usb *usbtouch)
+{
+	struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
+	struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
+	struct nexio_priv *priv = usbtouch->priv;
+	int ret = -ENOMEM;
+	int actual_len, i;
+	unsigned char *buf;
+	char *firmware_ver = NULL, *device_name = NULL;
+	int input_ep = 0, output_ep = 0;
+
+	/* find first input and output endpoint */
+	for (i = 0; i < interface->desc.bNumEndpoints; i++) {
+		if (!input_ep &&
+		    usb_endpoint_dir_in(&interface->endpoint[i].desc))
+			input_ep = interface->endpoint[i].desc.bEndpointAddress;
+		if (!output_ep &&
+		    usb_endpoint_dir_out(&interface->endpoint[i].desc))
+			output_ep = interface->endpoint[i].desc.bEndpointAddress;
+	}
+	if (!input_ep || !output_ep)
+		return -ENXIO;
+
+	buf = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
+	if (!buf)
+		goto out_buf;
+
+	/* two empty reads */
+	for (i = 0; i < 2; i++) {
+		ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
+				   buf, NEXIO_BUFSIZE, &actual_len,
+				   NEXIO_TIMEOUT);
+		if (ret < 0)
+			goto out_buf;
+	}
+
+	/* send init command */
+	memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt));
+	ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep),
+			   buf, sizeof(nexio_init_pkt), &actual_len,
+			   NEXIO_TIMEOUT);
+	if (ret < 0)
+		goto out_buf;
+
+	/* read replies */
+	for (i = 0; i < 3; i++) {
+		memset(buf, 0, NEXIO_BUFSIZE);
+		ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
+				   buf, NEXIO_BUFSIZE, &actual_len,
+				   NEXIO_TIMEOUT);
+		if (ret < 0 || actual_len < 1 || buf[1] != actual_len)
+			continue;
+		switch (buf[0]) {
+		case 0x83:	/* firmware version */
+			if (!firmware_ver)
+				firmware_ver = kstrdup(&buf[2], GFP_NOIO);
+			break;
+		case 0x84:	/* device name */
+			if (!device_name)
+				device_name = kstrdup(&buf[2], GFP_NOIO);
+			break;
+		}
+	}
+
+	printk(KERN_INFO "Nexio device: %s, firmware version: %s\n",
+	       device_name, firmware_ver);
+
+	kfree(firmware_ver);
+	kfree(device_name);
+
+	usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
+			  priv->ack_buf, sizeof(nexio_ack_pkt),
+			  nexio_ack_complete, usbtouch);
+	ret = 0;
+
+out_buf:
+	kfree(buf);
+	return ret;
+}
+
+static void nexio_exit(struct usbtouch_usb *usbtouch)
+{
+	struct nexio_priv *priv = usbtouch->priv;
+
+	usb_kill_urb(priv->ack);
+	usb_free_urb(priv->ack);
+	kfree(priv->ack_buf);
+	kfree(priv);
+}
+
+static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
+{
+	struct nexio_touch_packet *packet = (void *) pkt;
+	struct nexio_priv *priv = usbtouch->priv;
+	unsigned int data_len = be16_to_cpu(packet->data_len);
+	unsigned int x_len = be16_to_cpu(packet->x_len);
+	unsigned int y_len = be16_to_cpu(packet->y_len);
+	int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
+
+	/* got touch data? */
+	if ((pkt[0] & 0xe0) != 0xe0)
+		return 0;
+
+	if (data_len > 0xff)
+		data_len -= 0x100;
+	if (x_len > 0xff)
+		x_len -= 0x80;
+
+	/* send ACK */
+	ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
+
+	if (!usbtouch->type->max_xc) {
+		usbtouch->type->max_xc = 2 * x_len;
+		input_set_abs_params(usbtouch->input, ABS_X,
+				     0, usbtouch->type->max_xc, 0, 0);
+		usbtouch->type->max_yc = 2 * y_len;
+		input_set_abs_params(usbtouch->input, ABS_Y,
+				     0, usbtouch->type->max_yc, 0, 0);
+	}
+	/*
+	 * The device reports state of IR sensors on X and Y axes.
+	 * Each byte represents "darkness" percentage (0-100) of one element.
+	 * 17" touchscreen reports only 64 x 52 bytes so the resolution is low.
+	 * This also means that there's a limited multi-touch capability but
+	 * it's disabled (and untested) here as there's no X driver for that.
+	 */
+	begin_x = end_x = begin_y = end_y = -1;
+	for (x = 0; x < x_len; x++) {
+		if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
+			begin_x = x;
+			continue;
+		}
+		if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
+			end_x = x - 1;
+			for (y = x_len; y < data_len; y++) {
+				if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
+					begin_y = y - x_len;
+					continue;
+				}
+				if (end_y == -1 &&
+				    begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
+					end_y = y - 1 - x_len;
+					w = end_x - begin_x;
+					h = end_y - begin_y;
+#if 0
+					/* multi-touch */
+					input_report_abs(usbtouch->input,
+						    ABS_MT_TOUCH_MAJOR, max(w,h));
+					input_report_abs(usbtouch->input,
+						    ABS_MT_TOUCH_MINOR, min(x,h));
+					input_report_abs(usbtouch->input,
+						    ABS_MT_POSITION_X, 2*begin_x+w);
+					input_report_abs(usbtouch->input,
+						    ABS_MT_POSITION_Y, 2*begin_y+h);
+					input_report_abs(usbtouch->input,
+						    ABS_MT_ORIENTATION, w > h);
+					input_mt_sync(usbtouch->input);
+#endif
+					/* single touch */
+					usbtouch->x = 2 * begin_x + w;
+					usbtouch->y = 2 * begin_y + h;
+					usbtouch->touch = packet->flags & 0x01;
+					begin_y = end_y = -1;
+					return 1;
+				}
+			}
+			begin_x = end_x = -1;
+		}
+
+	}
+	return 0;
+}
+#endif
+
+
+/*****************************************************************************
+ * ELO part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ELO
+
+static int elo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+	dev->x = (pkt[3] << 8) | pkt[2];
+	dev->y = (pkt[5] << 8) | pkt[4];
+	dev->touch = pkt[6] > 0;
+	dev->press = pkt[6];
+
+	return 1;
+}
+#endif
+
+
+/*****************************************************************************
+ * the different device descriptors
+ */
+#ifdef MULTI_PACKET
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+				   unsigned char *pkt, int len);
+#endif
+
+static struct usbtouch_device_info usbtouch_dev_info[] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_ELO
+	[DEVTYPE_ELO] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.max_press	= 0xff,
+		.rept_size	= 8,
+		.read_data	= elo_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
+	[DEVTYPE_EGALAX] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x07ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x07ff,
+		.rept_size	= 16,
+		.process_pkt	= usbtouch_process_multi,
+		.get_pkt_len	= egalax_get_pkt_len,
+		.read_data	= egalax_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
+	[DEVTYPE_PANJIT] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.rept_size	= 8,
+		.read_data	= panjit_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_3M
+	[DEVTYPE_3M] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x4000,
+		.min_yc		= 0x0,
+		.max_yc		= 0x4000,
+		.rept_size	= 11,
+		.read_data	= mtouch_read_data,
+		.init		= mtouch_init,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ITM
+	[DEVTYPE_ITM] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.max_press	= 0xff,
+		.rept_size	= 8,
+		.read_data	= itm_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
+	[DEVTYPE_ETURBO] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x07ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x07ff,
+		.rept_size	= 8,
+		.process_pkt	= usbtouch_process_multi,
+		.get_pkt_len	= eturbo_get_pkt_len,
+		.read_data	= eturbo_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
+	[DEVTYPE_GUNZE] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.rept_size	= 4,
+		.read_data	= gunze_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
+	[DEVTYPE_DMC_TSC10] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x03ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x03ff,
+		.rept_size	= 5,
+		.init		= dmc_tsc10_init,
+		.read_data	= dmc_tsc10_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+	[DEVTYPE_IRTOUCH] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.rept_size	= 8,
+		.read_data	= irtouch_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+	[DEVTYPE_IDEALTEK] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.rept_size	= 8,
+		.process_pkt	= usbtouch_process_multi,
+		.get_pkt_len	= idealtek_get_pkt_len,
+		.read_data	= idealtek_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+	[DEVTYPE_GENERAL_TOUCH] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x7fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x7fff,
+		.rept_size	= 7,
+		.read_data	= general_touch_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+	[DEVTYPE_GOTOP] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x03ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x03ff,
+		.rept_size	= 4,
+		.read_data	= gotop_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+	[DEVTYPE_JASTEC] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.rept_size	= 4,
+		.read_data	= jastec_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+	[DEVTYPE_E2I] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x7fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x7fff,
+		.rept_size	= 6,
+		.init		= e2i_init,
+		.read_data	= e2i_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+	[DEVTYPE_ZYTRONIC] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x03ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x03ff,
+		.rept_size	= 5,
+		.read_data	= zytronic_read_data,
+		.irq_always     = true,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+	[DEVTYPE_TC45USB] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x0fff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x0fff,
+		.rept_size	= 5,
+		.read_data	= tc45usb_read_data,
+	},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+	[DEVTYPE_NEXIO] = {
+		.rept_size	= 1024,
+		.irq_always	= true,
+		.read_data	= nexio_read_data,
+		.alloc		= nexio_alloc,
+		.init		= nexio_init,
+		.exit		= nexio_exit,
+	},
+#endif
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+	[DEVTYPE_ETOUCH] = {
+		.min_xc		= 0x0,
+		.max_xc		= 0x07ff,
+		.min_yc		= 0x0,
+		.max_yc		= 0x07ff,
+		.rept_size	= 16,
+		.process_pkt	= usbtouch_process_multi,
+		.get_pkt_len	= etouch_get_pkt_len,
+		.read_data	= etouch_read_data,
+	},
+#endif
+};
+
+
+/*****************************************************************************
+ * Generic Part
+ */
+static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
+                                 unsigned char *pkt, int len)
+{
+	struct usbtouch_device_info *type = usbtouch->type;
+
+	if (!type->read_data(usbtouch, pkt))
+			return;
+
+	input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
+
+	if (swap_xy) {
+		input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
+		input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
+	} else {
+		input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
+		input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
+	}
+	if (type->max_press)
+		input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
+	input_sync(usbtouch->input);
+}
+
+
+#ifdef MULTI_PACKET
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+                                   unsigned char *pkt, int len)
+{
+	unsigned char *buffer;
+	int pkt_len, pos, buf_len, tmp;
+
+	/* process buffer */
+	if (unlikely(usbtouch->buf_len)) {
+		/* try to get size */
+		pkt_len = usbtouch->type->get_pkt_len(
+				usbtouch->buffer, usbtouch->buf_len);
+
+		/* drop? */
+		if (unlikely(!pkt_len))
+			goto out_flush_buf;
+
+		/* need to append -pkt_len bytes before able to get size */
+		if (unlikely(pkt_len < 0)) {
+			int append = -pkt_len;
+			if (unlikely(append > len))
+			       append = len;
+			if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
+				goto out_flush_buf;
+			memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
+			usbtouch->buf_len += append;
+
+			pkt_len = usbtouch->type->get_pkt_len(
+					usbtouch->buffer, usbtouch->buf_len);
+			if (pkt_len < 0)
+				return;
+		}
+
+		/* append */
+		tmp = pkt_len - usbtouch->buf_len;
+		if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
+			goto out_flush_buf;
+		memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
+		usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);
+
+		buffer = pkt + tmp;
+		buf_len = len - tmp;
+	} else {
+		buffer = pkt;
+		buf_len = len;
+	}
+
+	/* loop over the received packet, process */
+	pos = 0;
+	while (pos < buf_len) {
+		/* get packet len */
+		pkt_len = usbtouch->type->get_pkt_len(buffer + pos,
+							buf_len - pos);
+
+		/* unknown packet: skip one byte */
+		if (unlikely(!pkt_len)) {
+			pos++;
+			continue;
+		}
+
+		/* full packet: process */
+		if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
+			usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
+		} else {
+			/* incomplete packet: save in buffer */
+			memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
+			usbtouch->buf_len = buf_len - pos;
+			return;
+		}
+		pos += pkt_len;
+	}
+
+out_flush_buf:
+	usbtouch->buf_len = 0;
+	return;
+}
+#endif
+
+
+static void usbtouch_irq(struct urb *urb)
+{
+	struct usbtouch_usb *usbtouch = urb->context;
+	int retval;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ETIME:
+		/* this urb is timing out */
+		dbg("%s - urb timed out - was the device unplugged?",
+		    __func__);
+		return;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+	case -EPIPE:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+		    __func__, urb->status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+		    __func__, urb->status);
+		goto exit;
+	}
+
+	usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
+
+exit:
+	usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("%s - usb_submit_urb failed with result: %d",
+		    __func__, retval);
+}
+
+static int usbtouch_open(struct input_dev *input)
+{
+	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+	int r;
+
+	usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
+
+	r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
+	if (r < 0)
+		goto out;
+
+	if (!usbtouch->type->irq_always) {
+		if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
+			r = -EIO;
+			goto out_put;
+		}
+	}
+
+	usbtouch->interface->needs_remote_wakeup = 1;
+out_put:
+	usb_autopm_put_interface(usbtouch->interface);
+out:
+	return r;
+}
+
+static void usbtouch_close(struct input_dev *input)
+{
+	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+	int r;
+
+	if (!usbtouch->type->irq_always)
+		usb_kill_urb(usbtouch->irq);
+	r = usb_autopm_get_interface(usbtouch->interface);
+	usbtouch->interface->needs_remote_wakeup = 0;
+	if (!r)
+		usb_autopm_put_interface(usbtouch->interface);
+}
+
+static int usbtouch_suspend
+(struct usb_interface *intf, pm_message_t message)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+	usb_kill_urb(usbtouch->irq);
+
+	return 0;
+}
+
+static int usbtouch_resume(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+	struct input_dev *input = usbtouch->input;
+	int result = 0;
+
+	mutex_lock(&input->mutex);
+	if (input->users || usbtouch->type->irq_always)
+		result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+	mutex_unlock(&input->mutex);
+
+	return result;
+}
+
+static int usbtouch_reset_resume(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+	struct input_dev *input = usbtouch->input;
+	int err = 0;
+
+	/* reinit the device */
+	if (usbtouch->type->init) {
+		err = usbtouch->type->init(usbtouch);
+		if (err) {
+			dbg("%s - type->init() failed, err: %d",
+			    __func__, err);
+			return err;
+		}
+	}
+
+	/* restart IO if needed */
+	mutex_lock(&input->mutex);
+	if (input->users)
+		err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+	mutex_unlock(&input->mutex);
+
+	return err;
+}
+
+static void usbtouch_free_buffers(struct usb_device *udev,
+				  struct usbtouch_usb *usbtouch)
+{
+	usb_free_coherent(udev, usbtouch->data_size,
+			  usbtouch->data, usbtouch->data_dma);
+	kfree(usbtouch->buffer);
+}
+
+static struct usb_endpoint_descriptor *
+usbtouch_get_input_endpoint(struct usb_host_interface *interface)
+{
+	int i;
+
+	for (i = 0; i < interface->desc.bNumEndpoints; i++)
+		if (usb_endpoint_dir_in(&interface->endpoint[i].desc))
+			return &interface->endpoint[i].desc;
+
+	return NULL;
+}
+
+static int usbtouch_probe(struct usb_interface *intf,
+			  const struct usb_device_id *id)
+{
+	struct usbtouch_usb *usbtouch;
+	struct input_dev *input_dev;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usbtouch_device_info *type;
+	int err = -ENOMEM;
+
+	/* some devices are ignored */
+	if (id->driver_info == DEVTYPE_IGNORE)
+		return -ENODEV;
+
+	endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
+	if (!endpoint)
+		return -ENXIO;
+
+	usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!usbtouch || !input_dev)
+		goto out_free;
+
+	type = &usbtouch_dev_info[id->driver_info];
+	usbtouch->type = type;
+	if (!type->process_pkt)
+		type->process_pkt = usbtouch_process_pkt;
+
+	usbtouch->data_size = type->rept_size;
+	if (type->get_pkt_len) {
+		/*
+		 * When dealing with variable-length packets we should
+		 * not request more than wMaxPacketSize bytes at once
+		 * as we do not know if there is more data coming or
+		 * we filled exactly wMaxPacketSize bytes and there is
+		 * nothing else.
+		 */
+		usbtouch->data_size = min(usbtouch->data_size,
+					  usb_endpoint_maxp(endpoint));
+	}
+
+	usbtouch->data = usb_alloc_coherent(udev, usbtouch->data_size,
+					    GFP_KERNEL, &usbtouch->data_dma);
+	if (!usbtouch->data)
+		goto out_free;
+
+	if (type->get_pkt_len) {
+		usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
+		if (!usbtouch->buffer)
+			goto out_free_buffers;
+	}
+
+	usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usbtouch->irq) {
+		dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
+		goto out_free_buffers;
+	}
+
+	usbtouch->interface = intf;
+	usbtouch->input = input_dev;
+
+	if (udev->manufacturer)
+		strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));
+
+	if (udev->product) {
+		if (udev->manufacturer)
+			strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
+		strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
+	}
+
+	if (!strlen(usbtouch->name))
+		snprintf(usbtouch->name, sizeof(usbtouch->name),
+			"USB Touchscreen %04x:%04x",
+			 le16_to_cpu(udev->descriptor.idVendor),
+			 le16_to_cpu(udev->descriptor.idProduct));
+
+	usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
+	strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
+
+	input_dev->name = usbtouch->name;
+	input_dev->phys = usbtouch->phys;
+	usb_to_input_id(udev, &input_dev->id);
+	input_dev->dev.parent = &intf->dev;
+
+	input_set_drvdata(input_dev, usbtouch);
+
+	input_dev->open = usbtouch_open;
+	input_dev->close = usbtouch_close;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+	input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
+	if (type->max_press)
+		input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
+		                     type->max_press, 0, 0);
+
+	if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
+		usb_fill_int_urb(usbtouch->irq, udev,
+			 usb_rcvintpipe(udev, endpoint->bEndpointAddress),
+			 usbtouch->data, usbtouch->data_size,
+			 usbtouch_irq, usbtouch, endpoint->bInterval);
+	else
+		usb_fill_bulk_urb(usbtouch->irq, udev,
+			 usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
+			 usbtouch->data, usbtouch->data_size,
+			 usbtouch_irq, usbtouch);
+
+	usbtouch->irq->dev = udev;
+	usbtouch->irq->transfer_dma = usbtouch->data_dma;
+	usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* device specific allocations */
+	if (type->alloc) {
+		err = type->alloc(usbtouch);
+		if (err) {
+			dbg("%s - type->alloc() failed, err: %d", __func__, err);
+			goto out_free_urb;
+		}
+	}
+
+	/* device specific initialisation*/
+	if (type->init) {
+		err = type->init(usbtouch);
+		if (err) {
+			dbg("%s - type->init() failed, err: %d", __func__, err);
+			goto out_do_exit;
+		}
+	}
+
+	err = input_register_device(usbtouch->input);
+	if (err) {
+		dbg("%s - input_register_device failed, err: %d", __func__, err);
+		goto out_do_exit;
+	}
+
+	usb_set_intfdata(intf, usbtouch);
+
+	if (usbtouch->type->irq_always) {
+		/* this can't fail */
+		usb_autopm_get_interface(intf);
+		err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
+		if (err) {
+			usb_autopm_put_interface(intf);
+			err("%s - usb_submit_urb failed with result: %d",
+			    __func__, err);
+			goto out_unregister_input;
+		}
+	}
+
+	return 0;
+
+out_unregister_input:
+	input_unregister_device(input_dev);
+	input_dev = NULL;
+out_do_exit:
+	if (type->exit)
+		type->exit(usbtouch);
+out_free_urb:
+	usb_free_urb(usbtouch->irq);
+out_free_buffers:
+	usbtouch_free_buffers(udev, usbtouch);
+out_free:
+	input_free_device(input_dev);
+	kfree(usbtouch);
+	return err;
+}
+
+static void usbtouch_disconnect(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+	dbg("%s - called", __func__);
+
+	if (!usbtouch)
+		return;
+
+	dbg("%s - usbtouch is initialized, cleaning up", __func__);
+	usb_set_intfdata(intf, NULL);
+	/* this will stop IO via close */
+	input_unregister_device(usbtouch->input);
+	usb_free_urb(usbtouch->irq);
+	if (usbtouch->type->exit)
+		usbtouch->type->exit(usbtouch);
+	usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);
+	kfree(usbtouch);
+}
+
+MODULE_DEVICE_TABLE(usb, usbtouch_devices);
+
+static struct usb_driver usbtouch_driver = {
+	.name		= "usbtouchscreen",
+	.probe		= usbtouch_probe,
+	.disconnect	= usbtouch_disconnect,
+	.suspend	= usbtouch_suspend,
+	.resume		= usbtouch_resume,
+	.reset_resume	= usbtouch_reset_resume,
+	.id_table	= usbtouch_devices,
+	.supports_autosuspend = 1,
+};
+
+module_usb_driver(usbtouch_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("touchkitusb");
+MODULE_ALIAS("itmtouch");
+MODULE_ALIAS("mtouchusb");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/w90p910_ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/w90p910_ts.c
new file mode 100644
index 0000000..9396b21
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/w90p910_ts.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* ADC controller bit defines */
+#define ADC_DELAY	0xf00
+#define ADC_DOWN	0x01
+#define ADC_TSC_Y	(0x01 << 8)
+#define ADC_TSC_X	(0x00 << 8)
+#define TSC_FOURWIRE	(~(0x03 << 1))
+#define ADC_CLK_EN	(0x01 << 28)	/* ADC clock enable */
+#define ADC_READ_CON	(0x01 << 12)
+#define ADC_CONV	(0x01 << 13)
+#define ADC_SEMIAUTO	(0x01 << 14)
+#define ADC_WAITTRIG	(0x03 << 14)
+#define ADC_RST1	(0x01 << 16)
+#define ADC_RST0	(0x00 << 16)
+#define ADC_EN		(0x01 << 17)
+#define ADC_INT		(0x01 << 18)
+#define WT_INT		(0x01 << 20)
+#define ADC_INT_EN	(0x01 << 21)
+#define LVD_INT_EN	(0x01 << 22)
+#define WT_INT_EN	(0x01 << 23)
+#define ADC_DIV		(0x04 << 1)	/* div = 6 */
+
+enum ts_state {
+	TS_WAIT_NEW_PACKET,	/* We are waiting next touch report */
+	TS_WAIT_X_COORD,	/* We are waiting for ADC to report X coord */
+	TS_WAIT_Y_COORD,	/* We are waiting for ADC to report Y coord */
+	TS_IDLE,		/* Input device is closed, don't do anything */
+};
+
+struct w90p910_ts {
+	struct input_dev *input;
+	struct timer_list timer;
+	struct clk *clk;
+	int irq_num;
+	void __iomem *ts_reg;
+	spinlock_t lock;
+	enum ts_state state;
+};
+
+static void w90p910_report_event(struct w90p910_ts *w90p910_ts, bool down)
+{
+	struct input_dev *dev = w90p910_ts->input;
+
+	if (down) {
+		input_report_abs(dev, ABS_X,
+				 __raw_readl(w90p910_ts->ts_reg + 0x0c));
+		input_report_abs(dev, ABS_Y,
+				 __raw_readl(w90p910_ts->ts_reg + 0x10));
+	}
+
+	input_report_key(dev, BTN_TOUCH, down);
+	input_sync(dev);
+}
+
+static void w90p910_prepare_x_reading(struct w90p910_ts *w90p910_ts)
+{
+	unsigned long ctlreg;
+
+	__raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04);
+	ctlreg = __raw_readl(w90p910_ts->ts_reg);
+	ctlreg &= ~(ADC_WAITTRIG | WT_INT | WT_INT_EN);
+	ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
+	__raw_writel(ctlreg, w90p910_ts->ts_reg);
+
+	w90p910_ts->state = TS_WAIT_X_COORD;
+}
+
+static void w90p910_prepare_y_reading(struct w90p910_ts *w90p910_ts)
+{
+	unsigned long ctlreg;
+
+	__raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04);
+	ctlreg = __raw_readl(w90p910_ts->ts_reg);
+	ctlreg &= ~(ADC_WAITTRIG | ADC_INT | WT_INT_EN);
+	ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
+	__raw_writel(ctlreg, w90p910_ts->ts_reg);
+
+	w90p910_ts->state = TS_WAIT_Y_COORD;
+}
+
+static void w90p910_prepare_next_packet(struct w90p910_ts *w90p910_ts)
+{
+	unsigned long ctlreg;
+
+	ctlreg = __raw_readl(w90p910_ts->ts_reg);
+	ctlreg &= ~(ADC_INT | ADC_INT_EN | ADC_SEMIAUTO | ADC_CONV);
+	ctlreg |= ADC_WAITTRIG | WT_INT_EN;
+	__raw_writel(ctlreg, w90p910_ts->ts_reg);
+
+	w90p910_ts->state = TS_WAIT_NEW_PACKET;
+}
+
+static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
+{
+	struct w90p910_ts *w90p910_ts = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&w90p910_ts->lock, flags);
+
+	switch (w90p910_ts->state) {
+	case TS_WAIT_NEW_PACKET:
+		/*
+		 * The controller only generates interrupts when pen
+		 * is down.
+		 */
+		del_timer(&w90p910_ts->timer);
+		w90p910_prepare_x_reading(w90p910_ts);
+		break;
+
+
+	case TS_WAIT_X_COORD:
+		w90p910_prepare_y_reading(w90p910_ts);
+		break;
+
+	case TS_WAIT_Y_COORD:
+		w90p910_report_event(w90p910_ts, true);
+		w90p910_prepare_next_packet(w90p910_ts);
+		mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(100));
+		break;
+
+	case TS_IDLE:
+		break;
+	}
+
+	spin_unlock_irqrestore(&w90p910_ts->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void w90p910_check_pen_up(unsigned long data)
+{
+	struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&w90p910_ts->lock, flags);
+
+	if (w90p910_ts->state == TS_WAIT_NEW_PACKET &&
+	    !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) {
+
+		w90p910_report_event(w90p910_ts, false);
+	}
+
+	spin_unlock_irqrestore(&w90p910_ts->lock, flags);
+}
+
+static int w90p910_open(struct input_dev *dev)
+{
+	struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
+	unsigned long val;
+
+	/* enable the ADC clock */
+	clk_enable(w90p910_ts->clk);
+
+	__raw_writel(ADC_RST1, w90p910_ts->ts_reg);
+	msleep(1);
+	__raw_writel(ADC_RST0, w90p910_ts->ts_reg);
+	msleep(1);
+
+	/* set delay and screen type */
+	val = __raw_readl(w90p910_ts->ts_reg + 0x04);
+	__raw_writel(val & TSC_FOURWIRE, w90p910_ts->ts_reg + 0x04);
+	__raw_writel(ADC_DELAY, w90p910_ts->ts_reg + 0x08);
+
+	w90p910_ts->state = TS_WAIT_NEW_PACKET;
+	wmb();
+
+	/* set trigger mode */
+	val = __raw_readl(w90p910_ts->ts_reg);
+	val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN;
+	__raw_writel(val, w90p910_ts->ts_reg);
+
+	return 0;
+}
+
+static void w90p910_close(struct input_dev *dev)
+{
+	struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
+	unsigned long val;
+
+	/* disable trigger mode */
+
+	spin_lock_irq(&w90p910_ts->lock);
+
+	w90p910_ts->state = TS_IDLE;
+
+	val = __raw_readl(w90p910_ts->ts_reg);
+	val &= ~(ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN | ADC_INT_EN);
+	__raw_writel(val, w90p910_ts->ts_reg);
+
+	spin_unlock_irq(&w90p910_ts->lock);
+
+	/* Now that interrupts are shut off we can safely delete timer */
+	del_timer_sync(&w90p910_ts->timer);
+
+	/* stop the ADC clock */
+	clk_disable(w90p910_ts->clk);
+}
+
+static int __devinit w90x900ts_probe(struct platform_device *pdev)
+{
+	struct w90p910_ts *w90p910_ts;
+	struct input_dev *input_dev;
+	struct resource *res;
+	int err;
+
+	w90p910_ts = kzalloc(sizeof(struct w90p910_ts), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!w90p910_ts || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	w90p910_ts->input = input_dev;
+	w90p910_ts->state = TS_IDLE;
+	spin_lock_init(&w90p910_ts->lock);
+	setup_timer(&w90p910_ts->timer, w90p910_check_pen_up,
+		    (unsigned long)w90p910_ts);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -ENXIO;
+		goto fail1;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res),
+				pdev->name)) {
+		err = -EBUSY;
+		goto fail1;
+	}
+
+	w90p910_ts->ts_reg = ioremap(res->start, resource_size(res));
+	if (!w90p910_ts->ts_reg) {
+		err = -ENOMEM;
+		goto fail2;
+	}
+
+	w90p910_ts->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(w90p910_ts->clk)) {
+		err = PTR_ERR(w90p910_ts->clk);
+		goto fail3;
+	}
+
+	input_dev->name = "W90P910 TouchScreen";
+	input_dev->phys = "w90p910ts/event0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor  = 0x0005;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = w90p910_open;
+	input_dev->close = w90p910_close;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0);
+
+	input_set_drvdata(input_dev, w90p910_ts);
+
+	w90p910_ts->irq_num = platform_get_irq(pdev, 0);
+	if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
+			0, "w90p910ts", w90p910_ts)) {
+		err = -EBUSY;
+		goto fail4;
+	}
+
+	err = input_register_device(w90p910_ts->input);
+	if (err)
+		goto fail5;
+
+	platform_set_drvdata(pdev, w90p910_ts);
+
+	return 0;
+
+fail5:	free_irq(w90p910_ts->irq_num, w90p910_ts);
+fail4:	clk_put(w90p910_ts->clk);
+fail3:	iounmap(w90p910_ts->ts_reg);
+fail2:	release_mem_region(res->start, resource_size(res));
+fail1:	input_free_device(input_dev);
+	kfree(w90p910_ts);
+	return err;
+}
+
+static int __devexit w90x900ts_remove(struct platform_device *pdev)
+{
+	struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	free_irq(w90p910_ts->irq_num, w90p910_ts);
+	del_timer_sync(&w90p910_ts->timer);
+	iounmap(w90p910_ts->ts_reg);
+
+	clk_put(w90p910_ts->clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+
+	input_unregister_device(w90p910_ts->input);
+	kfree(w90p910_ts);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver w90x900ts_driver = {
+	.probe		= w90x900ts_probe,
+	.remove		= __devexit_p(w90x900ts_remove),
+	.driver		= {
+		.name	= "nuc900-ts",
+		.owner	= THIS_MODULE,
+	},
+};
+module_platform_driver(w90x900ts_driver);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("w90p910 touch screen driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-ts");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wacom_w8001.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wacom_w8001.c
new file mode 100644
index 0000000..1569a39
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wacom_w8001.c
@@ -0,0 +1,608 @@
+/*
+ * Wacom W8001 penabled serial touchscreen driver
+ *
+ * Copyright (c) 2008 Jaya Kumar
+ * Copyright (c) 2010 Red Hat, Inc.
+ * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. <pingc@wacom.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Layout based on Elo serial touchscreen driver by Vojtech Pavlik
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input/mt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+
+#define DRIVER_DESC	"Wacom W8001 serial touchscreen driver"
+
+MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define W8001_MAX_LENGTH	11
+#define W8001_LEAD_MASK		0x80
+#define W8001_LEAD_BYTE		0x80
+#define W8001_TAB_MASK		0x40
+#define W8001_TAB_BYTE		0x40
+/* set in first byte of touch data packets */
+#define W8001_TOUCH_MASK	(0x10 | W8001_LEAD_MASK)
+#define W8001_TOUCH_BYTE	(0x10 | W8001_LEAD_BYTE)
+
+#define W8001_QUERY_PACKET	0x20
+
+#define W8001_CMD_STOP		'0'
+#define W8001_CMD_START		'1'
+#define W8001_CMD_QUERY		'*'
+#define W8001_CMD_TOUCHQUERY	'%'
+
+/* length of data packets in bytes, depends on device. */
+#define W8001_PKTLEN_TOUCH93	5
+#define W8001_PKTLEN_TOUCH9A	7
+#define W8001_PKTLEN_TPCPEN	9
+#define W8001_PKTLEN_TPCCTL	11	/* control packet */
+#define W8001_PKTLEN_TOUCH2FG	13
+
+/* resolution in points/mm */
+#define W8001_PEN_RESOLUTION    100
+#define W8001_TOUCH_RESOLUTION  10
+
+struct w8001_coord {
+	u8 rdy;
+	u8 tsw;
+	u8 f1;
+	u8 f2;
+	u16 x;
+	u16 y;
+	u16 pen_pressure;
+	u8 tilt_x;
+	u8 tilt_y;
+};
+
+/* touch query reply packet */
+struct w8001_touch_query {
+	u16 x;
+	u16 y;
+	u8 panel_res;
+	u8 capacity_res;
+	u8 sensor_id;
+};
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct w8001 {
+	struct input_dev *dev;
+	struct serio *serio;
+	struct completion cmd_done;
+	int id;
+	int idx;
+	unsigned char response_type;
+	unsigned char response[W8001_MAX_LENGTH];
+	unsigned char data[W8001_MAX_LENGTH];
+	char phys[32];
+	int type;
+	unsigned int pktlen;
+	u16 max_touch_x;
+	u16 max_touch_y;
+	u16 max_pen_x;
+	u16 max_pen_y;
+	char name[64];
+};
+
+static void parse_pen_data(u8 *data, struct w8001_coord *coord)
+{
+	memset(coord, 0, sizeof(*coord));
+
+	coord->rdy = data[0] & 0x20;
+	coord->tsw = data[0] & 0x01;
+	coord->f1 = data[0] & 0x02;
+	coord->f2 = data[0] & 0x04;
+
+	coord->x = (data[1] & 0x7F) << 9;
+	coord->x |= (data[2] & 0x7F) << 2;
+	coord->x |= (data[6] & 0x60) >> 5;
+
+	coord->y = (data[3] & 0x7F) << 9;
+	coord->y |= (data[4] & 0x7F) << 2;
+	coord->y |= (data[6] & 0x18) >> 3;
+
+	coord->pen_pressure = data[5] & 0x7F;
+	coord->pen_pressure |= (data[6] & 0x07) << 7 ;
+
+	coord->tilt_x = data[7] & 0x7F;
+	coord->tilt_y = data[8] & 0x7F;
+}
+
+static void parse_single_touch(u8 *data, struct w8001_coord *coord)
+{
+	coord->x = (data[1] << 7) | data[2];
+	coord->y = (data[3] << 7) | data[4];
+	coord->tsw = data[0] & 0x01;
+}
+
+static void scale_touch_coordinates(struct w8001 *w8001,
+				    unsigned int *x, unsigned int *y)
+{
+	if (w8001->max_pen_x && w8001->max_touch_x)
+		*x = *x * w8001->max_pen_x / w8001->max_touch_x;
+
+	if (w8001->max_pen_y && w8001->max_touch_y)
+		*y = *y * w8001->max_pen_y / w8001->max_touch_y;
+}
+
+static void parse_multi_touch(struct w8001 *w8001)
+{
+	struct input_dev *dev = w8001->dev;
+	unsigned char *data = w8001->data;
+	unsigned int x, y;
+	int i;
+	int count = 0;
+
+	for (i = 0; i < 2; i++) {
+		bool touch = data[0] & (1 << i);
+
+		input_mt_slot(dev, i);
+		input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
+		if (touch) {
+			x = (data[6 * i + 1] << 7) | data[6 * i + 2];
+			y = (data[6 * i + 3] << 7) | data[6 * i + 4];
+			/* data[5,6] and [11,12] is finger capacity */
+
+			/* scale to pen maximum */
+			scale_touch_coordinates(w8001, &x, &y);
+
+			input_report_abs(dev, ABS_MT_POSITION_X, x);
+			input_report_abs(dev, ABS_MT_POSITION_Y, y);
+			count++;
+		}
+	}
+
+	/* emulate single touch events when stylus is out of proximity.
+	 * This is to make single touch backward support consistent
+	 * across all Wacom single touch devices.
+	 */
+	if (w8001->type != BTN_TOOL_PEN &&
+			    w8001->type != BTN_TOOL_RUBBER) {
+		w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED;
+		input_mt_report_pointer_emulation(dev, true);
+	}
+
+	input_sync(dev);
+}
+
+static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
+{
+	memset(query, 0, sizeof(*query));
+
+	query->panel_res = data[1];
+	query->sensor_id = data[2] & 0x7;
+	query->capacity_res = data[7];
+
+	query->x = data[3] << 9;
+	query->x |= data[4] << 2;
+	query->x |= (data[2] >> 5) & 0x3;
+
+	query->y = data[5] << 9;
+	query->y |= data[6] << 2;
+	query->y |= (data[2] >> 3) & 0x3;
+
+	/* Early days' single-finger touch models need the following defaults */
+	if (!query->x && !query->y) {
+		query->x = 1024;
+		query->y = 1024;
+		if (query->panel_res)
+			query->x = query->y = (1 << query->panel_res);
+		query->panel_res = W8001_TOUCH_RESOLUTION;
+	}
+}
+
+static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
+{
+	struct input_dev *dev = w8001->dev;
+
+	/*
+	 * We have 1 bit for proximity (rdy) and 3 bits for tip, side,
+	 * side2/eraser. If rdy && f2 are set, this can be either pen + side2,
+	 * or eraser. Assume:
+	 * - if dev is already in proximity and f2 is toggled → pen + side2
+	 * - if dev comes into proximity with f2 set → eraser
+	 * If f2 disappears after assuming eraser, fake proximity out for
+	 * eraser and in for pen.
+	 */
+
+	switch (w8001->type) {
+	case BTN_TOOL_RUBBER:
+		if (!coord->f2) {
+			input_report_abs(dev, ABS_PRESSURE, 0);
+			input_report_key(dev, BTN_TOUCH, 0);
+			input_report_key(dev, BTN_STYLUS, 0);
+			input_report_key(dev, BTN_STYLUS2, 0);
+			input_report_key(dev, BTN_TOOL_RUBBER, 0);
+			input_sync(dev);
+			w8001->type = BTN_TOOL_PEN;
+		}
+		break;
+
+	case BTN_TOOL_FINGER:
+		input_report_key(dev, BTN_TOUCH, 0);
+		input_report_key(dev, BTN_TOOL_FINGER, 0);
+		input_sync(dev);
+		/* fall through */
+
+	case KEY_RESERVED:
+		w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+		break;
+
+	default:
+		input_report_key(dev, BTN_STYLUS2, coord->f2);
+		break;
+	}
+
+	input_report_abs(dev, ABS_X, coord->x);
+	input_report_abs(dev, ABS_Y, coord->y);
+	input_report_abs(dev, ABS_PRESSURE, coord->pen_pressure);
+	input_report_key(dev, BTN_TOUCH, coord->tsw);
+	input_report_key(dev, BTN_STYLUS, coord->f1);
+	input_report_key(dev, w8001->type, coord->rdy);
+	input_sync(dev);
+
+	if (!coord->rdy)
+		w8001->type = KEY_RESERVED;
+}
+
+static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
+{
+	struct input_dev *dev = w8001->dev;
+	unsigned int x = coord->x;
+	unsigned int y = coord->y;
+
+	/* scale to pen maximum */
+	scale_touch_coordinates(w8001, &x, &y);
+
+	input_report_abs(dev, ABS_X, x);
+	input_report_abs(dev, ABS_Y, y);
+	input_report_key(dev, BTN_TOUCH, coord->tsw);
+	input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
+
+	input_sync(dev);
+
+	w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED;
+}
+
+static irqreturn_t w8001_interrupt(struct serio *serio,
+				   unsigned char data, unsigned int flags)
+{
+	struct w8001 *w8001 = serio_get_drvdata(serio);
+	struct w8001_coord coord;
+	unsigned char tmp;
+
+	w8001->data[w8001->idx] = data;
+	switch (w8001->idx++) {
+	case 0:
+		if ((data & W8001_LEAD_MASK) != W8001_LEAD_BYTE) {
+			pr_debug("w8001: unsynchronized data: 0x%02x\n", data);
+			w8001->idx = 0;
+		}
+		break;
+
+	case W8001_PKTLEN_TOUCH93 - 1:
+	case W8001_PKTLEN_TOUCH9A - 1:
+		tmp = w8001->data[0] & W8001_TOUCH_BYTE;
+		if (tmp != W8001_TOUCH_BYTE)
+			break;
+
+		if (w8001->pktlen == w8001->idx) {
+			w8001->idx = 0;
+			if (w8001->type != BTN_TOOL_PEN &&
+			    w8001->type != BTN_TOOL_RUBBER) {
+				parse_single_touch(w8001->data, &coord);
+				report_single_touch(w8001, &coord);
+			}
+		}
+		break;
+
+	/* Pen coordinates packet */
+	case W8001_PKTLEN_TPCPEN - 1:
+		tmp = w8001->data[0] & W8001_TAB_MASK;
+		if (unlikely(tmp == W8001_TAB_BYTE))
+			break;
+
+		tmp = w8001->data[0] & W8001_TOUCH_BYTE;
+		if (tmp == W8001_TOUCH_BYTE)
+			break;
+
+		w8001->idx = 0;
+		parse_pen_data(w8001->data, &coord);
+		report_pen_events(w8001, &coord);
+		break;
+
+	/* control packet */
+	case W8001_PKTLEN_TPCCTL - 1:
+		tmp = w8001->data[0] & W8001_TOUCH_MASK;
+		if (tmp == W8001_TOUCH_BYTE)
+			break;
+
+		w8001->idx = 0;
+		memcpy(w8001->response, w8001->data, W8001_MAX_LENGTH);
+		w8001->response_type = W8001_QUERY_PACKET;
+		complete(&w8001->cmd_done);
+		break;
+
+	/* 2 finger touch packet */
+	case W8001_PKTLEN_TOUCH2FG - 1:
+		w8001->idx = 0;
+		parse_multi_touch(w8001);
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int w8001_command(struct w8001 *w8001, unsigned char command,
+			 bool wait_response)
+{
+	int rc;
+
+	w8001->response_type = 0;
+	init_completion(&w8001->cmd_done);
+
+	rc = serio_write(w8001->serio, command);
+	if (rc == 0 && wait_response) {
+
+		wait_for_completion_timeout(&w8001->cmd_done, HZ);
+		if (w8001->response_type != W8001_QUERY_PACKET)
+			rc = -EIO;
+	}
+
+	return rc;
+}
+
+static int w8001_open(struct input_dev *dev)
+{
+	struct w8001 *w8001 = input_get_drvdata(dev);
+
+	return w8001_command(w8001, W8001_CMD_START, false);
+}
+
+static void w8001_close(struct input_dev *dev)
+{
+	struct w8001 *w8001 = input_get_drvdata(dev);
+
+	w8001_command(w8001, W8001_CMD_STOP, false);
+}
+
+static int w8001_setup(struct w8001 *w8001)
+{
+	struct input_dev *dev = w8001->dev;
+	struct w8001_coord coord;
+	struct w8001_touch_query touch;
+	int error;
+
+	error = w8001_command(w8001, W8001_CMD_STOP, false);
+	if (error)
+		return error;
+
+	msleep(250);	/* wait 250ms before querying the device */
+
+	dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
+
+	__set_bit(INPUT_PROP_DIRECT, dev->propbit);
+
+	/* penabled? */
+	error = w8001_command(w8001, W8001_CMD_QUERY, true);
+	if (!error) {
+		__set_bit(BTN_TOUCH, dev->keybit);
+		__set_bit(BTN_TOOL_PEN, dev->keybit);
+		__set_bit(BTN_TOOL_RUBBER, dev->keybit);
+		__set_bit(BTN_STYLUS, dev->keybit);
+		__set_bit(BTN_STYLUS2, dev->keybit);
+
+		parse_pen_data(w8001->response, &coord);
+		w8001->max_pen_x = coord.x;
+		w8001->max_pen_y = coord.y;
+
+		input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
+		input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
+		input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
+		input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
+		input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
+		if (coord.tilt_x && coord.tilt_y) {
+			input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
+			input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
+		}
+		w8001->id = 0x90;
+		strlcat(w8001->name, " Penabled", sizeof(w8001->name));
+	}
+
+	/* Touch enabled? */
+	error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
+
+	/*
+	 * Some non-touch devices may reply to the touch query. But their
+	 * second byte is empty, which indicates touch is not supported.
+	 */
+	if (!error && w8001->response[1]) {
+		__set_bit(BTN_TOUCH, dev->keybit);
+		__set_bit(BTN_TOOL_FINGER, dev->keybit);
+
+		parse_touchquery(w8001->response, &touch);
+		w8001->max_touch_x = touch.x;
+		w8001->max_touch_y = touch.y;
+
+		if (w8001->max_pen_x && w8001->max_pen_y) {
+			/* if pen is supported scale to pen maximum */
+			touch.x = w8001->max_pen_x;
+			touch.y = w8001->max_pen_y;
+			touch.panel_res = W8001_PEN_RESOLUTION;
+		}
+
+		input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
+		input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
+		input_abs_set_res(dev, ABS_X, touch.panel_res);
+		input_abs_set_res(dev, ABS_Y, touch.panel_res);
+
+		switch (touch.sensor_id) {
+		case 0:
+		case 2:
+			w8001->pktlen = W8001_PKTLEN_TOUCH93;
+			w8001->id = 0x93;
+			strlcat(w8001->name, " 1FG", sizeof(w8001->name));
+			break;
+
+		case 1:
+		case 3:
+		case 4:
+			w8001->pktlen = W8001_PKTLEN_TOUCH9A;
+			strlcat(w8001->name, " 1FG", sizeof(w8001->name));
+			w8001->id = 0x9a;
+			break;
+
+		case 5:
+			w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
+
+			input_mt_init_slots(dev, 2);
+			input_set_abs_params(dev, ABS_MT_POSITION_X,
+						0, touch.x, 0, 0);
+			input_set_abs_params(dev, ABS_MT_POSITION_Y,
+						0, touch.y, 0, 0);
+			input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
+						0, MT_TOOL_MAX, 0, 0);
+
+			strlcat(w8001->name, " 2FG", sizeof(w8001->name));
+			if (w8001->max_pen_x && w8001->max_pen_y)
+				w8001->id = 0xE3;
+			else
+				w8001->id = 0xE2;
+			break;
+		}
+	}
+
+	strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
+
+	return 0;
+}
+
+/*
+ * w8001_disconnect() is the opposite of w8001_connect()
+ */
+
+static void w8001_disconnect(struct serio *serio)
+{
+	struct w8001 *w8001 = serio_get_drvdata(serio);
+
+	serio_close(serio);
+
+	input_unregister_device(w8001->dev);
+	kfree(w8001);
+
+	serio_set_drvdata(serio, NULL);
+}
+
+/*
+ * w8001_connect() is the routine that is called when someone adds a
+ * new serio device that supports the w8001 protocol and registers it as
+ * an input device.
+ */
+
+static int w8001_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct w8001 *w8001;
+	struct input_dev *input_dev;
+	int err;
+
+	w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!w8001 || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	w8001->serio = serio;
+	w8001->dev = input_dev;
+	init_completion(&w8001->cmd_done);
+	snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
+
+	serio_set_drvdata(serio, w8001);
+	err = serio_open(serio, drv);
+	if (err)
+		goto fail2;
+
+	err = w8001_setup(w8001);
+	if (err)
+		goto fail3;
+
+	input_dev->name = w8001->name;
+	input_dev->phys = w8001->phys;
+	input_dev->id.product = w8001->id;
+	input_dev->id.bustype = BUS_RS232;
+	input_dev->id.vendor = 0x056a;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &serio->dev;
+
+	input_dev->open = w8001_open;
+	input_dev->close = w8001_close;
+
+	input_set_drvdata(input_dev, w8001);
+
+	err = input_register_device(w8001->dev);
+	if (err)
+		goto fail3;
+
+	return 0;
+
+fail3:
+	serio_close(serio);
+fail2:
+	serio_set_drvdata(serio, NULL);
+fail1:
+	input_free_device(input_dev);
+	kfree(w8001);
+	return err;
+}
+
+static struct serio_device_id w8001_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_W8001,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, w8001_serio_ids);
+
+static struct serio_driver w8001_drv = {
+	.driver		= {
+		.name	= "w8001",
+	},
+	.description	= DRIVER_DESC,
+	.id_table	= w8001_serio_ids,
+	.interrupt	= w8001_interrupt,
+	.connect	= w8001_connect,
+	.disconnect	= w8001_disconnect,
+};
+
+static int __init w8001_init(void)
+{
+	return serio_register_driver(&w8001_drv);
+}
+
+static void __exit w8001_exit(void)
+{
+	serio_unregister_driver(&w8001_drv);
+}
+
+module_init(w8001_init);
+module_exit(w8001_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm831x-ts.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm831x-ts.c
new file mode 100644
index 0000000..4bc851a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm831x-ts.c
@@ -0,0 +1,410 @@
+/*
+ * Touchscreen driver for WM831x PMICs
+ *
+ * Copyright 2011 Wolfson Microelectronics plc.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/irq.h>
+#include <linux/mfd/wm831x/pdata.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/*
+ * R16424 (0x4028) - Touch Control 1
+ */
+#define WM831X_TCH_ENA                          0x8000  /* TCH_ENA */
+#define WM831X_TCH_CVT_ENA                      0x4000  /* TCH_CVT_ENA */
+#define WM831X_TCH_SLPENA                       0x1000  /* TCH_SLPENA */
+#define WM831X_TCH_Z_ENA                        0x0400  /* TCH_Z_ENA */
+#define WM831X_TCH_Y_ENA                        0x0200  /* TCH_Y_ENA */
+#define WM831X_TCH_X_ENA                        0x0100  /* TCH_X_ENA */
+#define WM831X_TCH_DELAY_MASK                   0x00E0  /* TCH_DELAY - [7:5] */
+#define WM831X_TCH_DELAY_SHIFT                       5  /* TCH_DELAY - [7:5] */
+#define WM831X_TCH_DELAY_WIDTH                       3  /* TCH_DELAY - [7:5] */
+#define WM831X_TCH_RATE_MASK                    0x001F  /* TCH_RATE - [4:0] */
+#define WM831X_TCH_RATE_SHIFT                        0  /* TCH_RATE - [4:0] */
+#define WM831X_TCH_RATE_WIDTH                        5  /* TCH_RATE - [4:0] */
+
+/*
+ * R16425 (0x4029) - Touch Control 2
+ */
+#define WM831X_TCH_PD_WK                        0x2000  /* TCH_PD_WK */
+#define WM831X_TCH_5WIRE                        0x1000  /* TCH_5WIRE */
+#define WM831X_TCH_PDONLY                       0x0800  /* TCH_PDONLY */
+#define WM831X_TCH_ISEL                         0x0100  /* TCH_ISEL */
+#define WM831X_TCH_RPU_MASK                     0x000F  /* TCH_RPU - [3:0] */
+#define WM831X_TCH_RPU_SHIFT                         0  /* TCH_RPU - [3:0] */
+#define WM831X_TCH_RPU_WIDTH                         4  /* TCH_RPU - [3:0] */
+
+/*
+ * R16426-8 (0x402A-C) - Touch Data X/Y/X
+ */
+#define WM831X_TCH_PD                           0x8000  /* TCH_PD1 */
+#define WM831X_TCH_DATA_MASK                    0x0FFF  /* TCH_DATA - [11:0] */
+#define WM831X_TCH_DATA_SHIFT                        0  /* TCH_DATA - [11:0] */
+#define WM831X_TCH_DATA_WIDTH                       12  /* TCH_DATA - [11:0] */
+
+struct wm831x_ts {
+	struct input_dev *input_dev;
+	struct wm831x *wm831x;
+	unsigned int data_irq;
+	unsigned int pd_irq;
+	bool pressure;
+	bool pen_down;
+	struct work_struct pd_data_work;
+};
+
+static void wm831x_pd_data_work(struct work_struct *work)
+{
+	struct wm831x_ts *wm831x_ts =
+		container_of(work, struct wm831x_ts, pd_data_work);
+
+	if (wm831x_ts->pen_down) {
+		enable_irq(wm831x_ts->data_irq);
+		dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n");
+	} else {
+		enable_irq(wm831x_ts->pd_irq);
+		dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n");
+	}
+}
+
+static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data)
+{
+	struct wm831x_ts *wm831x_ts = irq_data;
+	struct wm831x *wm831x = wm831x_ts->wm831x;
+	static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE };
+	u16 data[3];
+	int count;
+	int i, ret;
+
+	if (wm831x_ts->pressure)
+		count = 3;
+	else
+		count = 2;
+
+	wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
+			WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT);
+
+	ret = wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count,
+			       data);
+	if (ret != 0) {
+		dev_err(wm831x->dev, "Failed to read touch data: %d\n",
+			ret);
+		return IRQ_NONE;
+	}
+
+	/*
+	 * We get a pen down reading on every reading, report pen up if any
+	 * individual reading does so.
+	 */
+	wm831x_ts->pen_down = true;
+	for (i = 0; i < count; i++) {
+		if (!(data[i] & WM831X_TCH_PD)) {
+			wm831x_ts->pen_down = false;
+			continue;
+		}
+		input_report_abs(wm831x_ts->input_dev, data_types[i],
+				 data[i] & WM831X_TCH_DATA_MASK);
+	}
+
+	if (!wm831x_ts->pen_down) {
+		/* Switch from data to pen down */
+		dev_dbg(wm831x->dev, "IRQ DATA->PD\n");
+
+		disable_irq_nosync(wm831x_ts->data_irq);
+
+		/* Don't need data any more */
+		wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+				WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
+				WM831X_TCH_Z_ENA, 0);
+
+		/* Flush any final samples that arrived while reading */
+		wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
+				WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT);
+
+		wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, data);
+
+		if (wm831x_ts->pressure)
+			input_report_abs(wm831x_ts->input_dev,
+					 ABS_PRESSURE, 0);
+
+		input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0);
+
+		schedule_work(&wm831x_ts->pd_data_work);
+	} else {
+		input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
+	}
+
+	input_sync(wm831x_ts->input_dev);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data)
+{
+	struct wm831x_ts *wm831x_ts = irq_data;
+	struct wm831x *wm831x = wm831x_ts->wm831x;
+	int ena = 0;
+
+	if (wm831x_ts->pen_down)
+		return IRQ_HANDLED;
+
+	disable_irq_nosync(wm831x_ts->pd_irq);
+
+	/* Start collecting data */
+	if (wm831x_ts->pressure)
+		ena |= WM831X_TCH_Z_ENA;
+
+	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+			WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA,
+			WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena);
+
+	wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
+			WM831X_TCHPD_EINT, WM831X_TCHPD_EINT);
+
+	wm831x_ts->pen_down = true;
+
+	/* Switch from pen down to data */
+	dev_dbg(wm831x->dev, "IRQ PD->DATA\n");
+	schedule_work(&wm831x_ts->pd_data_work);
+
+	return IRQ_HANDLED;
+}
+
+static int wm831x_ts_input_open(struct input_dev *idev)
+{
+	struct wm831x_ts *wm831x_ts = input_get_drvdata(idev);
+	struct wm831x *wm831x = wm831x_ts->wm831x;
+
+	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+			WM831X_TCH_ENA | WM831X_TCH_CVT_ENA |
+			WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA |
+			WM831X_TCH_Z_ENA, WM831X_TCH_ENA);
+
+	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+			WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA);
+
+	return 0;
+}
+
+static void wm831x_ts_input_close(struct input_dev *idev)
+{
+	struct wm831x_ts *wm831x_ts = input_get_drvdata(idev);
+	struct wm831x *wm831x = wm831x_ts->wm831x;
+
+	/* Shut the controller down, disabling all other functionality too */
+	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+			WM831X_TCH_ENA | WM831X_TCH_X_ENA |
+			WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0);
+
+	/* Make sure any pending IRQs are done, the above will prevent
+	 * new ones firing.
+	 */
+	synchronize_irq(wm831x_ts->data_irq);
+	synchronize_irq(wm831x_ts->pd_irq);
+
+	/* Make sure the IRQ completion work is quiesced */
+	flush_work_sync(&wm831x_ts->pd_data_work);
+
+	/* If we ended up with the pen down then make sure we revert back
+	 * to pen detection state for the next time we start up.
+	 */
+	if (wm831x_ts->pen_down) {
+		disable_irq(wm831x_ts->data_irq);
+		enable_irq(wm831x_ts->pd_irq);
+		wm831x_ts->pen_down = false;
+	}
+}
+
+static __devinit int wm831x_ts_probe(struct platform_device *pdev)
+{
+	struct wm831x_ts *wm831x_ts;
+	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+	struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent);
+	struct wm831x_touch_pdata *pdata = NULL;
+	struct input_dev *input_dev;
+	int error, irqf;
+
+	if (core_pdata)
+		pdata = core_pdata->touch;
+
+	wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!wm831x_ts || !input_dev) {
+		error = -ENOMEM;
+		goto err_alloc;
+	}
+
+	wm831x_ts->wm831x = wm831x;
+	wm831x_ts->input_dev = input_dev;
+	INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work);
+
+	/*
+	 * If we have a direct IRQ use it, otherwise use the interrupt
+	 * from the WM831x IRQ controller.
+	 */
+	if (pdata && pdata->data_irq)
+		wm831x_ts->data_irq = pdata->data_irq;
+	else
+		wm831x_ts->data_irq = platform_get_irq_byname(pdev, "TCHDATA");
+
+	if (pdata && pdata->pd_irq)
+		wm831x_ts->pd_irq = pdata->pd_irq;
+	else
+		wm831x_ts->pd_irq = platform_get_irq_byname(pdev, "TCHPD");
+
+	if (pdata)
+		wm831x_ts->pressure = pdata->pressure;
+	else
+		wm831x_ts->pressure = true;
+
+	/* Five wire touchscreens can't report pressure */
+	if (pdata && pdata->fivewire) {
+		wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+				WM831X_TCH_5WIRE, WM831X_TCH_5WIRE);
+
+		/* Pressure measurements are not possible for five wire mode */
+		WARN_ON(pdata->pressure && pdata->fivewire);
+		wm831x_ts->pressure = false;
+	} else {
+		wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+				WM831X_TCH_5WIRE, 0);
+	}
+
+	if (pdata) {
+		switch (pdata->isel) {
+		default:
+			dev_err(&pdev->dev, "Unsupported ISEL setting: %d\n",
+				pdata->isel);
+			/* Fall through */
+		case 200:
+		case 0:
+			wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+					WM831X_TCH_ISEL, 0);
+			break;
+		case 400:
+			wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+					WM831X_TCH_ISEL, WM831X_TCH_ISEL);
+			break;
+		}
+	}
+
+	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
+			WM831X_TCH_PDONLY, 0);
+
+	/* Default to 96 samples/sec */
+	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
+			WM831X_TCH_RATE_MASK, 6);
+
+	if (pdata && pdata->data_irqf)
+		irqf = pdata->data_irqf;
+	else
+		irqf = IRQF_TRIGGER_HIGH;
+
+	error = request_threaded_irq(wm831x_ts->data_irq,
+				     NULL, wm831x_ts_data_irq,
+				     irqf | IRQF_ONESHOT,
+				     "Touchscreen data", wm831x_ts);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n",
+			wm831x_ts->data_irq, error);
+		goto err_alloc;
+	}
+	disable_irq(wm831x_ts->data_irq);
+
+	if (pdata && pdata->pd_irqf)
+		irqf = pdata->pd_irqf;
+	else
+		irqf = IRQF_TRIGGER_HIGH;
+
+	error = request_threaded_irq(wm831x_ts->pd_irq,
+				     NULL, wm831x_ts_pen_down_irq,
+				     irqf | IRQF_ONESHOT,
+				     "Touchscreen pen down", wm831x_ts);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n",
+			wm831x_ts->pd_irq, error);
+		goto err_data_irq;
+	}
+
+	/* set up touch configuration */
+	input_dev->name = "WM831x touchscreen";
+	input_dev->phys = "wm831x";
+	input_dev->open = wm831x_ts_input_open;
+	input_dev->close = wm831x_ts_input_close;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	input_set_abs_params(input_dev, ABS_X, 0, 4095, 5, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 4095, 5, 0);
+	if (wm831x_ts->pressure)
+		input_set_abs_params(input_dev, ABS_PRESSURE, 0, 4095, 5, 0);
+
+	input_set_drvdata(input_dev, wm831x_ts);
+	input_dev->dev.parent = &pdev->dev;
+
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_pd_irq;
+
+	platform_set_drvdata(pdev, wm831x_ts);
+	return 0;
+
+err_pd_irq:
+	free_irq(wm831x_ts->pd_irq, wm831x_ts);
+err_data_irq:
+	free_irq(wm831x_ts->data_irq, wm831x_ts);
+err_alloc:
+	input_free_device(input_dev);
+	kfree(wm831x_ts);
+
+	return error;
+}
+
+static __devexit int wm831x_ts_remove(struct platform_device *pdev)
+{
+	struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev);
+
+	free_irq(wm831x_ts->pd_irq, wm831x_ts);
+	free_irq(wm831x_ts->data_irq, wm831x_ts);
+	input_unregister_device(wm831x_ts->input_dev);
+	kfree(wm831x_ts);
+
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver wm831x_ts_driver = {
+	.driver = {
+		.name = "wm831x-touch",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm831x_ts_probe,
+	.remove = __devexit_p(wm831x_ts_remove),
+};
+module_platform_driver(wm831x_ts_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM831x PMIC touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-touch");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9705.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9705.c
new file mode 100644
index 0000000..adc13a5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9705.c
@@ -0,0 +1,350 @@
+/*
+ * wm9705.c  --  Codec driver for Wolfson WM9705 AC97 Codec.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ *                   Andrew Zabolotny <zap@homelink.ru>
+ *                   Russell King <rmk@arm.linux.org.uk>
+ *
+ *  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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wm97xx.h>
+
+#define TS_NAME			"wm97xx"
+#define WM9705_VERSION		"1.00"
+#define DEFAULT_PRESSURE	0xb0c0
+
+/*
+ * Module parameters
+ */
+
+/*
+ * Set current used for pressure measurement.
+ *
+ * Set pil = 2 to use 400uA
+ *     pil = 1 to use 200uA and
+ *     pil = 0 to disable pressure measurement.
+ *
+ * This is used to increase the range of values returned by the adc
+ * when measureing touchpanel pressure.
+ */
+static int pil;
+module_param(pil, int, 0);
+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
+
+/*
+ * Set threshold for pressure measurement.
+ *
+ * Pen down pressure below threshold is ignored.
+ */
+static int pressure = DEFAULT_PRESSURE & 0xfff;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
+
+/*
+ * Set adc sample delay.
+ *
+ * For accurate touchpanel measurements, some settling time may be
+ * required between the switch matrix applying a voltage across the
+ * touchpanel plate and the ADC sampling the signal.
+ *
+ * This delay can be set by setting delay = n, where n is the array
+ * position of the delay in the array delay_table below.
+ * Long delays > 1ms are supported for completeness, but are not
+ * recommended.
+ */
+static int delay = 4;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "Set adc sample delay.");
+
+/*
+ * Pen detect comparator threshold.
+ *
+ * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
+ * i.e. 1 =  Vmid/15 threshold
+ *      15 =  Vmid/1 threshold
+ *
+ * Adjust this value if you are having problems with pen detect not
+ * detecting any down events.
+ */
+static int pdd = 8;
+module_param(pdd, int, 0);
+MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
+
+/*
+ * Set adc mask function.
+ *
+ * Sources of glitch noise, such as signals driving an LCD display, may feed
+ * through to the touch screen plates and affect measurement accuracy. In
+ * order to minimise this, a signal may be applied to the MASK pin to delay or
+ * synchronise the sampling.
+ *
+ * 0 = No delay or sync
+ * 1 = High on pin stops conversions
+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
+ * 3 = Edge triggered, edge on pin starts conversion after delay param
+ */
+static int mask;
+module_param(mask, int, 0);
+MODULE_PARM_DESC(mask, "Set adc mask function.");
+
+/*
+ * ADC sample delay times in uS
+ */
+static const int delay_table[] = {
+	21,    /* 1 AC97 Link frames */
+	42,    /* 2                  */
+	84,    /* 4                  */
+	167,   /* 8                  */
+	333,   /* 16                 */
+	667,   /* 32                 */
+	1000,  /* 48                 */
+	1333,  /* 64                 */
+	2000,  /* 96                 */
+	2667,  /* 128                */
+	3333,  /* 160                */
+	4000,  /* 192                */
+	4667,  /* 224                */
+	5333,  /* 256                */
+	6000,  /* 288                */
+	0      /* No delay, switch matrix always on */
+};
+
+/*
+ * Delay after issuing a POLL command.
+ *
+ * The delay is 3 AC97 link frames + the touchpanel settling delay
+ */
+static inline void poll_delay(int d)
+{
+	udelay(3 * AC97_LINK_FRAME + delay_table[d]);
+}
+
+/*
+ * set up the physical settings of the WM9705
+ */
+static void wm9705_phy_init(struct wm97xx *wm)
+{
+	u16 dig1 = 0, dig2 = WM97XX_RPR;
+
+	/*
+	* mute VIDEO and AUX as they share X and Y touchscreen
+	* inputs on the WM9705
+	*/
+	wm97xx_reg_write(wm, AC97_AUX, 0x8000);
+	wm97xx_reg_write(wm, AC97_VIDEO, 0x8000);
+
+	/* touchpanel pressure current*/
+	if (pil == 2) {
+		dig2 |= WM9705_PIL;
+		dev_dbg(wm->dev,
+			"setting pressure measurement current to 400uA.");
+	} else if (pil)
+		dev_dbg(wm->dev,
+			"setting pressure measurement current to 200uA.");
+	if (!pil)
+		pressure = 0;
+
+	/* polling mode sample settling delay */
+	if (delay != 4) {
+		if (delay < 0 || delay > 15) {
+			dev_dbg(wm->dev, "supplied delay out of range.");
+			delay = 4;
+		}
+	}
+	dig1 &= 0xff0f;
+	dig1 |= WM97XX_DELAY(delay);
+	dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
+		delay_table[delay]);
+
+	/* WM9705 pdd */
+	dig2 |= (pdd & 0x000f);
+	dev_dbg(wm->dev, "setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
+
+	/* mask */
+	dig2 |= ((mask & 0x3) << 4);
+
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+}
+
+static void wm9705_dig_enable(struct wm97xx *wm, int enable)
+{
+	if (enable) {
+		wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+				 wm->dig[2] | WM97XX_PRP_DET_DIG);
+		wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
+	} else
+		wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+				 wm->dig[2] & ~WM97XX_PRP_DET_DIG);
+}
+
+static void wm9705_aux_prepare(struct wm97xx *wm)
+{
+	memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
+}
+
+static void wm9705_dig_restore(struct wm97xx *wm)
+{
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
+}
+
+static inline int is_pden(struct wm97xx *wm)
+{
+	return wm->dig[2] & WM9705_PDEN;
+}
+
+/*
+ * Read a sample from the WM9705 adc in polling mode.
+ */
+static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
+{
+	int timeout = 5 * delay;
+	bool wants_pen = adcsel & WM97XX_PEN_DOWN;
+
+	if (wants_pen && !wm->pen_probably_down) {
+		u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+		if (!(data & WM97XX_PEN_DOWN))
+			return RC_PENUP;
+		wm->pen_probably_down = 1;
+	}
+
+	/* set up digitiser */
+	if (wm->mach_ops && wm->mach_ops->pre_sample)
+		wm->mach_ops->pre_sample(adcsel);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
+				| WM97XX_POLL | WM97XX_DELAY(delay));
+
+	/* wait 3 AC97 time slots + delay for conversion */
+	poll_delay(delay);
+
+	/* wait for POLL to go low */
+	while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
+	       && timeout) {
+		udelay(AC97_LINK_FRAME);
+		timeout--;
+	}
+
+	if (timeout == 0) {
+		/* If PDEN is set, we can get a timeout when pen goes up */
+		if (is_pden(wm))
+			wm->pen_probably_down = 0;
+		else
+			dev_dbg(wm->dev, "adc sample timeout");
+		return RC_PENUP;
+	}
+
+	*sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	if (wm->mach_ops && wm->mach_ops->post_sample)
+		wm->mach_ops->post_sample(adcsel);
+
+	/* check we have correct sample */
+	if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
+		dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
+			adcsel & WM97XX_ADCSEL_MASK,
+			*sample & WM97XX_ADCSEL_MASK);
+		return RC_PENUP;
+	}
+
+	if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
+		wm->pen_probably_down = 0;
+		return RC_PENUP;
+	}
+
+	return RC_VALID;
+}
+
+/*
+ * Sample the WM9705 touchscreen in polling mode
+ */
+static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
+{
+	int rc;
+
+	rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
+	if (rc != RC_VALID)
+		return rc;
+	rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
+	if (rc != RC_VALID)
+		return rc;
+	if (pil) {
+		rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, &data->p);
+		if (rc != RC_VALID)
+			return rc;
+	} else
+		data->p = DEFAULT_PRESSURE;
+
+	return RC_VALID;
+}
+
+/*
+ * Enable WM9705 continuous mode, i.e. touch data is streamed across
+ * an AC97 slot
+ */
+static int wm9705_acc_enable(struct wm97xx *wm, int enable)
+{
+	u16 dig1, dig2;
+	int ret = 0;
+
+	dig1 = wm->dig[1];
+	dig2 = wm->dig[2];
+
+	if (enable) {
+		/* continuous mode */
+		if (wm->mach_ops->acc_startup &&
+		    (ret = wm->mach_ops->acc_startup(wm)) < 0)
+			return ret;
+		dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
+			  WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
+		dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
+			WM97XX_DELAY(delay) |
+			WM97XX_SLT(wm->acc_slot) |
+			WM97XX_RATE(wm->acc_rate);
+		if (pil)
+			dig1 |= WM97XX_ADCSEL_PRES;
+		dig2 |= WM9705_PDEN;
+	} else {
+		dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
+		dig2 &= ~WM9705_PDEN;
+		if (wm->mach_ops->acc_shutdown)
+			wm->mach_ops->acc_shutdown(wm);
+	}
+
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+
+	return ret;
+}
+
+struct wm97xx_codec_drv wm9705_codec = {
+	.id = WM9705_ID2,
+	.name = "wm9705",
+	.poll_sample = wm9705_poll_sample,
+	.poll_touch = wm9705_poll_touch,
+	.acc_enable = wm9705_acc_enable,
+	.phy_init = wm9705_phy_init,
+	.dig_enable = wm9705_dig_enable,
+	.dig_restore = wm9705_dig_restore,
+	.aux_prepare = wm9705_aux_prepare,
+};
+EXPORT_SYMBOL_GPL(wm9705_codec);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9712.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9712.c
new file mode 100644
index 0000000..6e743e3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9712.c
@@ -0,0 +1,467 @@
+/*
+ * wm9712.c  --  Codec driver for Wolfson WM9712 AC97 Codecs.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ *                   Andrew Zabolotny <zap@homelink.ru>
+ *                   Russell King <rmk@arm.linux.org.uk>
+ *
+ *  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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wm97xx.h>
+
+#define TS_NAME			"wm97xx"
+#define WM9712_VERSION		"1.00"
+#define DEFAULT_PRESSURE	0xb0c0
+
+/*
+ * Module parameters
+ */
+
+/*
+ * Set internal pull up for pen detect.
+ *
+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
+ * i.e. pull up resistance = 64k Ohms / rpu.
+ *
+ * Adjust this value if you are having problems with pen detect not
+ * detecting any down event.
+ */
+static int rpu = 8;
+module_param(rpu, int, 0);
+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
+
+/*
+ * Set current used for pressure measurement.
+ *
+ * Set pil = 2 to use 400uA
+ *     pil = 1 to use 200uA and
+ *     pil = 0 to disable pressure measurement.
+ *
+ * This is used to increase the range of values returned by the adc
+ * when measureing touchpanel pressure.
+ */
+static int pil;
+module_param(pil, int, 0);
+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
+
+/*
+ * Set threshold for pressure measurement.
+ *
+ * Pen down pressure below threshold is ignored.
+ */
+static int pressure = DEFAULT_PRESSURE & 0xfff;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
+
+/*
+ * Set adc sample delay.
+ *
+ * For accurate touchpanel measurements, some settling time may be
+ * required between the switch matrix applying a voltage across the
+ * touchpanel plate and the ADC sampling the signal.
+ *
+ * This delay can be set by setting delay = n, where n is the array
+ * position of the delay in the array delay_table below.
+ * Long delays > 1ms are supported for completeness, but are not
+ * recommended.
+ */
+static int delay = 3;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "Set adc sample delay.");
+
+/*
+ * Set five_wire = 1 to use a 5 wire touchscreen.
+ *
+ * NOTE: Five wire mode does not allow for readback of pressure.
+ */
+static int five_wire;
+module_param(five_wire, int, 0);
+MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
+
+/*
+ * Set adc mask function.
+ *
+ * Sources of glitch noise, such as signals driving an LCD display, may feed
+ * through to the touch screen plates and affect measurement accuracy. In
+ * order to minimise this, a signal may be applied to the MASK pin to delay or
+ * synchronise the sampling.
+ *
+ * 0 = No delay or sync
+ * 1 = High on pin stops conversions
+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
+ * 3 = Edge triggered, edge on pin starts conversion after delay param
+ */
+static int mask;
+module_param(mask, int, 0);
+MODULE_PARM_DESC(mask, "Set adc mask function.");
+
+/*
+ * Coordinate Polling Enable.
+ *
+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
+ * for every poll.
+ */
+static int coord;
+module_param(coord, int, 0);
+MODULE_PARM_DESC(coord, "Polling coordinate mode");
+
+/*
+ * ADC sample delay times in uS
+ */
+static const int delay_table[] = {
+	21,    /* 1 AC97 Link frames */
+	42,    /* 2 */
+	84,    /* 4 */
+	167,   /* 8 */
+	333,   /* 16 */
+	667,   /* 32 */
+	1000,  /* 48 */
+	1333,  /* 64 */
+	2000,  /* 96 */
+	2667,  /* 128 */
+	3333,  /* 160 */
+	4000,  /* 192 */
+	4667,  /* 224 */
+	5333,  /* 256 */
+	6000,  /* 288 */
+	0      /* No delay, switch matrix always on */
+};
+
+/*
+ * Delay after issuing a POLL command.
+ *
+ * The delay is 3 AC97 link frames + the touchpanel settling delay
+ */
+static inline void poll_delay(int d)
+{
+	udelay(3 * AC97_LINK_FRAME + delay_table[d]);
+}
+
+/*
+ * set up the physical settings of the WM9712
+ */
+static void wm9712_phy_init(struct wm97xx *wm)
+{
+	u16 dig1 = 0;
+	u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
+
+	/* WM9712 rpu */
+	if (rpu) {
+		dig2 &= 0xffc0;
+		dig2 |= WM9712_RPU(rpu);
+		dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms",
+			64000 / rpu);
+	}
+
+	/* WM9712 five wire */
+	if (five_wire) {
+		dig2 |= WM9712_45W;
+		dev_dbg(wm->dev, "setting 5-wire touchscreen mode.");
+
+		if (pil) {
+			dev_warn(wm->dev, "pressure measurement is not "
+				 "supported in 5-wire mode\n");
+			pil = 0;
+		}
+	}
+
+	/* touchpanel pressure current*/
+	if (pil == 2) {
+		dig2 |= WM9712_PIL;
+		dev_dbg(wm->dev,
+			"setting pressure measurement current to 400uA.");
+	} else if (pil)
+		dev_dbg(wm->dev,
+			"setting pressure measurement current to 200uA.");
+	if (!pil)
+		pressure = 0;
+
+	/* polling mode sample settling delay */
+	if (delay < 0 || delay > 15) {
+		dev_dbg(wm->dev, "supplied delay out of range.");
+		delay = 4;
+	}
+	dig1 &= 0xff0f;
+	dig1 |= WM97XX_DELAY(delay);
+	dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
+		delay_table[delay]);
+
+	/* mask */
+	dig2 |= ((mask & 0x3) << 6);
+	if (mask) {
+		u16 reg;
+		/* Set GPIO4 as Mask Pin*/
+		reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
+		wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4);
+		reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
+		wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4);
+	}
+
+	/* wait - coord mode */
+	if (coord)
+		dig2 |= WM9712_WAIT;
+
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+}
+
+static void wm9712_dig_enable(struct wm97xx *wm, int enable)
+{
+	u16 dig2 = wm->dig[2];
+
+	if (enable) {
+		wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+				 dig2 | WM97XX_PRP_DET_DIG);
+		wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
+	} else
+		wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
+				 dig2 & ~WM97XX_PRP_DET_DIG);
+}
+
+static void wm9712_aux_prepare(struct wm97xx *wm)
+{
+	memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
+}
+
+static void wm9712_dig_restore(struct wm97xx *wm)
+{
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
+}
+
+static inline int is_pden(struct wm97xx *wm)
+{
+	return wm->dig[2] & WM9712_PDEN;
+}
+
+/*
+ * Read a sample from the WM9712 adc in polling mode.
+ */
+static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
+{
+	int timeout = 5 * delay;
+	bool wants_pen = adcsel & WM97XX_PEN_DOWN;
+
+	if (wants_pen && !wm->pen_probably_down) {
+		u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+		if (!(data & WM97XX_PEN_DOWN))
+			return RC_PENUP;
+		wm->pen_probably_down = 1;
+	}
+
+	/* set up digitiser */
+	if (wm->mach_ops && wm->mach_ops->pre_sample)
+		wm->mach_ops->pre_sample(adcsel);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
+				| WM97XX_POLL | WM97XX_DELAY(delay));
+
+	/* wait 3 AC97 time slots + delay for conversion */
+	poll_delay(delay);
+
+	/* wait for POLL to go low */
+	while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
+	       && timeout) {
+		udelay(AC97_LINK_FRAME);
+		timeout--;
+	}
+
+	if (timeout <= 0) {
+		/* If PDEN is set, we can get a timeout when pen goes up */
+		if (is_pden(wm))
+			wm->pen_probably_down = 0;
+		else
+			dev_dbg(wm->dev, "adc sample timeout");
+		return RC_PENUP;
+	}
+
+	*sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	if (wm->mach_ops && wm->mach_ops->post_sample)
+		wm->mach_ops->post_sample(adcsel);
+
+	/* check we have correct sample */
+	if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
+		dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
+			adcsel & WM97XX_ADCSEL_MASK,
+			*sample & WM97XX_ADCSEL_MASK);
+		return RC_PENUP;
+	}
+
+	if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
+		wm->pen_probably_down = 0;
+		return RC_PENUP;
+	}
+
+	return RC_VALID;
+}
+
+/*
+ * Read a coord from the WM9712 adc in polling mode.
+ */
+static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
+{
+	int timeout = 5 * delay;
+
+	if (!wm->pen_probably_down) {
+		u16 data_rd = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+		if (!(data_rd & WM97XX_PEN_DOWN))
+			return RC_PENUP;
+		wm->pen_probably_down = 1;
+	}
+
+	/* set up digitiser */
+	if (wm->mach_ops && wm->mach_ops->pre_sample)
+		wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
+		WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
+
+	/* wait 3 AC97 time slots + delay for conversion and read x */
+	poll_delay(delay);
+	data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	/* wait for POLL to go low */
+	while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
+	       && timeout) {
+		udelay(AC97_LINK_FRAME);
+		timeout--;
+	}
+
+	if (timeout <= 0) {
+		/* If PDEN is set, we can get a timeout when pen goes up */
+		if (is_pden(wm))
+			wm->pen_probably_down = 0;
+		else
+			dev_dbg(wm->dev, "adc sample timeout");
+		return RC_PENUP;
+	}
+
+	/* read back y data */
+	data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	if (pil)
+		data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	else
+		data->p = DEFAULT_PRESSURE;
+
+	if (wm->mach_ops && wm->mach_ops->post_sample)
+		wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+
+	/* check we have correct sample */
+	if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
+		goto err;
+	if (pil && !(data->p & WM97XX_ADCSEL_PRES))
+		goto err;
+
+	if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
+		wm->pen_probably_down = 0;
+		return RC_PENUP;
+	}
+	return RC_VALID;
+err:
+	return 0;
+}
+
+/*
+ * Sample the WM9712 touchscreen in polling mode
+ */
+static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
+{
+	int rc;
+
+	if (coord) {
+		rc = wm9712_poll_coord(wm, data);
+		if (rc != RC_VALID)
+			return rc;
+	} else {
+		rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN,
+					&data->x);
+		if (rc != RC_VALID)
+			return rc;
+
+		rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN,
+					&data->y);
+		if (rc != RC_VALID)
+			return rc;
+
+		if (pil && !five_wire) {
+			rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
+						&data->p);
+			if (rc != RC_VALID)
+				return rc;
+		} else
+			data->p = DEFAULT_PRESSURE;
+	}
+	return RC_VALID;
+}
+
+/*
+ * Enable WM9712 continuous mode, i.e. touch data is streamed across
+ * an AC97 slot
+ */
+static int wm9712_acc_enable(struct wm97xx *wm, int enable)
+{
+	u16 dig1, dig2;
+	int ret = 0;
+
+	dig1 = wm->dig[1];
+	dig2 = wm->dig[2];
+
+	if (enable) {
+		/* continuous mode */
+		if (wm->mach_ops->acc_startup) {
+			ret = wm->mach_ops->acc_startup(wm);
+			if (ret < 0)
+				return ret;
+		}
+		dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
+			WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
+		dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
+			WM97XX_DELAY(delay) |
+			WM97XX_SLT(wm->acc_slot) |
+			WM97XX_RATE(wm->acc_rate);
+		if (pil)
+			dig1 |= WM97XX_ADCSEL_PRES;
+		dig2 |= WM9712_PDEN;
+	} else {
+		dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
+		dig2 &= ~WM9712_PDEN;
+		if (wm->mach_ops->acc_shutdown)
+			wm->mach_ops->acc_shutdown(wm);
+	}
+
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
+	wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
+
+	return 0;
+}
+
+struct wm97xx_codec_drv wm9712_codec = {
+	.id = WM9712_ID2,
+	.name = "wm9712",
+	.poll_sample = wm9712_poll_sample,
+	.poll_touch = wm9712_poll_touch,
+	.acc_enable = wm9712_acc_enable,
+	.phy_init = wm9712_phy_init,
+	.dig_enable = wm9712_dig_enable,
+	.dig_restore = wm9712_dig_restore,
+	.aux_prepare = wm9712_aux_prepare,
+};
+EXPORT_SYMBOL_GPL(wm9712_codec);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9713.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9713.c
new file mode 100644
index 0000000..7405353
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm9713.c
@@ -0,0 +1,481 @@
+/*
+ * wm9713.c  --  Codec touch driver for Wolfson WM9713 AC97 Codec.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ *                   Andrew Zabolotny <zap@homelink.ru>
+ *                   Russell King <rmk@arm.linux.org.uk>
+ *
+ *  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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/wm97xx.h>
+
+#define TS_NAME			"wm97xx"
+#define WM9713_VERSION		"1.00"
+#define DEFAULT_PRESSURE	0xb0c0
+
+/*
+ * Module parameters
+ */
+
+/*
+ * Set internal pull up for pen detect.
+ *
+ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
+ * i.e. pull up resistance = 64k Ohms / rpu.
+ *
+ * Adjust this value if you are having problems with pen detect not
+ * detecting any down event.
+ */
+static int rpu = 8;
+module_param(rpu, int, 0);
+MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
+
+/*
+ * Set current used for pressure measurement.
+ *
+ * Set pil = 2 to use 400uA
+ *     pil = 1 to use 200uA and
+ *     pil = 0 to disable pressure measurement.
+ *
+ * This is used to increase the range of values returned by the adc
+ * when measureing touchpanel pressure.
+ */
+static int pil;
+module_param(pil, int, 0);
+MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
+
+/*
+ * Set threshold for pressure measurement.
+ *
+ * Pen down pressure below threshold is ignored.
+ */
+static int pressure = DEFAULT_PRESSURE & 0xfff;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
+
+/*
+ * Set adc sample delay.
+ *
+ * For accurate touchpanel measurements, some settling time may be
+ * required between the switch matrix applying a voltage across the
+ * touchpanel plate and the ADC sampling the signal.
+ *
+ * This delay can be set by setting delay = n, where n is the array
+ * position of the delay in the array delay_table below.
+ * Long delays > 1ms are supported for completeness, but are not
+ * recommended.
+ */
+static int delay = 4;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "Set adc sample delay.");
+
+/*
+ * Set five_wire = 1 to use a 5 wire touchscreen.
+ *
+ * NOTE: Five wire mode does not allow for readback of pressure.
+ */
+static int five_wire;
+module_param(five_wire, int, 0);
+MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
+
+/*
+ * Set adc mask function.
+ *
+ * Sources of glitch noise, such as signals driving an LCD display, may feed
+ * through to the touch screen plates and affect measurement accuracy. In
+ * order to minimise this, a signal may be applied to the MASK pin to delay or
+ * synchronise the sampling.
+ *
+ * 0 = No delay or sync
+ * 1 = High on pin stops conversions
+ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
+ * 3 = Edge triggered, edge on pin starts conversion after delay param
+ */
+static int mask;
+module_param(mask, int, 0);
+MODULE_PARM_DESC(mask, "Set adc mask function.");
+
+/*
+ * Coordinate Polling Enable.
+ *
+ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
+ * for every poll.
+ */
+static int coord;
+module_param(coord, int, 0);
+MODULE_PARM_DESC(coord, "Polling coordinate mode");
+
+/*
+ * ADC sample delay times in uS
+ */
+static const int delay_table[] = {
+	21,    /* 1 AC97 Link frames */
+	42,    /* 2 */
+	84,    /* 4 */
+	167,   /* 8 */
+	333,   /* 16 */
+	667,   /* 32 */
+	1000,  /* 48 */
+	1333,  /* 64 */
+	2000,  /* 96 */
+	2667,  /* 128 */
+	3333,  /* 160 */
+	4000,  /* 192 */
+	4667,  /* 224 */
+	5333,  /* 256 */
+	6000,  /* 288 */
+	0      /* No delay, switch matrix always on */
+};
+
+/*
+ * Delay after issuing a POLL command.
+ *
+ * The delay is 3 AC97 link frames + the touchpanel settling delay
+ */
+static inline void poll_delay(int d)
+{
+	udelay(3 * AC97_LINK_FRAME + delay_table[d]);
+}
+
+/*
+ * set up the physical settings of the WM9713
+ */
+static void wm9713_phy_init(struct wm97xx *wm)
+{
+	u16 dig1 = 0, dig2, dig3;
+
+	/* default values */
+	dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5);
+	dig3 = WM9712_RPU(1);
+
+	/* rpu */
+	if (rpu) {
+		dig3 &= 0xffc0;
+		dig3 |= WM9712_RPU(rpu);
+		dev_info(wm->dev, "setting pen detect pull-up to %d Ohms\n",
+			 64000 / rpu);
+	}
+
+	/* Five wire panel? */
+	if (five_wire) {
+		dig3 |= WM9713_45W;
+		dev_info(wm->dev, "setting 5-wire touchscreen mode.");
+
+		if (pil) {
+			dev_warn(wm->dev,
+				 "Pressure measurement not supported in 5 "
+				 "wire mode, disabling\n");
+			pil = 0;
+		}
+	}
+
+	/* touchpanel pressure */
+	if (pil == 2) {
+		dig3 |= WM9712_PIL;
+		dev_info(wm->dev,
+			 "setting pressure measurement current to 400uA.");
+	} else if (pil)
+		dev_info(wm->dev,
+			 "setting pressure measurement current to 200uA.");
+	if (!pil)
+		pressure = 0;
+
+	/* sample settling delay */
+	if (delay < 0 || delay > 15) {
+		dev_info(wm->dev, "supplied delay out of range.");
+		delay = 4;
+		dev_info(wm->dev, "setting adc sample delay to %d u Secs.",
+			 delay_table[delay]);
+	}
+	dig2 &= 0xff0f;
+	dig2 |= WM97XX_DELAY(delay);
+
+	/* mask */
+	dig3 |= ((mask & 0x3) << 4);
+	if (coord)
+		dig3 |= WM9713_WAIT;
+
+	wm->misc = wm97xx_reg_read(wm, 0x5a);
+
+	wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
+	wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0);
+}
+
+static void wm9713_dig_enable(struct wm97xx *wm, int enable)
+{
+	u16 val;
+
+	if (enable) {
+		val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
+		wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff);
+		wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] |
+				 WM97XX_PRP_DET_DIG);
+		wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
+	} else {
+		wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] &
+					~WM97XX_PRP_DET_DIG);
+		val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
+		wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000);
+	}
+}
+
+static void wm9713_dig_restore(struct wm97xx *wm)
+{
+	wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]);
+}
+
+static void wm9713_aux_prepare(struct wm97xx *wm)
+{
+	memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
+	wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG);
+}
+
+static inline int is_pden(struct wm97xx *wm)
+{
+	return wm->dig[2] & WM9713_PDEN;
+}
+
+/*
+ * Read a sample from the WM9713 adc in polling mode.
+ */
+static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
+{
+	u16 dig1;
+	int timeout = 5 * delay;
+	bool wants_pen = adcsel & WM97XX_PEN_DOWN;
+
+	if (wants_pen && !wm->pen_probably_down) {
+		u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+		if (!(data & WM97XX_PEN_DOWN))
+			return RC_PENUP;
+		wm->pen_probably_down = 1;
+	}
+
+	/* set up digitiser */
+	dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
+	dig1 &= ~WM9713_ADCSEL_MASK;
+	/* WM97XX_ADCSEL_* channels need to be converted to WM9713 format */
+	dig1 |= 1 << ((adcsel & WM97XX_ADCSEL_MASK) >> 12);
+
+	if (wm->mach_ops && wm->mach_ops->pre_sample)
+		wm->mach_ops->pre_sample(adcsel);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL);
+
+	/* wait 3 AC97 time slots + delay for conversion */
+	poll_delay(delay);
+
+	/* wait for POLL to go low */
+	while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) &&
+		timeout) {
+		udelay(AC97_LINK_FRAME);
+		timeout--;
+	}
+
+	if (timeout <= 0) {
+		/* If PDEN is set, we can get a timeout when pen goes up */
+		if (is_pden(wm))
+			wm->pen_probably_down = 0;
+		else
+			dev_dbg(wm->dev, "adc sample timeout");
+		return RC_PENUP;
+	}
+
+	*sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	if (wm->mach_ops && wm->mach_ops->post_sample)
+		wm->mach_ops->post_sample(adcsel);
+
+	/* check we have correct sample */
+	if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
+		dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
+			adcsel & WM97XX_ADCSEL_MASK,
+			*sample & WM97XX_ADCSEL_MASK);
+		return RC_PENUP;
+	}
+
+	if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
+		wm->pen_probably_down = 0;
+		return RC_PENUP;
+	}
+
+	return RC_VALID;
+}
+
+/*
+ * Read a coordinate from the WM9713 adc in polling mode.
+ */
+static int wm9713_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
+{
+	u16 dig1;
+	int timeout = 5 * delay;
+
+	if (!wm->pen_probably_down) {
+		u16 val = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+		if (!(val & WM97XX_PEN_DOWN))
+			return RC_PENUP;
+		wm->pen_probably_down = 1;
+	}
+
+	/* set up digitiser */
+	dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
+	dig1 &= ~WM9713_ADCSEL_MASK;
+	if (pil)
+		dig1 |= WM9713_ADCSEL_PRES;
+
+	if (wm->mach_ops && wm->mach_ops->pre_sample)
+		wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG1,
+			 dig1 | WM9713_POLL | WM9713_COO);
+
+	/* wait 3 AC97 time slots + delay for conversion */
+	poll_delay(delay);
+	data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	/* wait for POLL to go low */
+	while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL)
+	       && timeout) {
+		udelay(AC97_LINK_FRAME);
+		timeout--;
+	}
+
+	if (timeout <= 0) {
+		/* If PDEN is set, we can get a timeout when pen goes up */
+		if (is_pden(wm))
+			wm->pen_probably_down = 0;
+		else
+			dev_dbg(wm->dev, "adc sample timeout");
+		return RC_PENUP;
+	}
+
+	/* read back data */
+	data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	if (pil)
+		data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+	else
+		data->p = DEFAULT_PRESSURE;
+
+	if (wm->mach_ops && wm->mach_ops->post_sample)
+		wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
+
+	/* check we have correct sample */
+	if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
+		goto err;
+	if (pil && !(data->p & WM97XX_ADCSEL_PRES))
+		goto err;
+
+	if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
+		wm->pen_probably_down = 0;
+		return RC_PENUP;
+	}
+	return RC_VALID;
+err:
+	return 0;
+}
+
+/*
+ * Sample the WM9713 touchscreen in polling mode
+ */
+static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
+{
+	int rc;
+
+	if (coord) {
+		rc = wm9713_poll_coord(wm, data);
+		if (rc != RC_VALID)
+			return rc;
+	} else {
+		rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
+		if (rc != RC_VALID)
+			return rc;
+		rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
+		if (rc != RC_VALID)
+			return rc;
+		if (pil) {
+			rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
+						&data->p);
+			if (rc != RC_VALID)
+				return rc;
+		} else
+			data->p = DEFAULT_PRESSURE;
+	}
+	return RC_VALID;
+}
+
+/*
+ * Enable WM9713 continuous mode, i.e. touch data is streamed across
+ * an AC97 slot
+ */
+static int wm9713_acc_enable(struct wm97xx *wm, int enable)
+{
+	u16 dig1, dig2, dig3;
+	int ret = 0;
+
+	dig1 = wm->dig[0];
+	dig2 = wm->dig[1];
+	dig3 = wm->dig[2];
+
+	if (enable) {
+		/* continuous mode */
+		if (wm->mach_ops->acc_startup &&
+			(ret = wm->mach_ops->acc_startup(wm)) < 0)
+			return ret;
+
+		dig1 &= ~WM9713_ADCSEL_MASK;
+		dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X |
+			WM9713_ADCSEL_Y;
+		if (pil)
+			dig1 |= WM9713_ADCSEL_PRES;
+		dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK  |
+			WM97XX_CM_RATE_MASK);
+		dig2 |= WM97XX_SLEN | WM97XX_DELAY(delay) |
+		WM97XX_SLT(wm->acc_slot) | WM97XX_RATE(wm->acc_rate);
+		dig3 |= WM9713_PDEN;
+	} else {
+		dig1 &= ~(WM9713_CTC | WM9713_COO);
+		dig2 &= ~WM97XX_SLEN;
+		dig3 &= ~WM9713_PDEN;
+		if (wm->mach_ops->acc_shutdown)
+			wm->mach_ops->acc_shutdown(wm);
+	}
+
+	wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
+
+	return ret;
+}
+
+struct wm97xx_codec_drv wm9713_codec = {
+	.id = WM9713_ID2,
+	.name = "wm9713",
+	.poll_sample = wm9713_poll_sample,
+	.poll_touch = wm9713_poll_touch,
+	.acc_enable = wm9713_acc_enable,
+	.phy_init = wm9713_phy_init,
+	.dig_enable = wm9713_dig_enable,
+	.dig_restore = wm9713_dig_restore,
+	.aux_prepare = wm9713_aux_prepare,
+};
+EXPORT_SYMBOL_GPL(wm9713_codec);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm97xx-core.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm97xx-core.c
new file mode 100644
index 0000000..5dbe73a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/wm97xx-core.c
@@ -0,0 +1,848 @@
+/*
+ * wm97xx-core.c  --  Touch screen driver core for Wolfson WM9705, WM9712
+ *                    and WM9713 AC97 Codecs.
+ *
+ * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ *                   Andrew Zabolotny <zap@homelink.ru>
+ *                   Russell King <rmk@arm.linux.org.uk>
+ *
+ *  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.
+ *
+ * Notes:
+ *
+ *  Features:
+ *       - supports WM9705, WM9712, WM9713
+ *       - polling mode
+ *       - continuous mode (arch-dependent)
+ *       - adjustable rpu/dpp settings
+ *       - adjustable pressure current
+ *       - adjustable sample settle delay
+ *       - 4 and 5 wire touchscreens (5 wire is WM9712 only)
+ *       - pen down detection
+ *       - battery monitor
+ *       - sample AUX adcs
+ *       - power management
+ *       - codec GPIO
+ *       - codec event notification
+ * Todo
+ *       - Support for async sampling control for noisy LCDs.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+#include <linux/wm97xx.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define TS_NAME			"wm97xx"
+#define WM_CORE_VERSION		"1.00"
+#define DEFAULT_PRESSURE	0xb0c0
+
+
+/*
+ * Touchscreen absolute values
+ *
+ * These parameters are used to help the input layer discard out of
+ * range readings and reduce jitter etc.
+ *
+ *   o min, max:- indicate the min and max values your touch screen returns
+ *   o fuzz:- use a higher number to reduce jitter
+ *
+ * The default values correspond to Mainstone II in QVGA mode
+ *
+ * Please read
+ * Documentation/input/input-programming.txt for more details.
+ */
+
+static int abs_x[3] = {350, 3900, 5};
+module_param_array(abs_x, int, NULL, 0);
+MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
+
+static int abs_y[3] = {320, 3750, 40};
+module_param_array(abs_y, int, NULL, 0);
+MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
+
+static int abs_p[3] = {0, 150, 4};
+module_param_array(abs_p, int, NULL, 0);
+MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz");
+
+/*
+ * wm97xx IO access, all IO locking done by AC97 layer
+ */
+int wm97xx_reg_read(struct wm97xx *wm, u16 reg)
+{
+	if (wm->ac97)
+		return wm->ac97->bus->ops->read(wm->ac97, reg);
+	else
+		return -1;
+}
+EXPORT_SYMBOL_GPL(wm97xx_reg_read);
+
+void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val)
+{
+	/* cache digitiser registers */
+	if (reg >= AC97_WM9713_DIG1 && reg <= AC97_WM9713_DIG3)
+		wm->dig[(reg - AC97_WM9713_DIG1) >> 1] = val;
+
+	/* cache gpio regs */
+	if (reg >= AC97_GPIO_CFG && reg <= AC97_MISC_AFE)
+		wm->gpio[(reg - AC97_GPIO_CFG) >> 1] = val;
+
+	/* wm9713 irq reg */
+	if (reg == 0x5a)
+		wm->misc = val;
+
+	if (wm->ac97)
+		wm->ac97->bus->ops->write(wm->ac97, reg, val);
+}
+EXPORT_SYMBOL_GPL(wm97xx_reg_write);
+
+/**
+ * wm97xx_read_aux_adc - Read the aux adc.
+ * @wm: wm97xx device.
+ * @adcsel: codec ADC to be read
+ *
+ * Reads the selected AUX ADC.
+ */
+
+int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
+{
+	int power_adc = 0, auxval;
+	u16 power = 0;
+	int rc = 0;
+	int timeout = 0;
+
+	/* get codec */
+	mutex_lock(&wm->codec_mutex);
+
+	/* When the touchscreen is not in use, we may have to power up
+	 * the AUX ADC before we can use sample the AUX inputs->
+	 */
+	if (wm->id == WM9713_ID2 &&
+	    (power = wm97xx_reg_read(wm, AC97_EXTENDED_MID)) & 0x8000) {
+		power_adc = 1;
+		wm97xx_reg_write(wm, AC97_EXTENDED_MID, power & 0x7fff);
+	}
+
+	/* Prepare the codec for AUX reading */
+	wm->codec->aux_prepare(wm);
+
+	/* Turn polling mode on to read AUX ADC */
+	wm->pen_probably_down = 1;
+
+	while (rc != RC_VALID && timeout++ < 5)
+		rc = wm->codec->poll_sample(wm, adcsel, &auxval);
+
+	if (power_adc)
+		wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
+
+	wm->codec->dig_restore(wm);
+
+	wm->pen_probably_down = 0;
+
+	if (timeout >= 5) {
+		dev_err(wm->dev,
+			"timeout reading auxadc %d, disabling digitiser\n",
+			adcsel);
+		wm->codec->dig_enable(wm, false);
+	}
+
+	mutex_unlock(&wm->codec_mutex);
+	return (rc == RC_VALID ? auxval & 0xfff : -EBUSY);
+}
+EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
+
+/**
+ * wm97xx_get_gpio - Get the status of a codec GPIO.
+ * @wm: wm97xx device.
+ * @gpio: gpio
+ *
+ * Get the status of a codec GPIO pin
+ */
+
+enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio)
+{
+	u16 status;
+	enum wm97xx_gpio_status ret;
+
+	mutex_lock(&wm->codec_mutex);
+	status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+
+	if (status & gpio)
+		ret = WM97XX_GPIO_HIGH;
+	else
+		ret = WM97XX_GPIO_LOW;
+
+	mutex_unlock(&wm->codec_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(wm97xx_get_gpio);
+
+/**
+ * wm97xx_set_gpio - Set the status of a codec GPIO.
+ * @wm: wm97xx device.
+ * @gpio: gpio
+ *
+ *
+ * Set the status of a codec GPIO pin
+ */
+
+void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
+				enum wm97xx_gpio_status status)
+{
+	u16 reg;
+
+	mutex_lock(&wm->codec_mutex);
+	reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+
+	if (status == WM97XX_GPIO_HIGH)
+		reg |= gpio;
+	else
+		reg &= ~gpio;
+
+	if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
+		wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
+	else
+		wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
+	mutex_unlock(&wm->codec_mutex);
+}
+EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
+
+/*
+ * Codec GPIO pin configuration, this sets pin direction, polarity,
+ * stickyness and wake up.
+ */
+void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
+		   enum wm97xx_gpio_pol pol, enum wm97xx_gpio_sticky sticky,
+		   enum wm97xx_gpio_wake wake)
+{
+	u16 reg;
+
+	mutex_lock(&wm->codec_mutex);
+	reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
+
+	if (pol == WM97XX_GPIO_POL_HIGH)
+		reg |= gpio;
+	else
+		reg &= ~gpio;
+
+	wm97xx_reg_write(wm, AC97_GPIO_POLARITY, reg);
+	reg = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
+
+	if (sticky == WM97XX_GPIO_STICKY)
+		reg |= gpio;
+	else
+		reg &= ~gpio;
+
+	wm97xx_reg_write(wm, AC97_GPIO_STICKY, reg);
+	reg = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
+
+	if (wake == WM97XX_GPIO_WAKE)
+		reg |= gpio;
+	else
+		reg &= ~gpio;
+
+	wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, reg);
+	reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
+
+	if (dir == WM97XX_GPIO_IN)
+		reg |= gpio;
+	else
+		reg &= ~gpio;
+
+	wm97xx_reg_write(wm, AC97_GPIO_CFG, reg);
+	mutex_unlock(&wm->codec_mutex);
+}
+EXPORT_SYMBOL_GPL(wm97xx_config_gpio);
+
+/*
+ * Configure the WM97XX_PRP value to use while system is suspended.
+ * If a value other than 0 is set then WM97xx pen detection will be
+ * left enabled in the configured mode while the system is in suspend,
+ * the device has users and suspend has not been disabled via the
+ * wakeup sysfs entries.
+ *
+ * @wm:   WM97xx device to configure
+ * @mode: WM97XX_PRP value to configure while suspended
+ */
+void wm97xx_set_suspend_mode(struct wm97xx *wm, u16 mode)
+{
+	wm->suspend_mode = mode;
+	device_init_wakeup(&wm->input_dev->dev, mode != 0);
+}
+EXPORT_SYMBOL_GPL(wm97xx_set_suspend_mode);
+
+/*
+ * Handle a pen down interrupt.
+ */
+static void wm97xx_pen_irq_worker(struct work_struct *work)
+{
+	struct wm97xx *wm = container_of(work, struct wm97xx, pen_event_work);
+	int pen_was_down = wm->pen_is_down;
+
+	/* do we need to enable the touch panel reader */
+	if (wm->id == WM9705_ID2) {
+		if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) &
+					WM97XX_PEN_DOWN)
+			wm->pen_is_down = 1;
+		else
+			wm->pen_is_down = 0;
+	} else {
+		u16 status, pol;
+		mutex_lock(&wm->codec_mutex);
+		status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+		pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
+
+		if (WM97XX_GPIO_13 & pol & status) {
+			wm->pen_is_down = 1;
+			wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol &
+						~WM97XX_GPIO_13);
+		} else {
+			wm->pen_is_down = 0;
+			wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol |
+					 WM97XX_GPIO_13);
+		}
+
+		if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613)
+			wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status &
+						~WM97XX_GPIO_13) << 1);
+		else
+			wm97xx_reg_write(wm, AC97_GPIO_STATUS, status &
+						~WM97XX_GPIO_13);
+		mutex_unlock(&wm->codec_mutex);
+	}
+
+	/* If the system is not using continuous mode or it provides a
+	 * pen down operation then we need to schedule polls while the
+	 * pen is down.  Otherwise the machine driver is responsible
+	 * for scheduling reads.
+	 */
+	if (!wm->mach_ops->acc_enabled || wm->mach_ops->acc_pen_down) {
+		if (wm->pen_is_down && !pen_was_down) {
+			/* Data is not available immediately on pen down */
+			queue_delayed_work(wm->ts_workq, &wm->ts_reader, 1);
+		}
+
+		/* Let ts_reader report the pen up for debounce. */
+		if (!wm->pen_is_down && pen_was_down)
+			wm->pen_is_down = 1;
+	}
+
+	if (!wm->pen_is_down && wm->mach_ops->acc_enabled)
+		wm->mach_ops->acc_pen_up(wm);
+
+	wm->mach_ops->irq_enable(wm, 1);
+}
+
+/*
+ * Codec PENDOWN irq handler
+ *
+ * We have to disable the codec interrupt in the handler because it
+ * can take up to 1ms to clear the interrupt source. We schedule a task
+ * in a work queue to do the actual interaction with the chip.  The
+ * interrupt is then enabled again in the slow handler when the source
+ * has been cleared.
+ */
+static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
+{
+	struct wm97xx *wm = dev_id;
+
+	if (!work_pending(&wm->pen_event_work)) {
+		wm->mach_ops->irq_enable(wm, 0);
+		queue_work(wm->ts_workq, &wm->pen_event_work);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * initialise pen IRQ handler and workqueue
+ */
+static int wm97xx_init_pen_irq(struct wm97xx *wm)
+{
+	u16 reg;
+
+	/* If an interrupt is supplied an IRQ enable operation must also be
+	 * provided. */
+	BUG_ON(!wm->mach_ops->irq_enable);
+
+	if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED,
+			"wm97xx-pen", wm)) {
+		dev_err(wm->dev,
+			"Failed to register pen down interrupt, polling");
+		wm->pen_irq = 0;
+		return -EINVAL;
+	}
+
+	/* Configure GPIO as interrupt source on WM971x */
+	if (wm->id != WM9705_ID2) {
+		BUG_ON(!wm->mach_ops->irq_gpio);
+		reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
+		wm97xx_reg_write(wm, AC97_MISC_AFE,
+				reg & ~(wm->mach_ops->irq_gpio));
+		reg = wm97xx_reg_read(wm, 0x5a);
+		wm97xx_reg_write(wm, 0x5a, reg & ~0x0001);
+	}
+
+	return 0;
+}
+
+static int wm97xx_read_samples(struct wm97xx *wm)
+{
+	struct wm97xx_data data;
+	int rc;
+
+	mutex_lock(&wm->codec_mutex);
+
+	if (wm->mach_ops && wm->mach_ops->acc_enabled)
+		rc = wm->mach_ops->acc_pen_down(wm);
+	else
+		rc = wm->codec->poll_touch(wm, &data);
+
+	if (rc & RC_PENUP) {
+		if (wm->pen_is_down) {
+			wm->pen_is_down = 0;
+			dev_dbg(wm->dev, "pen up\n");
+			input_report_abs(wm->input_dev, ABS_PRESSURE, 0);
+			input_report_key(wm->input_dev, BTN_TOUCH, 0);
+			input_sync(wm->input_dev);
+		} else if (!(rc & RC_AGAIN)) {
+			/* We need high frequency updates only while
+			* pen is down, the user never will be able to
+			* touch screen faster than a few times per
+			* second... On the other hand, when the user
+			* is actively working with the touchscreen we
+			* don't want to lose the quick response. So we
+			* will slowly increase sleep time after the
+			* pen is up and quicky restore it to ~one task
+			* switch when pen is down again.
+			*/
+			if (wm->ts_reader_interval < HZ / 10)
+				wm->ts_reader_interval++;
+		}
+
+	} else if (rc & RC_VALID) {
+		dev_dbg(wm->dev,
+			"pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n",
+			data.x >> 12, data.x & 0xfff, data.y >> 12,
+			data.y & 0xfff, data.p >> 12, data.p & 0xfff);
+		input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
+		input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff);
+		input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff);
+		input_report_key(wm->input_dev, BTN_TOUCH, 1);
+		input_sync(wm->input_dev);
+		wm->pen_is_down = 1;
+		wm->ts_reader_interval = wm->ts_reader_min_interval;
+	} else if (rc & RC_PENDOWN) {
+		dev_dbg(wm->dev, "pen down\n");
+		wm->pen_is_down = 1;
+		wm->ts_reader_interval = wm->ts_reader_min_interval;
+	}
+
+	mutex_unlock(&wm->codec_mutex);
+	return rc;
+}
+
+/*
+* The touchscreen sample reader.
+*/
+static void wm97xx_ts_reader(struct work_struct *work)
+{
+	int rc;
+	struct wm97xx *wm = container_of(work, struct wm97xx, ts_reader.work);
+
+	BUG_ON(!wm->codec);
+
+	do {
+		rc = wm97xx_read_samples(wm);
+	} while (rc & RC_AGAIN);
+
+	if (wm->pen_is_down || !wm->pen_irq)
+		queue_delayed_work(wm->ts_workq, &wm->ts_reader,
+				   wm->ts_reader_interval);
+}
+
+/**
+ * wm97xx_ts_input_open - Open the touch screen input device.
+ * @idev:	Input device to be opened.
+ *
+ * Called by the input sub system to open a wm97xx touchscreen device.
+ * Starts the touchscreen thread and touch digitiser.
+ */
+static int wm97xx_ts_input_open(struct input_dev *idev)
+{
+	struct wm97xx *wm = input_get_drvdata(idev);
+
+	wm->ts_workq = create_singlethread_workqueue("kwm97xx");
+	if (wm->ts_workq == NULL) {
+		dev_err(wm->dev,
+			"Failed to create workqueue\n");
+		return -EINVAL;
+	}
+
+	/* start digitiser */
+	if (wm->mach_ops && wm->mach_ops->acc_enabled)
+		wm->codec->acc_enable(wm, 1);
+	wm->codec->dig_enable(wm, 1);
+
+	INIT_DELAYED_WORK(&wm->ts_reader, wm97xx_ts_reader);
+	INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker);
+
+	wm->ts_reader_min_interval = HZ >= 100 ? HZ / 100 : 1;
+	if (wm->ts_reader_min_interval < 1)
+		wm->ts_reader_min_interval = 1;
+	wm->ts_reader_interval = wm->ts_reader_min_interval;
+
+	wm->pen_is_down = 0;
+	if (wm->pen_irq)
+		wm97xx_init_pen_irq(wm);
+	else
+		dev_err(wm->dev, "No IRQ specified\n");
+
+	/* If we either don't have an interrupt for pen down events or
+	 * failed to acquire it then we need to poll.
+	 */
+	if (wm->pen_irq == 0)
+		queue_delayed_work(wm->ts_workq, &wm->ts_reader,
+				   wm->ts_reader_interval);
+
+	return 0;
+}
+
+/**
+ * wm97xx_ts_input_close - Close the touch screen input device.
+ * @idev:	Input device to be closed.
+ *
+ * Called by the input sub system to close a wm97xx touchscreen
+ * device.  Kills the touchscreen thread and stops the touch
+ * digitiser.
+ */
+
+static void wm97xx_ts_input_close(struct input_dev *idev)
+{
+	struct wm97xx *wm = input_get_drvdata(idev);
+	u16 reg;
+
+	if (wm->pen_irq) {
+		/* Return the interrupt to GPIO usage (disabling it) */
+		if (wm->id != WM9705_ID2) {
+			BUG_ON(!wm->mach_ops->irq_gpio);
+			reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
+			wm97xx_reg_write(wm, AC97_MISC_AFE,
+					 reg | wm->mach_ops->irq_gpio);
+		}
+
+		free_irq(wm->pen_irq, wm);
+	}
+
+	wm->pen_is_down = 0;
+
+	/* Balance out interrupt disables/enables */
+	if (cancel_work_sync(&wm->pen_event_work))
+		wm->mach_ops->irq_enable(wm, 1);
+
+	/* ts_reader rearms itself so we need to explicitly stop it
+	 * before we destroy the workqueue.
+	 */
+	cancel_delayed_work_sync(&wm->ts_reader);
+
+	destroy_workqueue(wm->ts_workq);
+
+	/* stop digitiser */
+	wm->codec->dig_enable(wm, 0);
+	if (wm->mach_ops && wm->mach_ops->acc_enabled)
+		wm->codec->acc_enable(wm, 0);
+}
+
+static int wm97xx_probe(struct device *dev)
+{
+	struct wm97xx *wm;
+	struct wm97xx_pdata *pdata = dev->platform_data;
+	int ret = 0, id = 0;
+
+	wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL);
+	if (!wm)
+		return -ENOMEM;
+	mutex_init(&wm->codec_mutex);
+
+	wm->dev = dev;
+	dev_set_drvdata(dev, wm);
+	wm->ac97 = to_ac97_t(dev);
+
+	/* check that we have a supported codec */
+	id = wm97xx_reg_read(wm, AC97_VENDOR_ID1);
+	if (id != WM97XX_ID1) {
+		dev_err(dev, "Device with vendor %04x is not a wm97xx\n", id);
+		ret = -ENODEV;
+		goto alloc_err;
+	}
+
+	wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
+
+	wm->variant = WM97xx_GENERIC;
+
+	dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff);
+
+	switch (wm->id & 0xff) {
+#ifdef CONFIG_TOUCHSCREEN_WM9705
+	case 0x05:
+		wm->codec = &wm9705_codec;
+		break;
+#endif
+#ifdef CONFIG_TOUCHSCREEN_WM9712
+	case 0x12:
+		wm->codec = &wm9712_codec;
+		break;
+#endif
+#ifdef CONFIG_TOUCHSCREEN_WM9713
+	case 0x13:
+		wm->codec = &wm9713_codec;
+		break;
+#endif
+	default:
+		dev_err(wm->dev, "Support for wm97%02x not compiled in.\n",
+			wm->id & 0xff);
+		ret = -ENODEV;
+		goto alloc_err;
+	}
+
+	/* set up physical characteristics */
+	wm->codec->phy_init(wm);
+
+	/* load gpio cache */
+	wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG);
+	wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
+	wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
+	wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
+	wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+	wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
+
+	wm->input_dev = input_allocate_device();
+	if (wm->input_dev == NULL) {
+		ret = -ENOMEM;
+		goto alloc_err;
+	}
+
+	/* set up touch configuration */
+	wm->input_dev->name = "wm97xx touchscreen";
+	wm->input_dev->phys = "wm97xx";
+	wm->input_dev->open = wm97xx_ts_input_open;
+	wm->input_dev->close = wm97xx_ts_input_close;
+
+	__set_bit(EV_ABS, wm->input_dev->evbit);
+	__set_bit(EV_KEY, wm->input_dev->evbit);
+	__set_bit(BTN_TOUCH, wm->input_dev->keybit);
+
+	input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1],
+			     abs_x[2], 0);
+	input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1],
+			     abs_y[2], 0);
+	input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1],
+			     abs_p[2], 0);
+
+	input_set_drvdata(wm->input_dev, wm);
+	wm->input_dev->dev.parent = dev;
+
+	ret = input_register_device(wm->input_dev);
+	if (ret < 0)
+		goto dev_alloc_err;
+
+	/* register our battery device */
+	wm->battery_dev = platform_device_alloc("wm97xx-battery", -1);
+	if (!wm->battery_dev) {
+		ret = -ENOMEM;
+		goto batt_err;
+	}
+	platform_set_drvdata(wm->battery_dev, wm);
+	wm->battery_dev->dev.parent = dev;
+	wm->battery_dev->dev.platform_data = pdata;
+	ret = platform_device_add(wm->battery_dev);
+	if (ret < 0)
+		goto batt_reg_err;
+
+	/* register our extended touch device (for machine specific
+	 * extensions) */
+	wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
+	if (!wm->touch_dev) {
+		ret = -ENOMEM;
+		goto touch_err;
+	}
+	platform_set_drvdata(wm->touch_dev, wm);
+	wm->touch_dev->dev.parent = dev;
+	wm->touch_dev->dev.platform_data = pdata;
+	ret = platform_device_add(wm->touch_dev);
+	if (ret < 0)
+		goto touch_reg_err;
+
+	return ret;
+
+ touch_reg_err:
+	platform_device_put(wm->touch_dev);
+ touch_err:
+	platform_device_del(wm->battery_dev);
+ batt_reg_err:
+	platform_device_put(wm->battery_dev);
+ batt_err:
+	input_unregister_device(wm->input_dev);
+	wm->input_dev = NULL;
+ dev_alloc_err:
+	input_free_device(wm->input_dev);
+ alloc_err:
+	kfree(wm);
+
+	return ret;
+}
+
+static int wm97xx_remove(struct device *dev)
+{
+	struct wm97xx *wm = dev_get_drvdata(dev);
+
+	platform_device_unregister(wm->battery_dev);
+	platform_device_unregister(wm->touch_dev);
+	input_unregister_device(wm->input_dev);
+	kfree(wm);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm97xx_suspend(struct device *dev, pm_message_t state)
+{
+	struct wm97xx *wm = dev_get_drvdata(dev);
+	u16 reg;
+	int suspend_mode;
+
+	if (device_may_wakeup(&wm->input_dev->dev))
+		suspend_mode = wm->suspend_mode;
+	else
+		suspend_mode = 0;
+
+	if (wm->input_dev->users)
+		cancel_delayed_work_sync(&wm->ts_reader);
+
+	/* Power down the digitiser (bypassing the cache for resume) */
+	reg = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER2);
+	reg &= ~WM97XX_PRP_DET_DIG;
+	if (wm->input_dev->users)
+		reg |= suspend_mode;
+	wm->ac97->bus->ops->write(wm->ac97, AC97_WM97XX_DIGITISER2, reg);
+
+	/* WM9713 has an additional power bit - turn it off if there
+	 * are no users or if suspend mode is zero. */
+	if (wm->id == WM9713_ID2 &&
+	    (!wm->input_dev->users || !suspend_mode)) {
+		reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000;
+		wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
+	}
+
+	return 0;
+}
+
+static int wm97xx_resume(struct device *dev)
+{
+	struct wm97xx *wm = dev_get_drvdata(dev);
+
+	/* restore digitiser and gpios */
+	if (wm->id == WM9713_ID2) {
+		wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]);
+		wm97xx_reg_write(wm, 0x5a, wm->misc);
+		if (wm->input_dev->users) {
+			u16 reg;
+			reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff;
+			wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
+		}
+	}
+
+	wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig[1]);
+	wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2]);
+
+	wm97xx_reg_write(wm, AC97_GPIO_CFG, wm->gpio[0]);
+	wm97xx_reg_write(wm, AC97_GPIO_POLARITY, wm->gpio[1]);
+	wm97xx_reg_write(wm, AC97_GPIO_STICKY, wm->gpio[2]);
+	wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, wm->gpio[3]);
+	wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]);
+	wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]);
+
+	if (wm->input_dev->users && !wm->pen_irq) {
+		wm->ts_reader_interval = wm->ts_reader_min_interval;
+		queue_delayed_work(wm->ts_workq, &wm->ts_reader,
+				   wm->ts_reader_interval);
+	}
+
+	return 0;
+}
+
+#else
+#define wm97xx_suspend		NULL
+#define wm97xx_resume		NULL
+#endif
+
+/*
+ * Machine specific operations
+ */
+int wm97xx_register_mach_ops(struct wm97xx *wm,
+			     struct wm97xx_mach_ops *mach_ops)
+{
+	mutex_lock(&wm->codec_mutex);
+	if (wm->mach_ops) {
+		mutex_unlock(&wm->codec_mutex);
+		return -EINVAL;
+	}
+	wm->mach_ops = mach_ops;
+	mutex_unlock(&wm->codec_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops);
+
+void wm97xx_unregister_mach_ops(struct wm97xx *wm)
+{
+	mutex_lock(&wm->codec_mutex);
+	wm->mach_ops = NULL;
+	mutex_unlock(&wm->codec_mutex);
+}
+EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);
+
+static struct device_driver wm97xx_driver = {
+	.name =		"wm97xx-ts",
+	.bus =		&ac97_bus_type,
+	.owner =	THIS_MODULE,
+	.probe =	wm97xx_probe,
+	.remove =	wm97xx_remove,
+	.suspend =	wm97xx_suspend,
+	.resume =	wm97xx_resume,
+};
+
+static int __init wm97xx_init(void)
+{
+	return driver_register(&wm97xx_driver);
+}
+
+static void __exit wm97xx_exit(void)
+{
+	driver_unregister(&wm97xx_driver);
+}
+
+module_init(wm97xx_init);
+module_exit(wm97xx_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/zylonite-wm97xx.c b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/zylonite-wm97xx.c
new file mode 100644
index 0000000..bf0869a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/input/touchscreen/zylonite-wm97xx.c
@@ -0,0 +1,232 @@
+/*
+ * zylonite-wm97xx.c  --  Zylonite Continuous Touch screen driver
+ *
+ * Copyright 2004, 2007, 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ * Parts Copyright : Ian Molton <spyro@f2s.com>
+ *                   Andrew Zabolotny <zap@homelink.ru>
+ *
+ *  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.
+ *
+ * Notes:
+ *     This is a wm97xx extended touch driver supporting interrupt driven
+ *     and continuous operation on Marvell Zylonite development systems
+ *     (which have a WM9713 on board).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/wm97xx.h>
+
+#include <mach/hardware.h>
+#include <mach/mfp.h>
+#include <mach/regs-ac97.h>
+
+struct continuous {
+	u16 id;    /* codec id */
+	u8 code;   /* continuous code */
+	u8 reads;  /* number of coord reads per read cycle */
+	u32 speed; /* number of coords per second */
+};
+
+#define WM_READS(sp) ((sp / HZ) + 1)
+
+static const struct continuous cinfo[] = {
+	{ WM9713_ID2, 0, WM_READS(94),  94  },
+	{ WM9713_ID2, 1, WM_READS(120), 120 },
+	{ WM9713_ID2, 2, WM_READS(154), 154 },
+	{ WM9713_ID2, 3, WM_READS(188), 188 },
+};
+
+/* continuous speed index */
+static int sp_idx;
+
+/*
+ * Pen sampling frequency (Hz) in continuous mode.
+ */
+static int cont_rate = 200;
+module_param(cont_rate, int, 0);
+MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
+
+/*
+ * Pressure readback.
+ *
+ * Set to 1 to read back pen down pressure
+ */
+static int pressure;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
+
+/*
+ * AC97 touch data slot.
+ *
+ * Touch screen readback data ac97 slot
+ */
+static int ac97_touch_slot = 5;
+module_param(ac97_touch_slot, int, 0);
+MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
+
+
+/* flush AC97 slot 5 FIFO machines */
+static void wm97xx_acc_pen_up(struct wm97xx *wm)
+{
+	int i;
+
+	msleep(1);
+
+	for (i = 0; i < 16; i++)
+		MODR;
+}
+
+static int wm97xx_acc_pen_down(struct wm97xx *wm)
+{
+	u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
+	int reads = 0;
+	static u16 last, tries;
+
+	/* When the AC97 queue has been drained we need to allow time
+	 * to buffer up samples otherwise we end up spinning polling
+	 * for samples.  The controller can't have a suitably low
+	 * threshold set to use the notifications it gives.
+	 */
+	msleep(1);
+
+	if (tries > 5) {
+		tries = 0;
+		return RC_PENUP;
+	}
+
+	x = MODR;
+	if (x == last) {
+		tries++;
+		return RC_AGAIN;
+	}
+	last = x;
+	do {
+		if (reads)
+			x = MODR;
+		y = MODR;
+		if (pressure)
+			p = MODR;
+
+		dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
+			x, y, p);
+
+		/* are samples valid */
+		if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
+		    (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
+		    (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
+			goto up;
+
+		/* coordinate is good */
+		tries = 0;
+		input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
+		input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
+		input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
+		input_report_key(wm->input_dev, BTN_TOUCH, (p != 0));
+		input_sync(wm->input_dev);
+		reads++;
+	} while (reads < cinfo[sp_idx].reads);
+up:
+	return RC_PENDOWN | RC_AGAIN;
+}
+
+static int wm97xx_acc_startup(struct wm97xx *wm)
+{
+	int idx;
+
+	/* check we have a codec */
+	if (wm->ac97 == NULL)
+		return -ENODEV;
+
+	/* Go you big red fire engine */
+	for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
+		if (wm->id != cinfo[idx].id)
+			continue;
+		sp_idx = idx;
+		if (cont_rate <= cinfo[idx].speed)
+			break;
+	}
+	wm->acc_rate = cinfo[sp_idx].code;
+	wm->acc_slot = ac97_touch_slot;
+	dev_info(wm->dev,
+		 "zylonite accelerated touchscreen driver, %d samples/sec\n",
+		 cinfo[sp_idx].speed);
+
+	return 0;
+}
+
+static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
+{
+	if (enable)
+		enable_irq(wm->pen_irq);
+	else
+		disable_irq_nosync(wm->pen_irq);
+}
+
+static struct wm97xx_mach_ops zylonite_mach_ops = {
+	.acc_enabled	= 1,
+	.acc_pen_up	= wm97xx_acc_pen_up,
+	.acc_pen_down	= wm97xx_acc_pen_down,
+	.acc_startup	= wm97xx_acc_startup,
+	.irq_enable	= wm97xx_irq_enable,
+	.irq_gpio	= WM97XX_GPIO_2,
+};
+
+static int zylonite_wm97xx_probe(struct platform_device *pdev)
+{
+	struct wm97xx *wm = platform_get_drvdata(pdev);
+	int gpio_touch_irq;
+
+	if (cpu_is_pxa320())
+		gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO15);
+	else
+		gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26);
+
+	wm->pen_irq = gpio_to_irq(gpio_touch_irq);
+	irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
+
+	wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
+			   WM97XX_GPIO_POL_HIGH,
+			   WM97XX_GPIO_STICKY,
+			   WM97XX_GPIO_WAKE);
+	wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
+			   WM97XX_GPIO_POL_HIGH,
+			   WM97XX_GPIO_NOTSTICKY,
+			   WM97XX_GPIO_NOWAKE);
+
+	return wm97xx_register_mach_ops(wm, &zylonite_mach_ops);
+}
+
+static int zylonite_wm97xx_remove(struct platform_device *pdev)
+{
+	struct wm97xx *wm = platform_get_drvdata(pdev);
+
+	wm97xx_unregister_mach_ops(wm);
+
+	return 0;
+}
+
+static struct platform_driver zylonite_wm97xx_driver = {
+	.probe	= zylonite_wm97xx_probe,
+	.remove	= zylonite_wm97xx_remove,
+	.driver	= {
+		.name	= "wm97xx-touch",
+	},
+};
+module_platform_driver(zylonite_wm97xx_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("wm97xx continuous touch driver for Zylonite");
+MODULE_LICENSE("GPL");