summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/input/touchscreen
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/touchscreen')
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/88pm860x-ts.c226
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/Kconfig854
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/Makefile72
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ad7877.c868
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ad7879-i2c.c109
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ad7879-spi.c165
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ad7879.c649
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ad7879.h30
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ads7846.c1440
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/atmel-wm97xx.c449
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/atmel_mxt_ts.c1275
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/atmel_tsadcc.c359
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/auo-pixcir-ts.c642
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/bu21013_ts.c659
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/cy8ctmg110_ts.c357
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_core.c625
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_core.h149
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_i2c.c136
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_spi.c200
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/da9034-ts.c387
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/dynapro.c206
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/eeti_ts.c327
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/egalax_ts.c292
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/elo.c423
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/fujitsu_ts.c189
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/gunze.c204
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/h3600_ts_input.c494
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/hampshire.c205
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/hp680_ts_input.c127
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/htcpen.c250
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ili210x.c360
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/inexio.c207
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/intel-mid-touch.c671
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/jornada720_ts.c176
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/lpc32xx_ts.c400
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/mainstone-wm97xx.c310
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/max11801_ts.c262
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/mc13783_ts.c268
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/mcs5000_ts.c310
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/migor_ts.c249
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/mk712.c219
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/mtouch.c220
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/pcap_ts.c260
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/penmount.c335
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/pixcir_i2c_ts.c229
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/s3c2410_ts.c441
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/st1232.c275
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/stmpe-ts.c387
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/synaptics_i2c_rmi.c675
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ti_tscadc.c486
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/tnetv107x-ts.c386
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/touchit213.c234
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/touchright.c194
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/touchwin.c201
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/tps6507x-ts.c377
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/tsc2005.c754
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/tsc2007.c406
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/tsc40.c184
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/ucb1400_ts.c467
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/usbtouchscreen.c1690
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/w90p910_ts.c339
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/wacom_w8001.c608
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/wm831x-ts.c410
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/wm9705.c350
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/wm9712.c467
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/wm9713.c481
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/wm97xx-core.c848
-rw-r--r--ANDROID_3.4.5/drivers/input/touchscreen/zylonite-wm97xx.c232
68 files changed, 27736 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/88pm860x-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/88pm860x-ts.c
new file mode 100644
index 00000000..05f30b73
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig b/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig
new file mode 100644
index 00000000..1e7c563c
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/touchscreen/Kconfig
@@ -0,0 +1,854 @@
+#
+# 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_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/ANDROID_3.4.5/drivers/input/touchscreen/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/Makefile
new file mode 100644
index 00000000..175d6414
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/touchscreen/Makefile
@@ -0,0 +1,72 @@
+#
+# 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_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/ANDROID_3.4.5/drivers/input/touchscreen/ad7877.c b/ANDROID_3.4.5/drivers/input/touchscreen/ad7877.c
new file mode 100644
index 00000000..2c769210
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/ad7879-i2c.c b/ANDROID_3.4.5/drivers/input/touchscreen/ad7879-i2c.c
new file mode 100644
index 00000000..3054354d
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/ad7879-spi.c b/ANDROID_3.4.5/drivers/input/touchscreen/ad7879-spi.c
new file mode 100644
index 00000000..db49abf0
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/ad7879.c b/ANDROID_3.4.5/drivers/input/touchscreen/ad7879.c
new file mode 100644
index 00000000..e2482b40
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/ad7879.h b/ANDROID_3.4.5/drivers/input/touchscreen/ad7879.h
new file mode 100644
index 00000000..6fd13c48
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/ads7846.c b/ANDROID_3.4.5/drivers/input/touchscreen/ads7846.c
new file mode 100644
index 00000000..f02028ec
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/atmel-wm97xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/atmel-wm97xx.c
new file mode 100644
index 00000000..c5c2dbb9
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/atmel_mxt_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/atmel_mxt_ts.c
new file mode 100644
index 00000000..19d4ea65
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/atmel_tsadcc.c b/ANDROID_3.4.5/drivers/input/touchscreen/atmel_tsadcc.c
new file mode 100644
index 00000000..201b2d2e
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/auo-pixcir-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/auo-pixcir-ts.c
new file mode 100644
index 00000000..c7047b6b
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/bu21013_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/bu21013_ts.c
new file mode 100644
index 00000000..f2d03c06
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/cy8ctmg110_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/cy8ctmg110_ts.c
new file mode 100644
index 00000000..237753ad
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_core.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 00000000..f030d9ec
--- /dev/null
+++ b/ANDROID_3.4.5/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, sizeof(bl_command));
+
+ 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/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_core.h b/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_core.h
new file mode 100644
index 00000000..1aa3c696
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_i2c.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100644
index 00000000..2af1d0c5
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_spi.c b/ANDROID_3.4.5/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100644
index 00000000..9f263410
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/da9034-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/da9034-ts.c
new file mode 100644
index 00000000..36b65cf1
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/dynapro.c b/ANDROID_3.4.5/drivers/input/touchscreen/dynapro.c
new file mode 100644
index 00000000..45535390
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/eeti_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/eeti_ts.c
new file mode 100644
index 00000000..503c7096
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/touchscreen/eeti_ts.c
@@ -0,0 +1,327 @@
+/*
+ * 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, 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(irq_to_gpio(priv->irq)) == 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;
+ 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 = client->irq;
+
+ pdata = client->dev.platform_data;
+
+ 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 err1;
+
+ 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 err2;
+ }
+
+ /*
+ * 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;
+
+err2:
+ input_unregister_device(input);
+ input = NULL; /* so we dont try to free it below */
+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/ANDROID_3.4.5/drivers/input/touchscreen/egalax_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/egalax_ts.c
new file mode 100644
index 00000000..70524dd3
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/elo.c b/ANDROID_3.4.5/drivers/input/touchscreen/elo.c
new file mode 100644
index 00000000..486d31ba
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/fujitsu_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/fujitsu_ts.c
new file mode 100644
index 00000000..80b21800
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/gunze.c b/ANDROID_3.4.5/drivers/input/touchscreen/gunze.c
new file mode 100644
index 00000000..a54f90e0
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/h3600_ts_input.c b/ANDROID_3.4.5/drivers/input/touchscreen/h3600_ts_input.c
new file mode 100644
index 00000000..6107e563
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/hampshire.c b/ANDROID_3.4.5/drivers/input/touchscreen/hampshire.c
new file mode 100644
index 00000000..2da6cc31
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/hp680_ts_input.c b/ANDROID_3.4.5/drivers/input/touchscreen/hp680_ts_input.c
new file mode 100644
index 00000000..85cf9bee
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/htcpen.c b/ANDROID_3.4.5/drivers/input/touchscreen/htcpen.c
new file mode 100644
index 00000000..d13143b6
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/ili210x.c b/ANDROID_3.4.5/drivers/input/touchscreen/ili210x.c
new file mode 100644
index 00000000..c0044175
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/inexio.c b/ANDROID_3.4.5/drivers/input/touchscreen/inexio.c
new file mode 100644
index 00000000..192ade0a
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/intel-mid-touch.c b/ANDROID_3.4.5/drivers/input/touchscreen/intel-mid-touch.c
new file mode 100644
index 00000000..3cd7a837
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/jornada720_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/jornada720_ts.c
new file mode 100644
index 00000000..d9be6eac
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/lpc32xx_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/lpc32xx_ts.c
new file mode 100644
index 00000000..afcd0691
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/mainstone-wm97xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/mainstone-wm97xx.c
new file mode 100644
index 00000000..7d2b2136
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/max11801_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/max11801_ts.c
new file mode 100644
index 00000000..4eab50b8
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/mc13783_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/mc13783_ts.c
new file mode 100644
index 00000000..48dc5b0d
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/mcs5000_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/mcs5000_ts.c
new file mode 100644
index 00000000..b5285118
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/migor_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/migor_ts.c
new file mode 100644
index 00000000..c038db93
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/mk712.c b/ANDROID_3.4.5/drivers/input/touchscreen/mk712.c
new file mode 100644
index 00000000..36e57dea
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/mtouch.c b/ANDROID_3.4.5/drivers/input/touchscreen/mtouch.c
new file mode 100644
index 00000000..90772284
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/pcap_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/pcap_ts.c
new file mode 100644
index 00000000..f57aeb80
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/penmount.c b/ANDROID_3.4.5/drivers/input/touchscreen/penmount.c
new file mode 100644
index 00000000..4c012fb2
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/pixcir_i2c_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/pixcir_i2c_ts.c
new file mode 100644
index 00000000..72f6ba3a
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/s3c2410_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/s3c2410_ts.c
new file mode 100644
index 00000000..bf1a0640
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/st1232.c b/ANDROID_3.4.5/drivers/input/touchscreen/st1232.c
new file mode 100644
index 00000000..cbbf71b2
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/stmpe-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/stmpe-ts.c
new file mode 100644
index 00000000..692b6857
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/synaptics_i2c_rmi.c b/ANDROID_3.4.5/drivers/input/touchscreen/synaptics_i2c_rmi.c
new file mode 100644
index 00000000..5729602c
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/touchscreen/synaptics_i2c_rmi.c
@@ -0,0 +1,675 @@
+/* drivers/input/keyboard/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/module.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/synaptics_i2c_rmi.h>
+
+static struct workqueue_struct *synaptics_wq;
+
+struct synaptics_ts_data {
+ uint16_t addr;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ int use_irq;
+ bool has_relative_report;
+ struct hrtimer timer;
+ struct work_struct work;
+ uint16_t max[2];
+ int snap_state[2][2];
+ int snap_down_on[2];
+ int snap_down_off[2];
+ int snap_up_on[2];
+ int snap_up_off[2];
+ int snap_down[2];
+ int snap_up[2];
+ uint32_t flags;
+ int reported_finger_count;
+ int8_t sensitivity_adjust;
+ int (*power)(int on);
+ struct early_suspend early_suspend;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void synaptics_ts_early_suspend(struct early_suspend *h);
+static void synaptics_ts_late_resume(struct early_suspend *h);
+#endif
+
+static int synaptics_init_panel(struct synaptics_ts_data *ts)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x10); /* page select = 0x10 */
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n");
+ goto err_page_select_failed;
+ }
+ ret = i2c_smbus_write_byte_data(ts->client, 0x41, 0x04); /* Set "No Clip Z" */
+ if (ret < 0)
+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for No Clip Z\n");
+
+ ret = i2c_smbus_write_byte_data(ts->client, 0x44,
+ ts->sensitivity_adjust);
+ if (ret < 0)
+ pr_err("synaptics_ts: failed to set Sensitivity Adjust\n");
+
+err_page_select_failed:
+ ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x04); /* page select = 0x04 */
+ if (ret < 0)
+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n");
+ ret = i2c_smbus_write_byte_data(ts->client, 0xf0, 0x81); /* normal operation, 80 reports per second */
+ if (ret < 0)
+ printk(KERN_ERR "synaptics_ts_resume: i2c_smbus_write_byte_data failed\n");
+ return ret;
+}
+
+static void synaptics_ts_work_func(struct work_struct *work)
+{
+ int i;
+ int ret;
+ int bad_data = 0;
+ struct i2c_msg msg[2];
+ uint8_t start_reg;
+ uint8_t buf[15];
+ struct synaptics_ts_data *ts = container_of(work, struct synaptics_ts_data, work);
+ int buf_len = ts->has_relative_report ? 15 : 13;
+
+ msg[0].addr = ts->client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &start_reg;
+ start_reg = 0x00;
+ msg[1].addr = ts->client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = buf_len;
+ msg[1].buf = buf;
+
+ /* printk("synaptics_ts_work_func\n"); */
+ for (i = 0; i < ((ts->use_irq && !bad_data) ? 1 : 10); i++) {
+ ret = i2c_transfer(ts->client->adapter, msg, 2);
+ if (ret < 0) {
+ printk(KERN_ERR "synaptics_ts_work_func: i2c_transfer failed\n");
+ bad_data = 1;
+ } else {
+ /* printk("synaptics_ts_work_func: %x %x %x %x %x %x" */
+ /* " %x %x %x %x %x %x %x %x %x, ret %d\n", */
+ /* buf[0], buf[1], buf[2], buf[3], */
+ /* buf[4], buf[5], buf[6], buf[7], */
+ /* buf[8], buf[9], buf[10], buf[11], */
+ /* buf[12], buf[13], buf[14], ret); */
+ if ((buf[buf_len - 1] & 0xc0) != 0x40) {
+ printk(KERN_WARNING "synaptics_ts_work_func:"
+ " bad read %x %x %x %x %x %x %x %x %x"
+ " %x %x %x %x %x %x, ret %d\n",
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7],
+ buf[8], buf[9], buf[10], buf[11],
+ buf[12], buf[13], buf[14], ret);
+ if (bad_data)
+ synaptics_init_panel(ts);
+ bad_data = 1;
+ continue;
+ }
+ bad_data = 0;
+ if ((buf[buf_len - 1] & 1) == 0) {
+ /* printk("read %d coordinates\n", i); */
+ break;
+ } else {
+ int pos[2][2];
+ int f, a;
+ int base;
+ /* int x = buf[3] | (uint16_t)(buf[2] & 0x1f) << 8; */
+ /* int y = buf[5] | (uint16_t)(buf[4] & 0x1f) << 8; */
+ int z = buf[1];
+ int w = buf[0] >> 4;
+ int finger = buf[0] & 7;
+
+ /* int x2 = buf[3+6] | (uint16_t)(buf[2+6] & 0x1f) << 8; */
+ /* int y2 = buf[5+6] | (uint16_t)(buf[4+6] & 0x1f) << 8; */
+ /* int z2 = buf[1+6]; */
+ /* int w2 = buf[0+6] >> 4; */
+ /* int finger2 = buf[0+6] & 7; */
+
+ /* int dx = (int8_t)buf[12]; */
+ /* int dy = (int8_t)buf[13]; */
+ int finger2_pressed;
+
+ /* printk("x %4d, y %4d, z %3d, w %2d, F %d, 2nd: x %4d, y %4d, z %3d, w %2d, F %d, dx %4d, dy %4d\n", */
+ /* x, y, z, w, finger, */
+ /* x2, y2, z2, w2, finger2, */
+ /* dx, dy); */
+
+ base = 2;
+ for (f = 0; f < 2; f++) {
+ uint32_t flip_flag = SYNAPTICS_FLIP_X;
+ for (a = 0; a < 2; a++) {
+ int p = buf[base + 1];
+ p |= (uint16_t)(buf[base] & 0x1f) << 8;
+ if (ts->flags & flip_flag)
+ p = ts->max[a] - p;
+ if (ts->flags & SYNAPTICS_SNAP_TO_INACTIVE_EDGE) {
+ if (ts->snap_state[f][a]) {
+ if (p <= ts->snap_down_off[a])
+ p = ts->snap_down[a];
+ else if (p >= ts->snap_up_off[a])
+ p = ts->snap_up[a];
+ else
+ ts->snap_state[f][a] = 0;
+ } else {
+ if (p <= ts->snap_down_on[a]) {
+ p = ts->snap_down[a];
+ ts->snap_state[f][a] = 1;
+ } else if (p >= ts->snap_up_on[a]) {
+ p = ts->snap_up[a];
+ ts->snap_state[f][a] = 1;
+ }
+ }
+ }
+ pos[f][a] = p;
+ base += 2;
+ flip_flag <<= 1;
+ }
+ base += 2;
+ if (ts->flags & SYNAPTICS_SWAP_XY)
+ swap(pos[f][0], pos[f][1]);
+ }
+ if (z) {
+ input_report_abs(ts->input_dev, ABS_X, pos[0][0]);
+ input_report_abs(ts->input_dev, ABS_Y, pos[0][1]);
+ }
+ input_report_abs(ts->input_dev, ABS_PRESSURE, z);
+ input_report_abs(ts->input_dev, ABS_TOOL_WIDTH, w);
+ input_report_key(ts->input_dev, BTN_TOUCH, finger);
+ finger2_pressed = finger > 1 && finger != 7;
+ input_report_key(ts->input_dev, BTN_2, finger2_pressed);
+ if (finger2_pressed) {
+ input_report_abs(ts->input_dev, ABS_HAT0X, pos[1][0]);
+ input_report_abs(ts->input_dev, ABS_HAT0Y, pos[1][1]);
+ }
+
+ if (!finger)
+ z = 0;
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[0][0]);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[0][1]);
+ input_mt_sync(ts->input_dev);
+ if (finger2_pressed) {
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[1][0]);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[1][1]);
+ input_mt_sync(ts->input_dev);
+ } else if (ts->reported_finger_count > 1) {
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
+ input_mt_sync(ts->input_dev);
+ }
+ ts->reported_finger_count = finger;
+ input_sync(ts->input_dev);
+ }
+ }
+ }
+ if (ts->use_irq)
+ enable_irq(ts->client->irq);
+}
+
+static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer)
+{
+ struct synaptics_ts_data *ts = container_of(timer, struct synaptics_ts_data, timer);
+ /* printk("synaptics_ts_timer_func\n"); */
+
+ queue_work(synaptics_wq, &ts->work);
+
+ hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
+ return HRTIMER_NORESTART;
+}
+
+static irqreturn_t synaptics_ts_irq_handler(int irq, void *dev_id)
+{
+ struct synaptics_ts_data *ts = dev_id;
+
+ /* printk("synaptics_ts_irq_handler\n"); */
+ disable_irq_nosync(ts->client->irq);
+ queue_work(synaptics_wq, &ts->work);
+ return IRQ_HANDLED;
+}
+
+static int synaptics_ts_probe(
+ struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct synaptics_ts_data *ts;
+ uint8_t buf0[4];
+ uint8_t buf1[8];
+ struct i2c_msg msg[2];
+ int ret = 0;
+ uint16_t max_x, max_y;
+ int fuzz_x, fuzz_y, fuzz_p, fuzz_w;
+ struct synaptics_i2c_rmi_platform_data *pdata;
+ unsigned long irqflags;
+ int inactive_area_left;
+ int inactive_area_right;
+ int inactive_area_top;
+ int inactive_area_bottom;
+ int snap_left_on;
+ int snap_left_off;
+ int snap_right_on;
+ int snap_right_off;
+ int snap_top_on;
+ int snap_top_off;
+ int snap_bottom_on;
+ int snap_bottom_off;
+ uint32_t panel_version;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ printk(KERN_ERR "synaptics_ts_probe: need I2C_FUNC_I2C\n");
+ ret = -ENODEV;
+ goto err_check_functionality_failed;
+ }
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts == NULL) {
+ ret = -ENOMEM;
+ goto err_alloc_data_failed;
+ }
+ INIT_WORK(&ts->work, synaptics_ts_work_func);
+ ts->client = client;
+ i2c_set_clientdata(client, ts);
+ pdata = client->dev.platform_data;
+ if (pdata)
+ ts->power = pdata->power;
+ if (ts->power) {
+ ret = ts->power(1);
+ if (ret < 0) {
+ printk(KERN_ERR "synaptics_ts_probe power on failed\n");
+ goto err_power_failed;
+ }
+ }
+
+ ret = i2c_smbus_write_byte_data(ts->client, 0xf4, 0x01); /* device command = reset */
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_write_byte_data failed\n");
+ /* fail? */
+ }
+ {
+ int retry = 10;
+ while (retry-- > 0) {
+ ret = i2c_smbus_read_byte_data(ts->client, 0xe4);
+ if (ret >= 0)
+ break;
+ msleep(100);
+ }
+ }
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n");
+ goto err_detect_failed;
+ }
+ printk(KERN_INFO "synaptics_ts_probe: Product Major Version %x\n", ret);
+ panel_version = ret << 8;
+ ret = i2c_smbus_read_byte_data(ts->client, 0xe5);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n");
+ goto err_detect_failed;
+ }
+ printk(KERN_INFO "synaptics_ts_probe: Product Minor Version %x\n", ret);
+ panel_version |= ret;
+
+ ret = i2c_smbus_read_byte_data(ts->client, 0xe3);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n");
+ goto err_detect_failed;
+ }
+ printk(KERN_INFO "synaptics_ts_probe: product property %x\n", ret);
+
+ if (pdata) {
+ while (pdata->version > panel_version)
+ pdata++;
+ ts->flags = pdata->flags;
+ ts->sensitivity_adjust = pdata->sensitivity_adjust;
+ irqflags = pdata->irqflags;
+ inactive_area_left = pdata->inactive_left;
+ inactive_area_right = pdata->inactive_right;
+ inactive_area_top = pdata->inactive_top;
+ inactive_area_bottom = pdata->inactive_bottom;
+ snap_left_on = pdata->snap_left_on;
+ snap_left_off = pdata->snap_left_off;
+ snap_right_on = pdata->snap_right_on;
+ snap_right_off = pdata->snap_right_off;
+ snap_top_on = pdata->snap_top_on;
+ snap_top_off = pdata->snap_top_off;
+ snap_bottom_on = pdata->snap_bottom_on;
+ snap_bottom_off = pdata->snap_bottom_off;
+ fuzz_x = pdata->fuzz_x;
+ fuzz_y = pdata->fuzz_y;
+ fuzz_p = pdata->fuzz_p;
+ fuzz_w = pdata->fuzz_w;
+ } else {
+ irqflags = 0;
+ inactive_area_left = 0;
+ inactive_area_right = 0;
+ inactive_area_top = 0;
+ inactive_area_bottom = 0;
+ snap_left_on = 0;
+ snap_left_off = 0;
+ snap_right_on = 0;
+ snap_right_off = 0;
+ snap_top_on = 0;
+ snap_top_off = 0;
+ snap_bottom_on = 0;
+ snap_bottom_off = 0;
+ fuzz_x = 0;
+ fuzz_y = 0;
+ fuzz_p = 0;
+ fuzz_w = 0;
+ }
+
+ ret = i2c_smbus_read_byte_data(ts->client, 0xf0);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n");
+ goto err_detect_failed;
+ }
+ printk(KERN_INFO "synaptics_ts_probe: device control %x\n", ret);
+
+ ret = i2c_smbus_read_byte_data(ts->client, 0xf1);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_byte_data failed\n");
+ goto err_detect_failed;
+ }
+ printk(KERN_INFO "synaptics_ts_probe: interrupt enable %x\n", ret);
+
+ ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0); /* disable interrupt */
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_write_byte_data failed\n");
+ goto err_detect_failed;
+ }
+
+ msg[0].addr = ts->client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = buf0;
+ buf0[0] = 0xe0;
+ msg[1].addr = ts->client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 8;
+ msg[1].buf = buf1;
+ ret = i2c_transfer(ts->client->adapter, msg, 2);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_transfer failed\n");
+ goto err_detect_failed;
+ }
+ printk(KERN_INFO "synaptics_ts_probe: 0xe0: %x %x %x %x %x %x %x %x\n",
+ buf1[0], buf1[1], buf1[2], buf1[3],
+ buf1[4], buf1[5], buf1[6], buf1[7]);
+
+ ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x10); /* page select = 0x10 */
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n");
+ goto err_detect_failed;
+ }
+ ret = i2c_smbus_read_word_data(ts->client, 0x02);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_word_data failed\n");
+ goto err_detect_failed;
+ }
+ ts->has_relative_report = !(ret & 0x100);
+ printk(KERN_INFO "synaptics_ts_probe: Sensor properties %x\n", ret);
+ ret = i2c_smbus_read_word_data(ts->client, 0x04);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_word_data failed\n");
+ goto err_detect_failed;
+ }
+ ts->max[0] = max_x = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8);
+ ret = i2c_smbus_read_word_data(ts->client, 0x06);
+ if (ret < 0) {
+ printk(KERN_ERR "i2c_smbus_read_word_data failed\n");
+ goto err_detect_failed;
+ }
+ ts->max[1] = max_y = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8);
+ if (ts->flags & SYNAPTICS_SWAP_XY)
+ swap(max_x, max_y);
+
+ ret = synaptics_init_panel(ts); /* will also switch back to page 0x04 */
+ if (ret < 0) {
+ printk(KERN_ERR "synaptics_init_panel failed\n");
+ goto err_detect_failed;
+ }
+
+ ts->input_dev = input_allocate_device();
+ if (ts->input_dev == NULL) {
+ ret = -ENOMEM;
+ printk(KERN_ERR "synaptics_ts_probe: Failed to allocate input device\n");
+ goto err_input_dev_alloc_failed;
+ }
+ ts->input_dev->name = "synaptics-rmi-touchscreen";
+ set_bit(EV_SYN, ts->input_dev->evbit);
+ set_bit(EV_KEY, ts->input_dev->evbit);
+ set_bit(BTN_TOUCH, ts->input_dev->keybit);
+ set_bit(BTN_2, ts->input_dev->keybit);
+ set_bit(EV_ABS, ts->input_dev->evbit);
+ inactive_area_left = inactive_area_left * max_x / 0x10000;
+ inactive_area_right = inactive_area_right * max_x / 0x10000;
+ inactive_area_top = inactive_area_top * max_y / 0x10000;
+ inactive_area_bottom = inactive_area_bottom * max_y / 0x10000;
+ snap_left_on = snap_left_on * max_x / 0x10000;
+ snap_left_off = snap_left_off * max_x / 0x10000;
+ snap_right_on = snap_right_on * max_x / 0x10000;
+ snap_right_off = snap_right_off * max_x / 0x10000;
+ snap_top_on = snap_top_on * max_y / 0x10000;
+ snap_top_off = snap_top_off * max_y / 0x10000;
+ snap_bottom_on = snap_bottom_on * max_y / 0x10000;
+ snap_bottom_off = snap_bottom_off * max_y / 0x10000;
+ fuzz_x = fuzz_x * max_x / 0x10000;
+ fuzz_y = fuzz_y * max_y / 0x10000;
+ ts->snap_down[!!(ts->flags & SYNAPTICS_SWAP_XY)] = -inactive_area_left;
+ ts->snap_up[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x + inactive_area_right;
+ ts->snap_down[!(ts->flags & SYNAPTICS_SWAP_XY)] = -inactive_area_top;
+ ts->snap_up[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y + inactive_area_bottom;
+ ts->snap_down_on[!!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_left_on;
+ ts->snap_down_off[!!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_left_off;
+ ts->snap_up_on[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x - snap_right_on;
+ ts->snap_up_off[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x - snap_right_off;
+ ts->snap_down_on[!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_top_on;
+ ts->snap_down_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_top_off;
+ ts->snap_up_on[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_on;
+ ts->snap_up_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_off;
+ printk(KERN_INFO "synaptics_ts_probe: max_x %d, max_y %d\n", max_x, max_y);
+ printk(KERN_INFO "synaptics_ts_probe: inactive_x %d %d, inactive_y %d %d\n",
+ inactive_area_left, inactive_area_right,
+ inactive_area_top, inactive_area_bottom);
+ printk(KERN_INFO "synaptics_ts_probe: snap_x %d-%d %d-%d, snap_y %d-%d %d-%d\n",
+ snap_left_on, snap_left_off, snap_right_on, snap_right_off,
+ snap_top_on, snap_top_off, snap_bottom_on, snap_bottom_off);
+ input_set_abs_params(ts->input_dev, ABS_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0);
+ input_set_abs_params(ts->input_dev, ABS_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0);
+ input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, fuzz_p, 0);
+ input_set_abs_params(ts->input_dev, ABS_TOOL_WIDTH, 0, 15, fuzz_w, 0);
+ input_set_abs_params(ts->input_dev, ABS_HAT0X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0);
+ input_set_abs_params(ts->input_dev, ABS_HAT0Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, fuzz_p, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 15, fuzz_w, 0);
+ /* ts->input_dev->name = ts->keypad_info->name; */
+ ret = input_register_device(ts->input_dev);
+ if (ret) {
+ printk(KERN_ERR "synaptics_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+ goto err_input_register_device_failed;
+ }
+ if (client->irq) {
+ ret = request_irq(client->irq, synaptics_ts_irq_handler, irqflags, client->name, ts);
+ if (ret == 0) {
+ ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0x01); /* enable abs int */
+ if (ret)
+ free_irq(client->irq, ts);
+ }
+ if (ret == 0)
+ ts->use_irq = 1;
+ else
+ dev_err(&client->dev, "request_irq failed\n");
+ }
+ if (!ts->use_irq) {
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ts->timer.function = synaptics_ts_timer_func;
+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ }
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->early_suspend.suspend = synaptics_ts_early_suspend;
+ ts->early_suspend.resume = synaptics_ts_late_resume;
+ register_early_suspend(&ts->early_suspend);
+#endif
+
+ printk(KERN_INFO "synaptics_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+
+ return 0;
+
+err_input_register_device_failed:
+ input_free_device(ts->input_dev);
+
+err_input_dev_alloc_failed:
+err_detect_failed:
+err_power_failed:
+ kfree(ts);
+err_alloc_data_failed:
+err_check_functionality_failed:
+ return ret;
+}
+
+static int synaptics_ts_remove(struct i2c_client *client)
+{
+ struct synaptics_ts_data *ts = i2c_get_clientdata(client);
+ unregister_early_suspend(&ts->early_suspend);
+ if (ts->use_irq)
+ free_irq(client->irq, ts);
+ else
+ hrtimer_cancel(&ts->timer);
+ input_unregister_device(ts->input_dev);
+ kfree(ts);
+ return 0;
+}
+
+static int synaptics_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ int ret;
+ struct synaptics_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts->use_irq)
+ disable_irq(client->irq);
+ else
+ hrtimer_cancel(&ts->timer);
+ ret = cancel_work_sync(&ts->work);
+ if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */
+ enable_irq(client->irq);
+ ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0); /* disable interrupt */
+ if (ret < 0)
+ printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n");
+
+ ret = i2c_smbus_write_byte_data(client, 0xf0, 0x86); /* deep sleep */
+ if (ret < 0)
+ printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n");
+ if (ts->power) {
+ ret = ts->power(0);
+ if (ret < 0)
+ printk(KERN_ERR "synaptics_ts_resume power off failed\n");
+ }
+ return 0;
+}
+
+static int synaptics_ts_resume(struct i2c_client *client)
+{
+ int ret;
+ struct synaptics_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts->power) {
+ ret = ts->power(1);
+ if (ret < 0)
+ printk(KERN_ERR "synaptics_ts_resume power on failed\n");
+ }
+
+ synaptics_init_panel(ts);
+
+ if (ts->use_irq)
+ enable_irq(client->irq);
+
+ if (!ts->use_irq)
+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ else
+ i2c_smbus_write_byte_data(ts->client, 0xf1, 0x01); /* enable abs int */
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void synaptics_ts_early_suspend(struct early_suspend *h)
+{
+ struct synaptics_ts_data *ts;
+ ts = container_of(h, struct synaptics_ts_data, early_suspend);
+ synaptics_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void synaptics_ts_late_resume(struct early_suspend *h)
+{
+ struct synaptics_ts_data *ts;
+ ts = container_of(h, struct synaptics_ts_data, early_suspend);
+ synaptics_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id synaptics_ts_id[] = {
+ { SYNAPTICS_I2C_RMI_NAME, 0 },
+ { }
+};
+
+static struct i2c_driver synaptics_ts_driver = {
+ .probe = synaptics_ts_probe,
+ .remove = synaptics_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = synaptics_ts_suspend,
+ .resume = synaptics_ts_resume,
+#endif
+ .id_table = synaptics_ts_id,
+ .driver = {
+ .name = SYNAPTICS_I2C_RMI_NAME,
+ },
+};
+
+static int __devinit synaptics_ts_init(void)
+{
+ synaptics_wq = create_singlethread_workqueue("synaptics_wq");
+ if (!synaptics_wq)
+ return -ENOMEM;
+ return i2c_add_driver(&synaptics_ts_driver);
+}
+
+static void __exit synaptics_ts_exit(void)
+{
+ i2c_del_driver(&synaptics_ts_driver);
+ if (synaptics_wq)
+ destroy_workqueue(synaptics_wq);
+}
+
+module_init(synaptics_ts_init);
+module_exit(synaptics_ts_exit);
+
+MODULE_DESCRIPTION("Synaptics Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/ti_tscadc.c b/ANDROID_3.4.5/drivers/input/touchscreen/ti_tscadc.c
new file mode 100644
index 00000000..d229c741
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/tnetv107x-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/tnetv107x-ts.c
new file mode 100644
index 00000000..7e748809
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/touchit213.c b/ANDROID_3.4.5/drivers/input/touchscreen/touchit213.c
new file mode 100644
index 00000000..d1297ba1
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/touchright.c b/ANDROID_3.4.5/drivers/input/touchscreen/touchright.c
new file mode 100644
index 00000000..3a5c142c
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/touchwin.c b/ANDROID_3.4.5/drivers/input/touchscreen/touchwin.c
new file mode 100644
index 00000000..763a656a
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/tps6507x-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/tps6507x-ts.c
new file mode 100644
index 00000000..f7eda3d0
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/tsc2005.c b/ANDROID_3.4.5/drivers/input/touchscreen/tsc2005.c
new file mode 100644
index 00000000..b6adeaee
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/tsc2007.c b/ANDROID_3.4.5/drivers/input/touchscreen/tsc2007.c
new file mode 100644
index 00000000..1473d238
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/tsc40.c b/ANDROID_3.4.5/drivers/input/touchscreen/tsc40.c
new file mode 100644
index 00000000..29d5ed4d
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/touchscreen/tsc40.c
@@ -0,0 +1,184 @@
+/*
+ * 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);
+ input_set_abs_params(ptsc->dev, ABS_PRESSURE, 0, 0, 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/ANDROID_3.4.5/drivers/input/touchscreen/ucb1400_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/ucb1400_ts.c
new file mode 100644
index 00000000..46e83ad5
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/usbtouchscreen.c b/ANDROID_3.4.5/drivers/input/touchscreen/usbtouchscreen.c
new file mode 100644
index 00000000..22cd96f5
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/touchscreen/usbtouchscreen.c
@@ -0,0 +1,1690 @@
+/******************************************************************************
+ * 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;
+ 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->type->rept_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 = usb_alloc_coherent(udev, type->rept_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, type->rept_size,
+ usbtouch_irq, usbtouch, endpoint->bInterval);
+ else
+ usb_fill_bulk_urb(usbtouch->irq, udev,
+ usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
+ usbtouch->data, type->rept_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/ANDROID_3.4.5/drivers/input/touchscreen/w90p910_ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/w90p910_ts.c
new file mode 100644
index 00000000..9396b21d
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/wacom_w8001.c b/ANDROID_3.4.5/drivers/input/touchscreen/wacom_w8001.c
new file mode 100644
index 00000000..1569a393
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/wm831x-ts.c b/ANDROID_3.4.5/drivers/input/touchscreen/wm831x-ts.c
new file mode 100644
index 00000000..4bc851a9
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/wm9705.c b/ANDROID_3.4.5/drivers/input/touchscreen/wm9705.c
new file mode 100644
index 00000000..adc13a52
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/wm9712.c b/ANDROID_3.4.5/drivers/input/touchscreen/wm9712.c
new file mode 100644
index 00000000..6e743e3d
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/wm9713.c b/ANDROID_3.4.5/drivers/input/touchscreen/wm9713.c
new file mode 100644
index 00000000..74053531
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/wm97xx-core.c b/ANDROID_3.4.5/drivers/input/touchscreen/wm97xx-core.c
new file mode 100644
index 00000000..5dbe73af
--- /dev/null
+++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/touchscreen/zylonite-wm97xx.c b/ANDROID_3.4.5/drivers/input/touchscreen/zylonite-wm97xx.c
new file mode 100644
index 00000000..bf0869a7
--- /dev/null
+++ b/ANDROID_3.4.5/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");