]> Git Repo - linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <[email protected]>
Sun, 20 Mar 2011 05:27:06 +0000 (22:27 -0700)
committerLinus Torvalds <[email protected]>
Sun, 20 Mar 2011 05:27:06 +0000 (22:27 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (64 commits)
  Input: tsc2005 - remove 'disable' sysfs attribute
  Input: tsc2005 - add open/close
  Input: tsc2005 - handle read errors from SPI layer
  Input: tsc2005 - do not rearm timer in hardirq handler
  Input: tsc2005 - don't use work for 'pen up' handling
  Input: tsc2005 - do not use 0 in place of NULL
  Input: tsc2005 - use true/false for boolean variables
  Input: tsc2005 - hide selftest attribute if we can't reset
  Input: tsc2005 - rework driver initialization code
  Input: tsc2005 - set up bus type in input device
  Input: tsc2005 - set up parent device
  Input: tsc2005 - clear driver data after unbinding
  Input: tsc2005 - add module description
  Input: tsc2005 - remove driver banner message
  Input: tsc2005 - remove incorrect module alias
  Input: tsc2005 - convert to using dev_pm_ops
  Input: tsc2005 - use spi_get/set_drvdata()
  Input: introduce tsc2005 driver
  Input: xen-kbdfront - move to drivers/input/misc
  Input: xen-kbdfront - add grant reference for shared page
  ...

53 files changed:
arch/arm/mach-s5pv210/mach-goni.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/input/Kconfig
drivers/input/Makefile
drivers/input/evdev.c
drivers/input/input-polldev.c
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/max7359_keypad.c
drivers/input/keyboard/mcs_touchkey.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/keyboard/qt1070.c [new file with mode: 0644]
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/keyboard/tca6416-keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ad714x-i2c.c
drivers/input/misc/ad714x-spi.c
drivers/input/misc/adxl34x-i2c.c
drivers/input/misc/adxl34x-spi.c
drivers/input/misc/ati_remote2.c
drivers/input/misc/uinput.c
drivers/input/misc/xen-kbdfront.c [new file with mode: 0644]
drivers/input/mouse/bcm5974.c
drivers/input/mouse/synaptics_i2c.c
drivers/input/sparse-keymap.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ad7879-spi.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/atmel_mxt_ts.c [new file with mode: 0644]
drivers/input/touchscreen/qt602240_ts.c [deleted file]
drivers/input/touchscreen/tsc2005.c [new file with mode: 0644]
drivers/input/touchscreen/wm831x-ts.c [new file with mode: 0644]
drivers/input/xen-kbdfront.c [deleted file]
drivers/media/dvb/dvb-usb/dvb-usb-remote.c
drivers/media/rc/rc-main.c
include/linux/i2c/atmel_mxt_ts.h [new file with mode: 0644]
include/linux/i2c/mcs.h
include/linux/i2c/qt602240_ts.h [deleted file]
include/linux/input-polldev.h
include/linux/input.h
include/linux/mfd/wm831x/pdata.h
include/linux/spi/tsc2005.h [new file with mode: 0644]

index 243291722c667484a22ec85337cc17b3f521f89e..31d5aa76975310a529084e575e0116e08a7846df 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/fb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
-#include <linux/i2c/qt602240_ts.h>
+#include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/mfd/max8998.h>
 #include <linux/mfd/wm8994/pdata.h>
 #include <linux/regulator/fixed.h>
@@ -25,6 +25,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -225,7 +226,7 @@ static void __init goni_radio_init(void)
 }
 
 /* TSP */
-static struct qt602240_platform_data qt602240_platform_data = {
+static struct mxt_platform_data qt602240_platform_data = {
        .x_line         = 17,
        .y_line         = 11,
        .x_size         = 800,
@@ -233,7 +234,8 @@ static struct qt602240_platform_data qt602240_platform_data = {
        .blen           = 0x21,
        .threshold      = 0x28,
        .voltage        = 2800000,              /* 2.8V */
-       .orient         = QT602240_DIAGONAL,
+       .orient         = MXT_DIAGONAL,
+       .irqflags       = IRQF_TRIGGER_FALLING,
 };
 
 static struct s3c2410_platform_i2c i2c2_data __initdata = {
index 61aa712333927815e5cb9d0d4777e8de3dacd1af..b85744fe846477221ad02221f78bb397c603f54d 100644 (file)
@@ -481,6 +481,12 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
index c3d66269ed7d584bb655be926cef4b8e073699a9..e9687768a335d5461e1ed7785d0d8bd551af3724 100644 (file)
@@ -1333,6 +1333,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1840,6 +1843,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
index d485894ff4db877f2045db8c21934cbd2d41d547..65ac53d7aeccf86a9f3a0c1e7a6a9c00af0a470f 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI  0x0242
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO   0x0243
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS   0x0244
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI   0x0245
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO    0x0246
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS    0x0247
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
index cd74203c8178950408b95cb51dd69b01ccb1ceea..33dde8724e02faec04fe1388103343a4cf03eda2 100644 (file)
@@ -900,8 +900,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                                        hid->ll_driver->hidinput_input_event;
                                input_dev->open = hidinput_open;
                                input_dev->close = hidinput_close;
-                               input_dev->setkeycode_new = hidinput_setkeycode;
-                               input_dev->getkeycode_new = hidinput_getkeycode;
+                               input_dev->setkeycode = hidinput_setkeycode;
+                               input_dev->getkeycode = hidinput_getkeycode;
 
                                input_dev->name = hid->name;
                                input_dev->phys = hid->phys;
index 1903c0f5b9257d2384cec4a8763cf116c2bb904e..23e82e46656dbe08236577dd0d5fdf04ca209f61 100644 (file)
@@ -161,16 +161,6 @@ config INPUT_APMPOWER
          To compile this driver as a module, choose M here: the
          module will be called apm-power.
 
-config XEN_KBDDEV_FRONTEND
-       tristate "Xen virtual keyboard and mouse support"
-       depends on XEN_FBDEV_FRONTEND
-       default y
-       select XEN_XENBUS_FRONTEND
-       help
-         This driver implements the front-end of the Xen virtual
-         keyboard and mouse device driver.  It communicates with a back-end
-         in another domain.
-
 comment "Input Device Drivers"
 
 source "drivers/input/keyboard/Kconfig"
index 09614ce74961bccded0b02ecd29815f3947533a1..0c789490e0b359d60040fd82ed6c19dfb8784d04 100644 (file)
@@ -24,5 +24,3 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN)       += touchscreen/
 obj-$(CONFIG_INPUT_MISC)       += misc/
 
 obj-$(CONFIG_INPUT_APMPOWER)   += apm-power.o
-
-obj-$(CONFIG_XEN_KBDDEV_FRONTEND)      += xen-kbdfront.o
index c8471a2552e73ea28c7401e58e713b66bbc6cc33..7f42d3a454d2d6aaebdc41e0e5a8c6700d6a00df 100644 (file)
@@ -321,6 +321,9 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
        struct input_event event;
        int retval;
 
+       if (count < input_event_size())
+               return -EINVAL;
+
        retval = mutex_lock_interruptible(&evdev->mutex);
        if (retval)
                return retval;
@@ -330,17 +333,16 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
                goto out;
        }
 
-       while (retval < count) {
-
+       do {
                if (input_event_from_user(buffer + retval, &event)) {
                        retval = -EFAULT;
                        goto out;
                }
+               retval += input_event_size();
 
                input_inject_event(&evdev->handle,
                                   event.type, event.code, event.value);
-               retval += input_event_size();
-       }
+       } while (retval + input_event_size() <= count);
 
  out:
        mutex_unlock(&evdev->mutex);
index 0559e309bac9a443230e66d3f3cfff31e7963f0b..3037842a60d8a10e0533033b665aca490c10b030 100644 (file)
@@ -192,7 +192,7 @@ static struct attribute_group input_polldev_attribute_group = {
 };
 
 /**
- * input_allocate_polled_device - allocated memory polled device
+ * input_allocate_polled_device - allocate memory for polled device
  *
  * The function allocates memory for a polled device and also
  * for an input device associated with this polled device.
@@ -239,7 +239,7 @@ EXPORT_SYMBOL(input_free_polled_device);
  * with input layer. The device should be allocated with call to
  * input_allocate_polled_device(). Callers should also set up poll()
  * method and set up capabilities (id, name, phys, bits) of the
- * corresponing input_dev structure.
+ * corresponding input_dev structure.
  */
 int input_register_polled_device(struct input_polled_dev *dev)
 {
index 11905b6a30237c574825a178b16b8fde32d593dd..d6e8bd8a851c26d0e4718d10d30977451bb28009 100644 (file)
@@ -791,22 +791,9 @@ int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
        int retval;
 
        spin_lock_irqsave(&dev->event_lock, flags);
-
-       if (dev->getkeycode) {
-               /*
-                * Support for legacy drivers, that don't implement the new
-                * ioctls
-                */
-               u32 scancode = ke->index;
-
-               memcpy(ke->scancode, &scancode, sizeof(scancode));
-               ke->len = sizeof(scancode);
-               retval = dev->getkeycode(dev, scancode, &ke->keycode);
-       } else {
-               retval = dev->getkeycode_new(dev, ke);
-       }
-
+       retval = dev->getkeycode(dev, ke);
        spin_unlock_irqrestore(&dev->event_lock, flags);
+
        return retval;
 }
 EXPORT_SYMBOL(input_get_keycode);
@@ -831,35 +818,7 @@ int input_set_keycode(struct input_dev *dev,
 
        spin_lock_irqsave(&dev->event_lock, flags);
 
-       if (dev->setkeycode) {
-               /*
-                * Support for legacy drivers, that don't implement the new
-                * ioctls
-                */
-               unsigned int scancode;
-
-               retval = input_scancode_to_scalar(ke, &scancode);
-               if (retval)
-                       goto out;
-
-               /*
-                * We need to know the old scancode, in order to generate a
-                * keyup effect, if the set operation happens successfully
-                */
-               if (!dev->getkeycode) {
-                       retval = -EINVAL;
-                       goto out;
-               }
-
-               retval = dev->getkeycode(dev, scancode, &old_keycode);
-               if (retval)
-                       goto out;
-
-               retval = dev->setkeycode(dev, scancode, ke->keycode);
-       } else {
-               retval = dev->setkeycode_new(dev, ke, &old_keycode);
-       }
-
+       retval = dev->setkeycode(dev, ke, &old_keycode);
        if (retval)
                goto out;
 
@@ -1846,11 +1805,11 @@ int input_register_device(struct input_dev *dev)
                dev->rep[REP_PERIOD] = 33;
        }
 
-       if (!dev->getkeycode && !dev->getkeycode_new)
-               dev->getkeycode_new = input_default_getkeycode;
+       if (!dev->getkeycode)
+               dev->getkeycode = input_default_getkeycode;
 
-       if (!dev->setkeycode && !dev->setkeycode_new)
-               dev->setkeycode_new = input_default_setkeycode;
+       if (!dev->setkeycode)
+               dev->setkeycode = input_default_setkeycode;
 
        dev_set_name(&dev->dev, "input%ld",
                     (unsigned long) atomic_inc_return(&input_no) - 1);
index c7a92028f450953b264ac6d8d950eeef9135c4a6..b16bed038f7245634aa3a6ffbbac45b40d168878 100644 (file)
@@ -112,6 +112,16 @@ config KEYBOARD_ATKBD_RDI_KEYCODES
          right-hand column will be interpreted as the key shown in the
          left-hand column.
 
+config KEYBOARD_QT1070
+       tristate "Atmel AT42QT1070 Touch Sensor Chip"
+       depends on I2C
+       help
+         Say Y here if you want to use Atmel AT42QT1070 QTouch
+         Sensor chip as input device.
+
+         To compile this driver as a module, choose M here:
+         the module will be called qt1070
+
 config KEYBOARD_QT2160
        tristate "Atmel AT42QT2160 Touch Sensor Chip"
        depends on I2C && EXPERIMENTAL
index 468c627a28447efb78b9fb32b9a35351719d4f06..878e6c20deb0e1f231526e26846aedd1e1ce60d4 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_OMAP4)          += omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)       += opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
+obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o
 obj-$(CONFIG_KEYBOARD_QT2160)          += qt2160.o
 obj-$(CONFIG_KEYBOARD_SAMSUNG)         += samsung-keypad.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)                += sh_keysc.o
index f7c2a166576b8cc161c1debb85639c8426906584..b732870ecc897a1465ad8645342b9ce60435beba 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/leds.h>
+#include <linux/pm.h>
 #include <linux/i2c/lm8323.h>
 #include <linux/slab.h>
 
@@ -802,8 +803,9 @@ static int __devexit lm8323_remove(struct i2c_client *client)
  * We don't need to explicitly suspend the chip, as it already switches off
  * when there's no activity.
  */
-static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
+static int lm8323_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct lm8323_chip *lm = i2c_get_clientdata(client);
        int i;
 
@@ -821,8 +823,9 @@ static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int lm8323_resume(struct i2c_client *client)
+static int lm8323_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct lm8323_chip *lm = i2c_get_clientdata(client);
        int i;
 
@@ -839,11 +842,10 @@ static int lm8323_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define lm8323_suspend NULL
-#define lm8323_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume);
+
 static const struct i2c_device_id lm8323_id[] = {
        { "lm8323", 0 },
        { }
@@ -852,11 +854,10 @@ static const struct i2c_device_id lm8323_id[] = {
 static struct i2c_driver lm8323_i2c_driver = {
        .driver = {
                .name   = "lm8323",
+               .pm     = &lm8323_pm_ops,
        },
        .probe          = lm8323_probe,
        .remove         = __devexit_p(lm8323_remove),
-       .suspend        = lm8323_suspend,
-       .resume         = lm8323_resume,
        .id_table       = lm8323_id,
 };
 MODULE_DEVICE_TABLE(i2c, lm8323_id);
index 9091ff5ea808b8829d7d9475f15f704532d10c5e..5afe35ad24d37b4ec3558cc5a07c20470e6f3ea8 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/pm.h>
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 
@@ -271,8 +272,10 @@ static int __devexit max7359_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int max7359_suspend(struct i2c_client *client, pm_message_t mesg)
+static int max7359_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        max7359_fall_deepsleep(client);
 
        if (device_may_wakeup(&client->dev))
@@ -281,8 +284,10 @@ static int max7359_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int max7359_resume(struct i2c_client *client)
+static int max7359_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
+
        if (device_may_wakeup(&client->dev))
                disable_irq_wake(client->irq);
 
@@ -291,11 +296,10 @@ static int max7359_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define max7359_suspend        NULL
-#define max7359_resume NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume);
+
 static const struct i2c_device_id max7359_ids[] = {
        { "max7359", 0 },
        { }
@@ -305,11 +309,10 @@ MODULE_DEVICE_TABLE(i2c, max7359_ids);
 static struct i2c_driver max7359_i2c_driver = {
        .driver = {
                .name = "max7359",
+               .pm   = &max7359_pm,
        },
        .probe          = max7359_probe,
        .remove         = __devexit_p(max7359_remove),
-       .suspend        = max7359_suspend,
-       .resume         = max7359_resume,
        .id_table       = max7359_ids,
 };
 
index 63b849d7e90b0fb9d2755ed6a1e9f0bf9975959f..af1aab324a4c58c0e011ea8660e483802db2ef41 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
+ * Touchkey driver for MELFAS MCS5000/5080 controller
  *
  * Copyright (C) 2010 Samsung Electronics Co.Ltd
  * Author: HeungJun Kim <[email protected]>
@@ -19,6 +19,7 @@
 #include <linux/input.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
+#include <linux/pm.h>
 
 /* MCS5000 Touchkey */
 #define MCS5000_TOUCHKEY_STATUS                0x04
@@ -45,6 +46,8 @@ struct mcs_touchkey_chip {
 };
 
 struct mcs_touchkey_data {
+       void (*poweron)(bool);
+
        struct i2c_client *client;
        struct input_dev *input_dev;
        struct mcs_touchkey_chip chip;
@@ -169,6 +172,11 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client,
        if (pdata->cfg_pin)
                pdata->cfg_pin();
 
+       if (pdata->poweron) {
+               data->poweron = pdata->poweron;
+               data->poweron(true);
+       }
+
        error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
                        IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
        if (error) {
@@ -196,12 +204,57 @@ static int __devexit mcs_touchkey_remove(struct i2c_client *client)
        struct mcs_touchkey_data *data = i2c_get_clientdata(client);
 
        free_irq(client->irq, data);
+       if (data->poweron)
+               data->poweron(false);
        input_unregister_device(data->input_dev);
        kfree(data);
 
        return 0;
 }
 
+static void mcs_touchkey_shutdown(struct i2c_client *client)
+{
+       struct mcs_touchkey_data *data = i2c_get_clientdata(client);
+
+       if (data->poweron)
+               data->poweron(false);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mcs_touchkey_suspend(struct device *dev)
+{
+       struct mcs_touchkey_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+
+       /* Disable the work */
+       disable_irq(client->irq);
+
+       /* Finally turn off the power */
+       if (data->poweron)
+               data->poweron(false);
+
+       return 0;
+}
+
+static int mcs_touchkey_resume(struct device *dev)
+{
+       struct mcs_touchkey_data *data = dev_get_drvdata(dev);
+       struct i2c_client *client = data->client;
+
+       /* Enable the device first */
+       if (data->poweron)
+               data->poweron(true);
+
+       /* Enable irq again */
+       enable_irq(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mcs_touchkey_pm_ops,
+                        mcs_touchkey_suspend, mcs_touchkey_resume);
+
 static const struct i2c_device_id mcs_touchkey_id[] = {
        { "mcs5000_touchkey", MCS5000_TOUCHKEY },
        { "mcs5080_touchkey", MCS5080_TOUCHKEY },
@@ -213,9 +266,11 @@ static struct i2c_driver mcs_touchkey_driver = {
        .driver = {
                .name   = "mcs_touchkey",
                .owner  = THIS_MODULE,
+               .pm     = &mcs_touchkey_pm_ops,
        },
        .probe          = mcs_touchkey_probe,
        .remove         = __devexit_p(mcs_touchkey_remove),
+       .shutdown       = mcs_touchkey_shutdown,
        .id_table       = mcs_touchkey_id,
 };
 
index 45bd0977d0066622d543a9d51cca96873536f8a9..c51a3c4a7feb52520246c332d93784a25fc70774 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/io.h>
 #include <linux/input.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/omap4-keypad.h>
 
@@ -80,20 +81,6 @@ struct omap4_keypad {
        unsigned short keymap[];
 };
 
-static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data)
-{
-       __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
-                       keypad_data->base + OMAP4_KBD_CTRL);
-       __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
-                       keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
-       __raw_writel(OMAP4_VAL_IRQDISABLE,
-                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
-       __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
-                       keypad_data->base + OMAP4_KBD_IRQENABLE);
-       __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
-                       keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
-}
-
 /* Interrupt handler */
 static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
 {
@@ -144,6 +131,49 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int omap4_keypad_open(struct input_dev *input)
+{
+       struct omap4_keypad *keypad_data = input_get_drvdata(input);
+
+       pm_runtime_get_sync(input->dev.parent);
+
+       disable_irq(keypad_data->irq);
+
+       __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
+                       keypad_data->base + OMAP4_KBD_CTRL);
+       __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
+                       keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
+       __raw_writel(OMAP4_VAL_IRQDISABLE,
+                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
+       __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
+                       keypad_data->base + OMAP4_KBD_IRQENABLE);
+       __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
+                       keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
+
+       enable_irq(keypad_data->irq);
+
+       return 0;
+}
+
+static void omap4_keypad_close(struct input_dev *input)
+{
+       struct omap4_keypad *keypad_data = input_get_drvdata(input);
+
+       disable_irq(keypad_data->irq);
+
+       /* Disable interrupts */
+       __raw_writel(OMAP4_VAL_IRQDISABLE,
+                    keypad_data->base + OMAP4_KBD_IRQENABLE);
+
+       /* clear pending interrupts */
+       __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
+                       keypad_data->base + OMAP4_KBD_IRQSTATUS);
+
+       enable_irq(keypad_data->irq);
+
+       pm_runtime_put_sync(input->dev.parent);
+}
+
 static int __devinit omap4_keypad_probe(struct platform_device *pdev)
 {
        const struct omap4_keypad_platform_data *pdata;
@@ -225,6 +255,9 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
        input_dev->id.product = 0x0001;
        input_dev->id.version = 0x0001;
 
+       input_dev->open = omap4_keypad_open;
+       input_dev->close = omap4_keypad_close;
+
        input_dev->keycode      = keypad_data->keymap;
        input_dev->keycodesize  = sizeof(keypad_data->keymap[0]);
        input_dev->keycodemax   = max_keys;
@@ -239,8 +272,6 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
        matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
                        input_dev->keycode, input_dev->keybit);
 
-       omap4_keypad_config(keypad_data);
-
        error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
                             IRQF_TRIGGER_RISING,
                             "omap4-keypad", keypad_data);
@@ -249,17 +280,19 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
                goto err_free_input;
        }
 
+       pm_runtime_enable(&pdev->dev);
+
        error = input_register_device(keypad_data->input);
        if (error < 0) {
                dev_err(&pdev->dev, "failed to register input device\n");
-               goto err_free_irq;
+               goto err_pm_disable;
        }
 
-
        platform_set_drvdata(pdev, keypad_data);
        return 0;
 
-err_free_irq:
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
        free_irq(keypad_data->irq, keypad_data);
 err_free_input:
        input_free_device(input_dev);
@@ -278,6 +311,9 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev)
        struct resource *res;
 
        free_irq(keypad_data->irq, keypad_data);
+
+       pm_runtime_disable(&pdev->dev);
+
        input_unregister_device(keypad_data->input);
 
        iounmap(keypad_data->base);
diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
new file mode 100644 (file)
index 0000000..fba8404
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ *  Atmel AT42QT1070 QTouch Sensor Controller
+ *
+ *  Copyright (C) 2011 Atmel
+ *
+ *  Authors: Bo Shen <[email protected]>
+ *
+ *  Base on AT42QT2160 driver by:
+ *  Raphael Derosso Pereira <[email protected]>
+ *  Copyright (C) 2009
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+
+/* Address for each register */
+#define CHIP_ID            0x00
+#define QT1070_CHIP_ID     0x2E
+
+#define FW_VERSION         0x01
+#define QT1070_FW_VERSION  0x15
+
+#define DET_STATUS         0x02
+
+#define KEY_STATUS         0x03
+
+/* Calibrate */
+#define CALIBRATE_CMD      0x38
+#define QT1070_CAL_TIME    200
+
+/* Reset */
+#define RESET              0x39
+#define QT1070_RESET_TIME  255
+
+/* AT42QT1070 support up to 7 keys */
+static const unsigned short qt1070_key2code[] = {
+       KEY_0, KEY_1, KEY_2, KEY_3,
+       KEY_4, KEY_5, KEY_6,
+};
+
+struct qt1070_data {
+       struct i2c_client *client;
+       struct input_dev *input;
+       unsigned int irq;
+       unsigned short keycodes[ARRAY_SIZE(qt1070_key2code)];
+       u8 last_keys;
+};
+
+static int qt1070_read(struct i2c_client *client, u8 reg)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "can not read register, returned %d\n", ret);
+
+       return ret;
+}
+
+static int qt1070_write(struct i2c_client *client, u8 reg, u8 data)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, reg, data);
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "can not write register, returned %d\n", ret);
+
+       return ret;
+}
+
+static bool __devinit qt1070_identify(struct i2c_client *client)
+{
+       int id, ver;
+
+       /* Read Chip ID */
+       id = qt1070_read(client, CHIP_ID);
+       if (id != QT1070_CHIP_ID) {
+               dev_err(&client->dev, "ID %d not supported\n", id);
+               return false;
+       }
+
+       /* Read firmware version */
+       ver = qt1070_read(client, FW_VERSION);
+       if (ver < 0) {
+               dev_err(&client->dev, "could not read the firmware version\n");
+               return false;
+       }
+
+       dev_info(&client->dev, "AT42QT1070 firmware version %x\n", ver);
+
+       return true;
+}
+
+static irqreturn_t qt1070_interrupt(int irq, void *dev_id)
+{
+       struct qt1070_data *data = dev_id;
+       struct i2c_client *client = data->client;
+       struct input_dev *input = data->input;
+       int i;
+       u8 new_keys, keyval, mask = 0x01;
+
+       /* Read the detected status register, thus clearing interrupt */
+       qt1070_read(client, DET_STATUS);
+
+       /* Read which key changed */
+       new_keys = qt1070_read(client, KEY_STATUS);
+
+       for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) {
+               keyval = new_keys & mask;
+               if ((data->last_keys & mask) != keyval)
+                       input_report_key(input, data->keycodes[i], keyval);
+               mask <<= 1;
+       }
+       input_sync(input);
+
+       data->last_keys = new_keys;
+       return IRQ_HANDLED;
+}
+
+static int __devinit qt1070_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct qt1070_data *data;
+       struct input_dev *input;
+       int i;
+       int err;
+
+       err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
+       if (!err) {
+               dev_err(&client->dev, "%s adapter not supported\n",
+                       dev_driver_string(&client->adapter->dev));
+               return -ENODEV;
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "please assign the irq to this device\n");
+               return -EINVAL;
+       }
+
+       /* Identify the qt1070 chip */
+       if (!qt1070_identify(client))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(struct qt1070_data), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!data || !input) {
+               dev_err(&client->dev, "insufficient memory\n");
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       data->client = client;
+       data->input = input;
+       data->irq = client->irq;
+
+       input->name = "AT42QT1070 QTouch Sensor";
+       input->dev.parent = &client->dev;
+       input->id.bustype = BUS_I2C;
+
+       /* Add the keycode */
+       input->keycode = data->keycodes;
+       input->keycodesize = sizeof(data->keycodes[0]);
+       input->keycodemax = ARRAY_SIZE(qt1070_key2code);
+
+       __set_bit(EV_KEY, input->evbit);
+
+       for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) {
+               data->keycodes[i] = qt1070_key2code[i];
+               __set_bit(qt1070_key2code[i], input->keybit);
+       }
+
+       /* Calibrate device */
+       qt1070_write(client, CALIBRATE_CMD, 1);
+       msleep(QT1070_CAL_TIME);
+
+       /* Soft reset */
+       qt1070_write(client, RESET, 1);
+       msleep(QT1070_RESET_TIME);
+
+       err = request_threaded_irq(client->irq, NULL, qt1070_interrupt,
+               IRQF_TRIGGER_NONE, client->dev.driver->name, data);
+       if (err) {
+               dev_err(&client->dev, "fail to request irq\n");
+               goto err_free_mem;
+       }
+
+       /* Register the input device */
+       err = input_register_device(data->input);
+       if (err) {
+               dev_err(&client->dev, "Failed to register input device\n");
+               goto err_free_irq;
+       }
+
+       i2c_set_clientdata(client, data);
+
+       /* Read to clear the chang line */
+       qt1070_read(client, DET_STATUS);
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_mem:
+       input_free_device(input);
+       kfree(data);
+       return err;
+}
+
+static int __devexit qt1070_remove(struct i2c_client *client)
+{
+       struct qt1070_data *data = i2c_get_clientdata(client);
+
+       /* Release IRQ */
+       free_irq(client->irq, data);
+
+       input_unregister_device(data->input);
+       kfree(data);
+
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+static const struct i2c_device_id qt1070_id[] = {
+       { "qt1070", 0 },
+       { },
+};
+
+static struct i2c_driver qt1070_driver = {
+       .driver = {
+               .name   = "qt1070",
+               .owner  = THIS_MODULE,
+       },
+       .id_table       = qt1070_id,
+       .probe          = qt1070_probe,
+       .remove         = __devexit_p(qt1070_remove),
+};
+
+static int __init qt1070_init(void)
+{
+       return i2c_add_driver(&qt1070_driver);
+}
+module_init(qt1070_init);
+
+static void __exit qt1070_exit(void)
+{
+       i2c_del_driver(&qt1070_driver);
+}
+module_exit(qt1070_exit);
+
+MODULE_AUTHOR("Bo Shen <[email protected]>");
+MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor");
+MODULE_LICENSE("GPL");
index dbbe761778d28e2815182ed023bf5d196f842b27..99122f59e98822d8620cec91c2ea4942e427269b 100644 (file)
@@ -402,7 +402,7 @@ static int __devexit tc3589x_keypad_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int tc3589x_keypad_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -439,19 +439,19 @@ static int tc3589x_keypad_resume(struct device *dev)
 
        return 0;
 }
-
-static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops,
-                              tc3589x_keypad_suspend, tc3589x_keypad_resume);
 #endif
 
+static SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops,
+                        tc3589x_keypad_suspend, tc3589x_keypad_resume);
+
 static struct platform_driver tc3589x_keypad_driver = {
-       .driver.name  = "tc3589x-keypad",
-       .driver.owner = THIS_MODULE,
-#ifdef CONFIG_PM
-       .driver.pm = &tc3589x_keypad_dev_pm_ops,
-#endif
-       .probe = tc3589x_keypad_probe,
-       .remove = __devexit_p(tc3589x_keypad_remove),
+       .driver = {
+               .name   = "tc3589x-keypad",
+               .owner  = THIS_MODULE,
+               .pm     = &tc3589x_keypad_dev_pm_ops,
+       },
+       .probe  = tc3589x_keypad_probe,
+       .remove = __devexit_p(tc3589x_keypad_remove),
 };
 
 static int __init tc3589x_keypad_init(void)
index 800fbccf1f0fb714017cefb47320829753b0f839..3afea3f897182adba5c1439dc38e7a34126fa440 100644 (file)
@@ -297,6 +297,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client,
        }
 
        i2c_set_clientdata(client, chip);
+       device_init_wakeup(&client->dev, 1);
 
        return 0;
 
@@ -326,10 +327,37 @@ static int __devexit tca6416_keypad_remove(struct i2c_client *client)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tca6416_keypad_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(chip->irqnum);
+
+       return 0;
+}
+
+static int tca6416_keypad_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(chip->irqnum);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops,
+                        tca6416_keypad_suspend, tca6416_keypad_resume);
 
 static struct i2c_driver tca6416_keypad_driver = {
        .driver = {
                .name   = "tca6416-keypad",
+               .pm     = &tca6416_keypad_dev_pm_ops,
        },
        .probe          = tca6416_keypad_probe,
        .remove         = __devexit_p(tca6416_keypad_remove),
index b0c6772851a99496727663941e092b46f81482e3..f9cf0881b0e3cf386a3e606d462aebf4bacd5575 100644 (file)
@@ -454,4 +454,17 @@ config INPUT_CMA3000_I2C
          To compile this driver as a module, choose M here: the
          module will be called cma3000_d0x_i2c.
 
+config INPUT_XEN_KBDDEV_FRONTEND
+       tristate "Xen virtual keyboard and mouse support"
+       depends on XEN_FBDEV_FRONTEND
+       default y
+       select XEN_XENBUS_FRONTEND
+       help
+         This driver implements the front-end of the Xen virtual
+         keyboard and mouse device driver.  It communicates with a back-end
+         in another domain.
+
+         To compile this driver as a module, choose M here: the
+         module will be called xen-kbdfront.
+
 endif
index 9b4797112c9ac14955ff7afb0b84ab616e613a89..e3f7984e627427ead449de2d6e6452d3aac1c915 100644 (file)
@@ -42,5 +42,6 @@ obj-$(CONFIG_INPUT_TWL4030_VIBRA)     += twl4030-vibra.o
 obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)       += wistron_btns.o
 obj-$(CONFIG_INPUT_WM831X_ON)          += wm831x-on.o
+obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)        += xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
 
index 2bef8fa56c948e0ba4305ea0f4f22450244f79d4..e21deb1baa8abfb193d46702023540e2d09a41ca 100644 (file)
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/pm.h>
 #include "ad714x.h"
 
 #ifdef CONFIG_PM
-static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+static int ad714x_i2c_suspend(struct device *dev)
 {
-       return ad714x_disable(i2c_get_clientdata(client));
+       return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev)));
 }
 
-static int ad714x_i2c_resume(struct i2c_client *client)
+static int ad714x_i2c_resume(struct device *dev)
 {
-       return ad714x_enable(i2c_get_clientdata(client));
+       return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev)));
 }
-#else
-# define ad714x_i2c_suspend NULL
-# define ad714x_i2c_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
+
 static int ad714x_i2c_write(struct device *dev, unsigned short reg,
                                unsigned short data)
 {
@@ -114,11 +114,10 @@ MODULE_DEVICE_TABLE(i2c, ad714x_id);
 static struct i2c_driver ad714x_i2c_driver = {
        .driver = {
                .name = "ad714x_captouch",
+               .pm   = &ad714x_i2c_pm,
        },
        .probe    = ad714x_i2c_probe,
        .remove   = __devexit_p(ad714x_i2c_remove),
-       .suspend  = ad714x_i2c_suspend,
-       .resume   = ad714x_i2c_resume,
        .id_table = ad714x_id,
 };
 
index 7f8dedfd1bfeed3db41403e560dc55b16a32f907..4120dd5493059126b272256b47eba121044e396d 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/input.h>       /* BUS_I2C */
 #include <linux/module.h>
 #include <linux/spi/spi.h>
+#include <linux/pm.h>
 #include <linux/types.h>
 #include "ad714x.h"
 
 #define AD714x_SPI_READ            BIT(10)
 
 #ifdef CONFIG_PM
-static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message)
+static int ad714x_spi_suspend(struct device *dev)
 {
-       return ad714x_disable(spi_get_drvdata(spi));
+       return ad714x_disable(spi_get_drvdata(to_spi_device(dev)));
 }
 
-static int ad714x_spi_resume(struct spi_device *spi)
+static int ad714x_spi_resume(struct device *dev)
 {
-       return ad714x_enable(spi_get_drvdata(spi));
+       return ad714x_enable(spi_get_drvdata(to_spi_device(dev)));
 }
-#else
-# define ad714x_spi_suspend NULL
-# define ad714x_spi_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
+
 static int ad714x_spi_read(struct device *dev, unsigned short reg,
                unsigned short *data)
 {
@@ -79,11 +79,10 @@ static struct spi_driver ad714x_spi_driver = {
        .driver = {
                .name   = "ad714x_captouch",
                .owner  = THIS_MODULE,
+               .pm     = &ad714x_spi_pm,
        },
        .probe          = ad714x_spi_probe,
        .remove         = __devexit_p(ad714x_spi_remove),
-       .suspend        = ad714x_spi_suspend,
-       .resume         = ad714x_spi_resume,
 };
 
 static __init int ad714x_spi_init(void)
index 0779724af7e79b8f34d6857c15793f09d7080b60..ccacf2bb06a4e56c74624dab181ac6398ab56bcc 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/pm.h>
 #include "adxl34x.h"
 
 static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
@@ -105,8 +106,9 @@ static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+static int adxl34x_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct adxl34x *ac = i2c_get_clientdata(client);
 
        adxl34x_suspend(ac);
@@ -114,19 +116,20 @@ static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
        return 0;
 }
 
-static int adxl34x_i2c_resume(struct i2c_client *client)
+static int adxl34x_i2c_resume(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct adxl34x *ac = i2c_get_clientdata(client);
 
        adxl34x_resume(ac);
 
        return 0;
 }
-#else
-# define adxl34x_i2c_suspend NULL
-# define adxl34x_i2c_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend,
+                        adxl34x_i2c_resume);
+
 static const struct i2c_device_id adxl34x_id[] = {
        { "adxl34x", 0 },
        { }
@@ -138,11 +141,10 @@ static struct i2c_driver adxl34x_driver = {
        .driver = {
                .name = "adxl34x",
                .owner = THIS_MODULE,
+               .pm = &adxl34x_i2c_pm,
        },
        .probe    = adxl34x_i2c_probe,
        .remove   = __devexit_p(adxl34x_i2c_remove),
-       .suspend  = adxl34x_i2c_suspend,
-       .resume   = adxl34x_i2c_resume,
        .id_table = adxl34x_id,
 };
 
index 782de9e898287b4905291a26305eb049a04fcac1..f29de22fdda054b7fed385ea0abe957e2cda5570 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/input.h>       /* BUS_SPI */
 #include <linux/module.h>
 #include <linux/spi/spi.h>
+#include <linux/pm.h>
 #include <linux/types.h>
 #include "adxl34x.h"
 
@@ -57,7 +58,7 @@ static int adxl34x_spi_read_block(struct device *dev,
        return (status < 0) ? status : 0;
 }
 
-static const struct adxl34x_bus_ops adx134x_spi_bops = {
+static const struct adxl34x_bus_ops adxl34x_spi_bops = {
        .bustype        = BUS_SPI,
        .write          = adxl34x_spi_write,
        .read           = adxl34x_spi_read,
@@ -76,7 +77,7 @@ static int __devinit adxl34x_spi_probe(struct spi_device *spi)
 
        ac = adxl34x_probe(&spi->dev, spi->irq,
                           spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
-                          &adx134x_spi_bops);
+                          &adxl34x_spi_bops);
 
        if (IS_ERR(ac))
                return PTR_ERR(ac);
@@ -94,8 +95,9 @@ static int __devexit adxl34x_spi_remove(struct spi_device *spi)
 }
 
 #ifdef CONFIG_PM
-static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
+static int adxl34x_spi_suspend(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct adxl34x *ac = dev_get_drvdata(&spi->dev);
 
        adxl34x_suspend(ac);
@@ -103,29 +105,29 @@ static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
        return 0;
 }
 
-static int adxl34x_spi_resume(struct spi_device *spi)
+static int adxl34x_spi_resume(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct adxl34x *ac = dev_get_drvdata(&spi->dev);
 
        adxl34x_resume(ac);
 
        return 0;
 }
-#else
-# define adxl34x_spi_suspend NULL
-# define adxl34x_spi_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend,
+                        adxl34x_spi_resume);
+
 static struct spi_driver adxl34x_driver = {
        .driver = {
                .name = "adxl34x",
                .bus = &spi_bus_type,
                .owner = THIS_MODULE,
+               .pm = &adxl34x_spi_pm,
        },
        .probe   = adxl34x_spi_probe,
        .remove  = __devexit_p(adxl34x_spi_remove),
-       .suspend = adxl34x_spi_suspend,
-       .resume  = adxl34x_spi_resume,
 };
 
 static int __init adxl34x_spi_init(void)
index 0b0e9be6354215319200a8a305c9db55e8b4c3dd..9ccdb82d869a09245c80bf125a99c5fcac5cffd7 100644 (file)
@@ -612,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
        idev->open = ati_remote2_open;
        idev->close = ati_remote2_close;
 
-       idev->getkeycode_new = ati_remote2_getkeycode;
-       idev->setkeycode_new = ati_remote2_setkeycode;
+       idev->getkeycode = ati_remote2_getkeycode;
+       idev->setkeycode = ati_remote2_setkeycode;
 
        idev->name = ar2->name;
        idev->phys = ar2->phys;
index 82542a1c1098fb00c3d33769a21088f3f7eccd05..364bdf43a381d8a052c730eb38eb005c0f006c0c 100644 (file)
@@ -347,8 +347,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
 {
        struct uinput_user_dev  *user_dev;
        struct input_dev        *dev;
-       char                    *name;
-       int                     i, size;
+       int                     i;
        int                     retval;
 
        if (count != sizeof(struct uinput_user_dev))
@@ -362,30 +361,25 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
 
        dev = udev->dev;
 
-       user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL);
-       if (!user_dev)
-               return -ENOMEM;
-
-       if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
-               retval = -EFAULT;
-               goto exit;
-       }
+       user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev));
+       if (IS_ERR(user_dev))
+               return PTR_ERR(user_dev);
 
        udev->ff_effects_max = user_dev->ff_effects_max;
 
-       size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
-       if (!size) {
+       /* Ensure name is filled in */
+       if (!user_dev->name[0]) {
                retval = -EINVAL;
                goto exit;
        }
 
        kfree(dev->name);
-       dev->name = name = kmalloc(size, GFP_KERNEL);
-       if (!name) {
+       dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE,
+                            GFP_KERNEL);
+       if (!dev->name) {
                retval = -ENOMEM;
                goto exit;
        }
-       strlcpy(name, user_dev->name, size);
 
        dev->id.bustype = user_dev->id.bustype;
        dev->id.vendor  = user_dev->id.vendor;
@@ -622,7 +616,6 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
        struct uinput_ff_upload ff_up;
        struct uinput_ff_erase  ff_erase;
        struct uinput_request   *req;
-       int                     length;
        char                    *phys;
 
        retval = mutex_lock_interruptible(&udev->mutex);
@@ -689,24 +682,15 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
                                retval = -EINVAL;
                                goto out;
                        }
-                       length = strnlen_user(p, 1024);
-                       if (length <= 0) {
-                               retval = -EFAULT;
-                               break;
+
+                       phys = strndup_user(p, 1024);
+                       if (IS_ERR(phys)) {
+                               retval = PTR_ERR(phys);
+                               goto out;
                        }
+
                        kfree(udev->dev->phys);
-                       udev->dev->phys = phys = kmalloc(length, GFP_KERNEL);
-                       if (!phys) {
-                               retval = -ENOMEM;
-                               break;
-                       }
-                       if (copy_from_user(phys, p, length)) {
-                               udev->dev->phys = NULL;
-                               kfree(phys);
-                               retval = -EFAULT;
-                               break;
-                       }
-                       phys[length - 1] = '\0';
+                       udev->dev->phys = phys;
                        break;
 
                case UI_BEGIN_FF_UPLOAD:
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c
new file mode 100644 (file)
index 0000000..7077f9b
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Xen para-virtual input device
+ *
+ * Copyright (C) 2005 Anthony Liguori <[email protected]>
+ * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <[email protected]>
+ *
+ *  Based on linux/drivers/input/mouse/sermouse.c
+ *
+ *  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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/fbif.h>
+#include <xen/interface/io/kbdif.h>
+#include <xen/xenbus.h>
+
+struct xenkbd_info {
+       struct input_dev *kbd;
+       struct input_dev *ptr;
+       struct xenkbd_page *page;
+       int gref;
+       int irq;
+       struct xenbus_device *xbdev;
+       char phys[32];
+};
+
+static int xenkbd_remove(struct xenbus_device *);
+static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
+static void xenkbd_disconnect_backend(struct xenkbd_info *);
+
+/*
+ * Note: if you need to send out events, see xenfb_do_update() for how
+ * to do that.
+ */
+
+static irqreturn_t input_handler(int rq, void *dev_id)
+{
+       struct xenkbd_info *info = dev_id;
+       struct xenkbd_page *page = info->page;
+       __u32 cons, prod;
+
+       prod = page->in_prod;
+       if (prod == page->in_cons)
+               return IRQ_HANDLED;
+       rmb();                  /* ensure we see ring contents up to prod */
+       for (cons = page->in_cons; cons != prod; cons++) {
+               union xenkbd_in_event *event;
+               struct input_dev *dev;
+               event = &XENKBD_IN_RING_REF(page, cons);
+
+               dev = info->ptr;
+               switch (event->type) {
+               case XENKBD_TYPE_MOTION:
+                       input_report_rel(dev, REL_X, event->motion.rel_x);
+                       input_report_rel(dev, REL_Y, event->motion.rel_y);
+                       if (event->motion.rel_z)
+                               input_report_rel(dev, REL_WHEEL,
+                                                -event->motion.rel_z);
+                       break;
+               case XENKBD_TYPE_KEY:
+                       dev = NULL;
+                       if (test_bit(event->key.keycode, info->kbd->keybit))
+                               dev = info->kbd;
+                       if (test_bit(event->key.keycode, info->ptr->keybit))
+                               dev = info->ptr;
+                       if (dev)
+                               input_report_key(dev, event->key.keycode,
+                                                event->key.pressed);
+                       else
+                               pr_warning("unhandled keycode 0x%x\n",
+                                          event->key.keycode);
+                       break;
+               case XENKBD_TYPE_POS:
+                       input_report_abs(dev, ABS_X, event->pos.abs_x);
+                       input_report_abs(dev, ABS_Y, event->pos.abs_y);
+                       if (event->pos.rel_z)
+                               input_report_rel(dev, REL_WHEEL,
+                                                -event->pos.rel_z);
+                       break;
+               }
+               if (dev)
+                       input_sync(dev);
+       }
+       mb();                   /* ensure we got ring contents */
+       page->in_cons = cons;
+       notify_remote_via_irq(info->irq);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit xenkbd_probe(struct xenbus_device *dev,
+                                 const struct xenbus_device_id *id)
+{
+       int ret, i, abs;
+       struct xenkbd_info *info;
+       struct input_dev *kbd, *ptr;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+               return -ENOMEM;
+       }
+       dev_set_drvdata(&dev->dev, info);
+       info->xbdev = dev;
+       info->irq = -1;
+       info->gref = -1;
+       snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
+
+       info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+       if (!info->page)
+               goto error_nomem;
+
+       if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0)
+               abs = 0;
+       if (abs)
+               xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1");
+
+       /* keyboard */
+       kbd = input_allocate_device();
+       if (!kbd)
+               goto error_nomem;
+       kbd->name = "Xen Virtual Keyboard";
+       kbd->phys = info->phys;
+       kbd->id.bustype = BUS_PCI;
+       kbd->id.vendor = 0x5853;
+       kbd->id.product = 0xffff;
+
+       __set_bit(EV_KEY, kbd->evbit);
+       for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
+               __set_bit(i, kbd->keybit);
+       for (i = KEY_OK; i < KEY_MAX; i++)
+               __set_bit(i, kbd->keybit);
+
+       ret = input_register_device(kbd);
+       if (ret) {
+               input_free_device(kbd);
+               xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
+               goto error;
+       }
+       info->kbd = kbd;
+
+       /* pointing device */
+       ptr = input_allocate_device();
+       if (!ptr)
+               goto error_nomem;
+       ptr->name = "Xen Virtual Pointer";
+       ptr->phys = info->phys;
+       ptr->id.bustype = BUS_PCI;
+       ptr->id.vendor = 0x5853;
+       ptr->id.product = 0xfffe;
+
+       if (abs) {
+               __set_bit(EV_ABS, ptr->evbit);
+               input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
+               input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
+       } else {
+               input_set_capability(ptr, EV_REL, REL_X);
+               input_set_capability(ptr, EV_REL, REL_Y);
+       }
+       input_set_capability(ptr, EV_REL, REL_WHEEL);
+
+       __set_bit(EV_KEY, ptr->evbit);
+       for (i = BTN_LEFT; i <= BTN_TASK; i++)
+               __set_bit(i, ptr->keybit);
+
+       ret = input_register_device(ptr);
+       if (ret) {
+               input_free_device(ptr);
+               xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
+               goto error;
+       }
+       info->ptr = ptr;
+
+       ret = xenkbd_connect_backend(dev, info);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+ error_nomem:
+       ret = -ENOMEM;
+       xenbus_dev_fatal(dev, ret, "allocating device memory");
+ error:
+       xenkbd_remove(dev);
+       return ret;
+}
+
+static int xenkbd_resume(struct xenbus_device *dev)
+{
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+
+       xenkbd_disconnect_backend(info);
+       memset(info->page, 0, PAGE_SIZE);
+       return xenkbd_connect_backend(dev, info);
+}
+
+static int xenkbd_remove(struct xenbus_device *dev)
+{
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+
+       xenkbd_disconnect_backend(info);
+       if (info->kbd)
+               input_unregister_device(info->kbd);
+       if (info->ptr)
+               input_unregister_device(info->ptr);
+       free_page((unsigned long)info->page);
+       kfree(info);
+       return 0;
+}
+
+static int xenkbd_connect_backend(struct xenbus_device *dev,
+                                 struct xenkbd_info *info)
+{
+       int ret, evtchn;
+       struct xenbus_transaction xbt;
+
+       ret = gnttab_grant_foreign_access(dev->otherend_id,
+                                         virt_to_mfn(info->page), 0);
+       if (ret < 0)
+               return ret;
+       info->gref = ret;
+
+       ret = xenbus_alloc_evtchn(dev, &evtchn);
+       if (ret)
+               goto error_grant;
+       ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
+                                       0, dev->devicetype, info);
+       if (ret < 0) {
+               xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
+               goto error_evtchan;
+       }
+       info->irq = ret;
+
+ again:
+       ret = xenbus_transaction_start(&xbt);
+       if (ret) {
+               xenbus_dev_fatal(dev, ret, "starting transaction");
+               goto error_irqh;
+       }
+       ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
+                           virt_to_mfn(info->page));
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref);
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+                           evtchn);
+       if (ret)
+               goto error_xenbus;
+       ret = xenbus_transaction_end(xbt, 0);
+       if (ret) {
+               if (ret == -EAGAIN)
+                       goto again;
+               xenbus_dev_fatal(dev, ret, "completing transaction");
+               goto error_irqh;
+       }
+
+       xenbus_switch_state(dev, XenbusStateInitialised);
+       return 0;
+
+ error_xenbus:
+       xenbus_transaction_end(xbt, 1);
+       xenbus_dev_fatal(dev, ret, "writing xenstore");
+ error_irqh:
+       unbind_from_irqhandler(info->irq, info);
+       info->irq = -1;
+ error_evtchan:
+       xenbus_free_evtchn(dev, evtchn);
+ error_grant:
+       gnttab_end_foreign_access_ref(info->gref, 0);
+       info->gref = -1;
+       return ret;
+}
+
+static void xenkbd_disconnect_backend(struct xenkbd_info *info)
+{
+       if (info->irq >= 0)
+               unbind_from_irqhandler(info->irq, info);
+       info->irq = -1;
+       if (info->gref >= 0)
+               gnttab_end_foreign_access_ref(info->gref, 0);
+       info->gref = -1;
+}
+
+static void xenkbd_backend_changed(struct xenbus_device *dev,
+                                  enum xenbus_state backend_state)
+{
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
+       int val;
+
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitialised:
+       case XenbusStateReconfiguring:
+       case XenbusStateReconfigured:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateInitWait:
+InitWait:
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateConnected:
+               /*
+                * Work around xenbus race condition: If backend goes
+                * through InitWait to Connected fast enough, we can
+                * get Connected twice here.
+                */
+               if (dev->state != XenbusStateConnected)
+                       goto InitWait; /* no InitWait seen yet, fudge it */
+
+               /* Set input abs params to match backend screen res */
+               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                "width", "%d", &val) > 0)
+                       input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
+
+               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                                "height", "%d", &val) > 0)
+                       input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
+
+               break;
+
+       case XenbusStateClosing:
+               xenbus_frontend_closed(dev);
+               break;
+       }
+}
+
+static const struct xenbus_device_id xenkbd_ids[] = {
+       { "vkbd" },
+       { "" }
+};
+
+static struct xenbus_driver xenkbd_driver = {
+       .name = "vkbd",
+       .owner = THIS_MODULE,
+       .ids = xenkbd_ids,
+       .probe = xenkbd_probe,
+       .remove = xenkbd_remove,
+       .resume = xenkbd_resume,
+       .otherend_changed = xenkbd_backend_changed,
+};
+
+static int __init xenkbd_init(void)
+{
+       if (!xen_pv_domain())
+               return -ENODEV;
+
+       /* Nothing to do if running in dom0. */
+       if (xen_initial_domain())
+               return -ENODEV;
+
+       return xenbus_register_frontend(&xenkbd_driver);
+}
+
+static void __exit xenkbd_cleanup(void)
+{
+       xenbus_unregister_driver(&xenkbd_driver);
+}
+
+module_init(xenkbd_init);
+module_exit(xenkbd_cleanup);
+
+MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xen:vkbd");
index ee82851afe3ee9a660873b59d5fcb8cf39181ca7..3aead91bacc851d283458a2f48064ab36ec01320 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI  0x0242
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO   0x0243
 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS   0x0244
+/* Macbook8 (unibody, March 2011) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI   0x0245
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO    0x0246
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS    0x0247
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -96,6 +100,10 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
+       /* MacbookPro8 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
        /* Terminating entry */
        {}
 };
@@ -274,6 +282,18 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                { DIM_X, DIM_X / SN_COORD, -4616, 5112 },
                { DIM_Y, DIM_Y / SN_COORD, -142, 5234 }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING5_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING5_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+               { DIM_X, DIM_X / SN_COORD, -4415, 5050 },
+               { DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
+       },
        {}
 };
 
@@ -430,10 +450,6 @@ static int report_tp_state(struct bcm5974 *dev, int size)
                ptest = int2bound(&c->p, raw_p);
                origin = raw2int(f->origin);
 
-               /* set the integrated button if applicable */
-               if (c->tp_type == TYPE2)
-                       ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
-
                /* while tracking finger still valid, count all fingers */
                if (ptest > PRESSURE_LOW && origin) {
                        abs_p = ptest;
@@ -452,6 +468,10 @@ static int report_tp_state(struct bcm5974 *dev, int size)
                }
        }
 
+       /* set the integrated button if applicable */
+       if (c->tp_type == TYPE2)
+               ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
+
        if (dev->fingers < nmin)
                dev->fingers = nmin;
        if (dev->fingers > nmax)
index 0ae62f0bcb3216ca32c494e3a807a75a8f6753bd..f6aa26d305edd4e4922517610fbd8437aab62367 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/pm.h>
 
 #define DRIVER_NAME            "synaptics_i2c"
 /* maximum product id is 15 characters */
@@ -619,8 +620,9 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM
-static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int synaptics_i2c_suspend(struct device *dev)
 {
+       struct i2c_client *client = to_i2c_client(dev);
        struct synaptics_i2c *touch = i2c_get_clientdata(client);
 
        cancel_delayed_work_sync(&touch->dwork);
@@ -631,9 +633,10 @@ static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
        return 0;
 }
 
-static int synaptics_i2c_resume(struct i2c_client *client)
+static int synaptics_i2c_resume(struct device *dev)
 {
        int ret;
+       struct i2c_client *client = to_i2c_client(dev);
        struct synaptics_i2c *touch = i2c_get_clientdata(client);
 
        ret = synaptics_i2c_reset_config(client);
@@ -645,11 +648,11 @@ static int synaptics_i2c_resume(struct i2c_client *client)
 
        return 0;
 }
-#else
-#define synaptics_i2c_suspend  NULL
-#define synaptics_i2c_resume   NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
+                        synaptics_i2c_resume);
+
 static const struct i2c_device_id synaptics_i2c_id_table[] = {
        { "synaptics_i2c", 0 },
        { },
@@ -660,13 +663,12 @@ static struct i2c_driver synaptics_i2c_driver = {
        .driver = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
+               .pm     = &synaptics_i2c_pm,
        },
 
        .probe          = synaptics_i2c_probe,
        .remove         = __devexit_p(synaptics_i2c_remove),
 
-       .suspend        = synaptics_i2c_suspend,
-       .resume         = synaptics_i2c_resume,
        .id_table       = synaptics_i2c_id_table,
 };
 
index 7729e547ba65d853581e115a4ce6428883549ecd..337bf51bc984253abf9a77b558eb36c8c10deb53 100644 (file)
@@ -210,8 +210,8 @@ int sparse_keymap_setup(struct input_dev *dev,
 
        dev->keycode = map;
        dev->keycodemax = map_size;
-       dev->getkeycode_new = sparse_keymap_getkeycode;
-       dev->setkeycode_new = sparse_keymap_setkeycode;
+       dev->getkeycode = sparse_keymap_getkeycode;
+       dev->setkeycode = sparse_keymap_setkeycode;
 
        return 0;
 
index cf8fb9f5d4a8282f9405736af668d5f8cd423a4b..449c0a46dbac51ba881ba49b8cfff1c3861dfee7 100644 (file)
@@ -193,16 +193,16 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                        case HID_USAGE_X:
                                if (usage == WCM_DESKTOP) {
                                        if (finger) {
-                                               features->device_type = BTN_TOOL_DOUBLETAP;
+                                               features->device_type = BTN_TOOL_FINGER;
                                                if (features->type == TABLETPC2FG) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_TPC2FG;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                }
                                                if (features->type == BAMBOO_PT) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_BBTOUCH;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                        features->x_phy =
                                                                get_unaligned_le16(&report[i + 5]);
                                                        features->x_max =
@@ -241,11 +241,11 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                        case HID_USAGE_Y:
                                if (usage == WCM_DESKTOP) {
                                        if (finger) {
-                                               features->device_type = BTN_TOOL_DOUBLETAP;
+                                               features->device_type = BTN_TOOL_FINGER;
                                                if (features->type == TABLETPC2FG) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_TPC2FG;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                        features->y_max =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->y_phy =
@@ -254,7 +254,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi
                                                } else if (features->type == BAMBOO_PT) {
                                                        /* need to reset back */
                                                        features->pktlen = WACOM_PKGLEN_BBTOUCH;
-                                                       features->device_type = BTN_TOOL_TRIPLETAP;
+                                                       features->device_type = BTN_TOOL_DOUBLETAP;
                                                        features->y_phy =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->y_max =
index 367fa82a607e81ef8bf03d7b69c8bc231736fc65..5597637cfd41895181176f627f072ac3f0c39a77 100644 (file)
@@ -675,169 +675,87 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        return 1;
 }
 
-
-static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx)
+static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 {
        struct input_dev *input = wacom->input;
-       int finger = idx + 1;
-       int x = le16_to_cpup((__le16 *)&data[finger * 2]) & 0x7fff;
-       int y = le16_to_cpup((__le16 *)&data[4 + finger * 2]) & 0x7fff;
+       unsigned char *data = wacom->data;
+       int contact_with_no_pen_down_count = 0;
+       int i;
 
-       /*
-        * Work around input core suppressing "duplicate" events since
-        * we are abusing ABS_X/ABS_Y to transmit multi-finger data.
-        * This should go away once we switch to true multitouch
-        * protocol.
-        */
-       if (wacom->last_finger != finger) {
-               if (x == input_abs_get_val(input, ABS_X))
-                       x++;
+       for (i = 0; i < 2; i++) {
+               int p = data[1] & (1 << i);
+               bool touch = p && !wacom->shared->stylus_in_proximity;
+
+               input_mt_slot(input, i);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+               if (touch) {
+                       int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff;
+                       int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff;
 
-               if (y == input_abs_get_val(input, ABS_Y))
-                       y++;
+                       input_report_abs(input, ABS_MT_POSITION_X, x);
+                       input_report_abs(input, ABS_MT_POSITION_Y, y);
+                       contact_with_no_pen_down_count++;
+               }
        }
 
-       input_report_abs(input, ABS_X, x);
-       input_report_abs(input, ABS_Y, y);
-       input_report_abs(input, ABS_MISC, wacom->id[0]);
-       input_report_key(input, wacom->tool[finger], 1);
-       if (!idx)
-               input_report_key(input, BTN_TOUCH, 1);
-       input_event(input, EV_MSC, MSC_SERIAL, finger);
-       input_sync(input);
+       /* keep touch state for pen event */
+       wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 
-       wacom->last_finger = finger;
-}
+       input_mt_report_pointer_emulation(input, true);
 
-static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx)
-{
-       struct input_dev *input = wacom->input;
-       int finger = idx + 1;
-
-       input_report_abs(input, ABS_X, 0);
-       input_report_abs(input, ABS_Y, 0);
-       input_report_abs(input, ABS_MISC, 0);
-       input_report_key(input, wacom->tool[finger], 0);
-       if (!idx)
-               input_report_key(input, BTN_TOUCH, 0);
-       input_event(input, EV_MSC, MSC_SERIAL, finger);
-       input_sync(input);
+       return 1;
 }
 
-static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len)
+static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
 {
        char *data = wacom->data;
        struct input_dev *input = wacom->input;
+       bool prox;
+       int x = 0, y = 0;
 
-       wacom->tool[1] = BTN_TOOL_DOUBLETAP;
-       wacom->id[0] = TOUCH_DEVICE_ID;
-       wacom->tool[2] = BTN_TOOL_TRIPLETAP;
-
-       if (len != WACOM_PKGLEN_TPC1FG) {
-
-               switch (data[0]) {
+       if (!wacom->shared->stylus_in_proximity) {
+               if (len == WACOM_PKGLEN_TPC1FG) {
+                       prox = data[0] & 0x01;
+                       x = get_unaligned_le16(&data[1]);
+                       y = get_unaligned_le16(&data[3]);
+               } else { /* with capacity */
+                       prox = data[1] & 0x01;
+                       x = le16_to_cpup((__le16 *)&data[2]);
+                       y = le16_to_cpup((__le16 *)&data[4]);
+               }
+       } else
+               /* force touch out when pen is in prox */
+               prox = 0;
 
-               case WACOM_REPORT_TPC1FG:
-                       input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
-                       input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
-                       input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6]));
-                       input_report_key(input, BTN_TOUCH, le16_to_cpup((__le16 *)&data[6]));
-                       input_report_abs(input, ABS_MISC, wacom->id[0]);
-                       input_report_key(input, wacom->tool[1], 1);
-                       input_sync(input);
-                       break;
+       if (prox) {
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+       }
+       input_report_key(input, BTN_TOUCH, prox);
 
-               case WACOM_REPORT_TPC2FG:
-                       if (data[1] & 0x01)
-                               wacom_tpc_finger_in(wacom, data, 0);
-                       else if (wacom->id[1] & 0x01)
-                               wacom_tpc_touch_out(wacom, 0);
+       /* keep touch state for pen events */
+       wacom->shared->touch_down = prox;
 
-                       if (data[1] & 0x02)
-                               wacom_tpc_finger_in(wacom, data, 1);
-                       else if (wacom->id[1] & 0x02)
-                               wacom_tpc_touch_out(wacom, 1);
-                       break;
-               }
-       } else {
-               input_report_abs(input, ABS_X, get_unaligned_le16(&data[1]));
-               input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3]));
-               input_report_key(input, BTN_TOUCH, 1);
-               input_report_abs(input, ABS_MISC, wacom->id[1]);
-               input_report_key(input, wacom->tool[1], 1);
-               input_sync(input);
-       }
+       return 1;
 }
 
-static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
+static int wacom_tpc_pen(struct wacom_wac *wacom)
 {
        struct wacom_features *features = &wacom->features;
        char *data = wacom->data;
        struct input_dev *input = wacom->input;
-       int prox = 0, pressure;
-       int retval = 0;
+       int pressure;
+       bool prox = data[1] & 0x20;
 
-       dbg("wacom_tpc_irq: received report #%d", data[0]);
-
-       if (len == WACOM_PKGLEN_TPC1FG ||                /* single touch */
-           data[0] == WACOM_REPORT_TPC1FG ||            /* single touch */
-           data[0] == WACOM_REPORT_TPC2FG) {            /* 2FG touch */
-
-               if (wacom->shared->stylus_in_proximity) {
-                       if (wacom->id[1] & 0x01)
-                               wacom_tpc_touch_out(wacom, 0);
-
-                       if (wacom->id[1] & 0x02)
-                               wacom_tpc_touch_out(wacom, 1);
-
-                       wacom->id[1] = 0;
-                       return 0;
-               }
-
-               if (len == WACOM_PKGLEN_TPC1FG) {       /* with touch */
-                       prox = data[0] & 0x01;
-               } else {  /* with capacity */
-                       if (data[0] == WACOM_REPORT_TPC1FG)
-                               /* single touch */
-                               prox = data[1] & 0x01;
-                       else
-                               /* 2FG touch data */
-                               prox = data[1] & 0x03;
-               }
-
-               if (prox) {
-                       if (!wacom->id[1])
-                               wacom->last_finger = 1;
-                       wacom_tpc_touch_in(wacom, len);
-               } else {
-                       if (data[0] == WACOM_REPORT_TPC2FG) {
-                               /* 2FGT out-prox */
-                               if (wacom->id[1] & 0x01)
-                                       wacom_tpc_touch_out(wacom, 0);
+       if (!wacom->shared->stylus_in_proximity) /* first in prox */
+               /* Going into proximity select tool */
+               wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
 
-                               if (wacom->id[1] & 0x02)
-                                       wacom_tpc_touch_out(wacom, 1);
-                       } else
-                               /* one finger touch */
-                               wacom_tpc_touch_out(wacom, 0);
+       /* keep pen state for touch events */
+       wacom->shared->stylus_in_proximity = prox;
 
-                       wacom->id[0] = 0;
-               }
-               /* keep prox bit to send proper out-prox event */
-               wacom->id[1] = prox;
-       } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */
-               prox = data[1] & 0x20;
-
-               if (!wacom->shared->stylus_in_proximity) { /* first in prox */
-                       /* Going into proximity select tool */
-                       wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-                       if (wacom->tool[0] == BTN_TOOL_PEN)
-                               wacom->id[0] = STYLUS_DEVICE_ID;
-                       else
-                               wacom->id[0] = ERASER_DEVICE_ID;
-
-                       wacom->shared->stylus_in_proximity = true;
-               }
+       /* send pen events only when touch is up or forced out */
+       if (!wacom->shared->touch_down) {
                input_report_key(input, BTN_STYLUS, data[1] & 0x02);
                input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
                input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
@@ -847,15 +765,27 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
                        pressure = features->pressure_max + pressure + 1;
                input_report_abs(input, ABS_PRESSURE, pressure);
                input_report_key(input, BTN_TOUCH, data[1] & 0x05);
-               if (!prox) { /* out-prox */
-                       wacom->id[0] = 0;
-                       wacom->shared->stylus_in_proximity = false;
-               }
                input_report_key(input, wacom->tool[0], prox);
-               input_report_abs(input, ABS_MISC, wacom->id[0]);
-               retval = 1;
+               return 1;
        }
-       return retval;
+
+       return 0;
+}
+
+static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
+{
+       char *data = wacom->data;
+
+       dbg("wacom_tpc_irq: received report #%d", data[0]);
+
+       if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG)
+               return wacom_tpc_single_touch(wacom, len);
+       else if (data[0] == WACOM_REPORT_TPC2FG)
+               return wacom_tpc_mt_touch(wacom);
+       else if (data[0] == WACOM_REPORT_PENABLED)
+               return wacom_tpc_pen(wacom);
+
+       return 0;
 }
 
 static int wacom_bpt_touch(struct wacom_wac *wacom)
@@ -1078,7 +1008,7 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 {
 
        /* touch device found but size is not defined. use default */
-       if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) {
+       if (features->device_type == BTN_TOOL_FINGER && !features->x_max) {
                features->x_max = 1023;
                features->y_max = 1023;
        }
@@ -1090,7 +1020,7 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 
        /* quirks for bamboo touch */
        if (features->type == BAMBOO_PT &&
-           features->device_type == BTN_TOOL_TRIPLETAP) {
+           features->device_type == BTN_TOOL_DOUBLETAP) {
                features->x_max <<= 5;
                features->y_max <<= 5;
                features->x_fuzz <<= 5;
@@ -1226,27 +1156,30 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                break;
 
        case TABLETPC2FG:
-               if (features->device_type == BTN_TOOL_TRIPLETAP) {
-                       __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-                       input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
+               if (features->device_type == BTN_TOOL_DOUBLETAP) {
+
+                       input_mt_init_slots(input_dev, 2);
+                       input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
+                                       0, MT_TOOL_MAX, 0, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+                                       0, features->x_max, 0, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                                       0, features->y_max, 0, 0);
                }
                /* fall through */
 
        case TABLETPC:
-               if (features->device_type == BTN_TOOL_DOUBLETAP ||
-                   features->device_type == BTN_TOOL_TRIPLETAP) {
+               __clear_bit(ABS_MISC, input_dev->absbit);
+
+               if (features->device_type != BTN_TOOL_PEN) {
                        input_abs_set_res(input_dev, ABS_X,
                                wacom_calculate_touch_res(features->x_max,
                                                        features->x_phy));
                        input_abs_set_res(input_dev, ABS_Y,
                                wacom_calculate_touch_res(features->y_max,
                                                        features->y_phy));
-                       __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-               }
-
-               if (features->device_type != BTN_TOOL_PEN)
                        break;  /* no need to process stylus stuff */
-
+               }
                /* fall through */
 
        case PL:
@@ -1264,7 +1197,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
        case BAMBOO_PT:
                __clear_bit(ABS_MISC, input_dev->absbit);
 
-               if (features->device_type == BTN_TOOL_TRIPLETAP) {
+               if (features->device_type == BTN_TOOL_DOUBLETAP) {
                        __set_bit(BTN_LEFT, input_dev->keybit);
                        __set_bit(BTN_FORWARD, input_dev->keybit);
                        __set_bit(BTN_BACK, input_dev->keybit);
index b1310ec9720c0613ab6a219cbe421d6e6eb62241..835f756b150c193fb9b46b4cd3ae6cccefa0a851 100644 (file)
@@ -88,15 +88,15 @@ struct wacom_features {
 
 struct wacom_shared {
        bool stylus_in_proximity;
+       bool touch_down;
 };
 
 struct wacom_wac {
        char name[64];
        unsigned char *data;
-       int tool[3];
-       int id[3];
+       int tool[2];
+       int id[2];
        __u32 serial[2];
-       int last_finger;
        struct wacom_features features;
        struct wacom_shared *shared;
        struct input_dev *input;
index 61834ae282e13c72be5ea2fad3dca266debc91b3..112ec55f2939733d53cc1a85c926cc4ee42618fd 100644 (file)
@@ -86,6 +86,18 @@ config TOUCHSCREEN_AD7879_SPI
          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_BITSY
        tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
        depends on SA1100_BITSY
@@ -339,18 +351,6 @@ config TOUCHSCREEN_PENMOUNT
          To compile this driver as a module, choose M here: the
          module will be called penmount.
 
-config TOUCHSCREEN_QT602240
-       tristate "QT602240 I2C Touchscreen"
-       depends on I2C
-       help
-         Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
-         connected to your system.
-
-         If unsure, say N.
-
-         To compile this driver as a module, choose M here: the
-         module will be called qt602240_ts.
-
 config TOUCHSCREEN_MIGOR
        tristate "Renesas MIGO-R touchscreen"
        depends on SH_MIGOR && I2C
@@ -423,6 +423,16 @@ config TOUCHSCREEN_UCB1400
          To compile this driver as a module, choose M here: the
          module will be called ucb1400_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
@@ -629,6 +639,17 @@ config TOUCHSCREEN_TOUCHIT213
          To compile this driver as a module, choose M here: the
          module will be called touchit213.
 
+config TOUCHSCREEN_TSC2005
+        tristate "TSC2005 based touchscreens"
+        depends on SPI_MASTER
+        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
index 718bcc814952cd38b82b3c2b086a05ec19ed983d..ca94098d4c92b8116815c17a9ac742e77aa622e3 100644 (file)
@@ -12,6 +12,7 @@ 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_BITSY)                += h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
@@ -37,7 +38,6 @@ 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_QT602240)     += qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)       += st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)                += stmpe-ts.o
@@ -45,9 +45,11 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X)  += tnetv107x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)   += touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.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
index a1952fcc083e14a68694b5f69c64359588818b2c..714d4e0f9f95f546affadbdbc677d87c27152bc0 100644 (file)
@@ -41,6 +41,7 @@
 #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>
@@ -826,39 +827,37 @@ static int __devexit ad7877_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int ad7877_suspend(struct spi_device *spi, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int ad7877_suspend(struct device *dev)
 {
-       struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        ad7877_disable(ts);
 
        return 0;
 }
 
-static int ad7877_resume(struct spi_device *spi)
+static int ad7877_resume(struct device *dev)
 {
-       struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+       struct ad7877 *ts = dev_get_drvdata(dev);
 
        ad7877_enable(ts);
 
        return 0;
 }
-#else
-#define ad7877_suspend NULL
-#define ad7877_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
+
 static struct spi_driver ad7877_driver = {
        .driver = {
                .name   = "ad7877",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &ad7877_pm,
        },
        .probe          = ad7877_probe,
        .remove         = __devexit_p(ad7877_remove),
-       .suspend        = ad7877_suspend,
-       .resume         = ad7877_resume,
 };
 
 static int __init ad7877_init(void)
index 59c6e68c432507a61392993b572541dc2c8693a4..ddf732f3cafcd3021c889f435d2d1c662f627663 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/input.h>       /* BUS_SPI */
+#include <linux/pm.h>
 #include <linux/spi/spi.h>
 
 #include "ad7879.h"
 #define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
 #define AD7879_READCMD(reg)  (AD7879_CMD(reg) | AD7879_CMD_READ)
 
-#ifdef CONFIG_PM
-static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int ad7879_spi_suspend(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct ad7879 *ts = spi_get_drvdata(spi);
 
        ad7879_suspend(ts);
@@ -30,19 +32,19 @@ static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message)
        return 0;
 }
 
-static int ad7879_spi_resume(struct spi_device *spi)
+static int ad7879_spi_resume(struct device *dev)
 {
+       struct spi_device *spi = to_spi_device(dev);
        struct ad7879 *ts = spi_get_drvdata(spi);
 
        ad7879_resume(ts);
 
        return 0;
 }
-#else
-# define ad7879_spi_suspend NULL
-# define ad7879_spi_resume  NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(ad7879_spi_pm, ad7879_spi_suspend, ad7879_spi_resume);
+
 /*
  * ad7879_read/write are only used for initial setup and for sysfs controls.
  * The main traffic is done in ad7879_collect().
@@ -173,11 +175,10 @@ static struct spi_driver ad7879_spi_driver = {
                .name   = "ad7879",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &ad7879_spi_pm,
        },
        .probe          = ad7879_spi_probe,
        .remove         = __devexit_p(ad7879_spi_remove),
-       .suspend        = ad7879_spi_suspend,
-       .resume         = ad7879_spi_resume,
 };
 
 static int __init ad7879_spi_init(void)
index 4bf2316e3284b8db426e6e11d2dfda72166b1278..c24946f512564e35925d0e6c090b7fd4a6c4eccd 100644 (file)
@@ -26,6 +26,7 @@
 #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>
@@ -892,9 +893,10 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
        return IRQ_HANDLED;
 }
 
-static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int ads7846_suspend(struct device *dev)
 {
-       struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+       struct ads7846 *ts = dev_get_drvdata(dev);
 
        mutex_lock(&ts->lock);
 
@@ -914,9 +916,9 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
        return 0;
 }
 
-static int ads7846_resume(struct spi_device *spi)
+static int ads7846_resume(struct device *dev)
 {
-       struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+       struct ads7846 *ts = dev_get_drvdata(dev);
 
        mutex_lock(&ts->lock);
 
@@ -935,6 +937,9 @@ static int ads7846_resume(struct spi_device *spi)
 
        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)
 {
@@ -1408,11 +1413,10 @@ static struct spi_driver ads7846_driver = {
                .name   = "ads7846",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
+               .pm     = &ads7846_pm,
        },
        .probe          = ads7846_probe,
        .remove         = __devexit_p(ads7846_remove),
-       .suspend        = ads7846_suspend,
-       .resume         = ads7846_resume,
 };
 
 static int __init ads7846_init(void)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
new file mode 100644 (file)
index 0000000..4012436
--- /dev/null
@@ -0,0 +1,1211 @@
+/*
+ * Atmel maXTouch Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#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.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   37
+#define MXT_GEN_MESSAGE                5
+#define MXT_GEN_COMMAND                6
+#define MXT_GEN_POWER          7
+#define MXT_GEN_ACQUIRE                8
+#define MXT_TOUCH_MULTI                9
+#define MXT_TOUCH_KEYARRAY     15
+#define MXT_TOUCH_PROXIMITY    23
+#define MXT_PROCI_GRIPFACE     20
+#define MXT_PROCG_NOISE                22
+#define MXT_PROCI_ONETOUCH     24
+#define MXT_PROCI_TWOTOUCH     27
+#define MXT_PROCI_GRIP         40
+#define MXT_PROCI_PALM         41
+#define MXT_SPT_COMMSCONFIG    18
+#define MXT_SPT_GPIOPWM                19
+#define MXT_SPT_SELFTEST       25
+#define MXT_SPT_CTECONFIG      28
+#define MXT_SPT_USERDATA       38
+#define MXT_SPT_DIGITIZER      43
+#define MXT_SPT_MESSAGECOUNT   44
+
+/* MXT_GEN_COMMAND 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 field */
+#define MXT_POWER_IDLEACQINT   0
+#define MXT_POWER_ACTVACQINT   1
+#define MXT_POWER_ACTV2IDLETO  2
+
+/* MXT_GEN_ACQUIRE 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 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 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 */
+#define MXT_COMMS_CTRL         0
+#define MXT_COMMS_CMD          1
+
+/* MXT_SPT_CTECONFIG 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 */
+#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)
+
+/* Touchscreen absolute values */
+#define MXT_MAX_XC             0x3ff
+#define MXT_MAX_YC             0x3ff
+#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;
+};
+
+/* 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;
+};
+
+static bool mxt_object_readable(unsigned int type)
+{
+       switch (type) {
+       case MXT_GEN_MESSAGE:
+       case MXT_GEN_COMMAND:
+       case MXT_GEN_POWER:
+       case MXT_GEN_ACQUIRE:
+       case MXT_TOUCH_MULTI:
+       case MXT_TOUCH_KEYARRAY:
+       case MXT_TOUCH_PROXIMITY:
+       case MXT_PROCI_GRIPFACE:
+       case MXT_PROCG_NOISE:
+       case MXT_PROCI_ONETOUCH:
+       case MXT_PROCI_TWOTOUCH:
+       case MXT_PROCI_GRIP:
+       case MXT_PROCI_PALM:
+       case MXT_SPT_COMMSCONFIG:
+       case MXT_SPT_GPIOPWM:
+       case MXT_SPT_SELFTEST:
+       case MXT_SPT_CTECONFIG:
+       case MXT_SPT_USERDATA:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool mxt_object_writable(unsigned int type)
+{
+       switch (type) {
+       case MXT_GEN_COMMAND:
+       case MXT_GEN_POWER:
+       case MXT_GEN_ACQUIRE:
+       case MXT_TOUCH_MULTI:
+       case MXT_TOUCH_KEYARRAY:
+       case MXT_TOUCH_PROXIMITY:
+       case MXT_PROCI_GRIPFACE:
+       case MXT_PROCG_NOISE:
+       case MXT_PROCI_ONETOUCH:
+       case MXT_PROCI_TWOTOUCH:
+       case MXT_PROCI_GRIP:
+       case MXT_PROCI_PALM:
+       case MXT_SPT_GPIOPWM:
+       case MXT_SPT_SELFTEST:
+       case MXT_SPT_CTECONFIG:
+               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);
+       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_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+                               finger[id].status != MXT_RELEASE ?
+                               finger[id].area : 0);
+               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_mt_sync(input_dev);
+
+               if (finger[id].status == MXT_RELEASE)
+                       finger[id].status = 0;
+               else
+                       finger_num++;
+       }
+
+       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_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;
+
+       /* 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] << 2) | ((message->message[3] & ~0x3f) >> 6);
+       y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+       area = message->message[4];
+
+       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;
+
+       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 */
+               object = mxt_get_object(data, MXT_TOUCH_MULTI);
+               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; 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;
+       }
+
+       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, MXT_TOUCH_XSIZE,
+                       pdata->x_line);
+       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YSIZE,
+                       pdata->y_line);
+
+       /* Set touchscreen orient */
+       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_ORIENT,
+                       pdata->orient);
+
+       /* Set touchscreen burst length */
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_BLEN, pdata->blen);
+
+       /* Set touchscreen threshold */
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_TCHTHR, pdata->threshold);
+
+       /* Set touchscreen resolution */
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
+       mxt_write_object(data, MXT_TOUCH_MULTI,
+                       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,
+                               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;
+
+       error = mxt_make_highchg(data);
+       if (error)
+               return error;
+
+       mxt_handle_pdata(data);
+
+       /* Backup to memory */
+       mxt_write_object(data, MXT_GEN_COMMAND,
+                       MXT_COMMAND_BACKUPNV,
+                       MXT_BACKUP_VALUE);
+       msleep(MXT_BACKUP_TIME);
+
+       /* Soft reset */
+       mxt_write_object(data, MXT_GEN_COMMAND,
+                       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 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 += sprintf(buf + count,
+                               "Object Table Element %d(Type %d)\n",
+                               i + 1, object->type);
+
+               if (!mxt_object_readable(object->type)) {
+                       count += sprintf(buf + count, "\n");
+                       continue;
+               }
+
+               for (j = 0; j < object->size + 1; j++) {
+                       error = mxt_read_object(data,
+                                               object->type, j, &val);
+                       if (error)
+                               return error;
+
+                       count += sprintf(buf + count,
+                                       "  Byte %d: 0x%x (%d)\n", j, val, val);
+               }
+
+               count += sprintf(buf + count, "\n");
+       }
+
+       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,
+                       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);
+
+       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, MXT_TOUCH_CTRL, 0x83);
+}
+
+static void mxt_stop(struct mxt_data *data)
+{
+       /* Touch disable */
+       mxt_write_object(data,
+                       MXT_TOUCH_MULTI, 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;
+
+       __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, MXT_MAX_XC, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y,
+                            0, MXT_MAX_YC, 0, 0);
+
+       /* For multi touch */
+       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, MXT_MAX_XC, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                            0, MXT_MAX_YC, 0, 0);
+
+       input_set_drvdata(input_dev, data);
+
+       data->client = client;
+       data->input_dev = input_dev;
+       data->pdata = pdata;
+       data->irq = client->irq;
+
+       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 = 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,
+                       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,
+};
+
+static int __init mxt_init(void)
+{
+       return i2c_add_driver(&mxt_driver);
+}
+
+static void __exit mxt_exit(void)
+{
+       i2c_del_driver(&mxt_driver);
+}
+
+module_init(mxt_init);
+module_exit(mxt_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <[email protected]>");
+MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c
deleted file mode 100644 (file)
index 4dcb0e8..0000000
+++ /dev/null
@@ -1,1406 +0,0 @@
-/*
- * AT42QT602240/ATMXT224 Touchscreen driver
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <[email protected]>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <linux/i2c/qt602240_ts.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-/* Version */
-#define QT602240_VER_20                        20
-#define QT602240_VER_21                        21
-#define QT602240_VER_22                        22
-
-/* Slave addresses */
-#define QT602240_APP_LOW               0x4a
-#define QT602240_APP_HIGH              0x4b
-#define QT602240_BOOT_LOW              0x24
-#define QT602240_BOOT_HIGH             0x25
-
-/* Firmware */
-#define QT602240_FW_NAME               "qt602240.fw"
-
-/* Registers */
-#define QT602240_FAMILY_ID             0x00
-#define QT602240_VARIANT_ID            0x01
-#define QT602240_VERSION               0x02
-#define QT602240_BUILD                 0x03
-#define QT602240_MATRIX_X_SIZE         0x04
-#define QT602240_MATRIX_Y_SIZE         0x05
-#define QT602240_OBJECT_NUM            0x06
-#define QT602240_OBJECT_START          0x07
-
-#define QT602240_OBJECT_SIZE           6
-
-/* Object types */
-#define QT602240_DEBUG_DIAGNOSTIC      37
-#define QT602240_GEN_MESSAGE           5
-#define QT602240_GEN_COMMAND           6
-#define QT602240_GEN_POWER             7
-#define QT602240_GEN_ACQUIRE           8
-#define QT602240_TOUCH_MULTI           9
-#define QT602240_TOUCH_KEYARRAY                15
-#define QT602240_TOUCH_PROXIMITY       23
-#define QT602240_PROCI_GRIPFACE                20
-#define QT602240_PROCG_NOISE           22
-#define QT602240_PROCI_ONETOUCH                24
-#define QT602240_PROCI_TWOTOUCH                27
-#define QT602240_SPT_COMMSCONFIG       18      /* firmware ver 21 over */
-#define QT602240_SPT_GPIOPWM           19
-#define QT602240_SPT_SELFTEST          25
-#define QT602240_SPT_CTECONFIG         28
-#define QT602240_SPT_USERDATA          38      /* firmware ver 21 over */
-
-/* QT602240_GEN_COMMAND field */
-#define QT602240_COMMAND_RESET         0
-#define QT602240_COMMAND_BACKUPNV      1
-#define QT602240_COMMAND_CALIBRATE     2
-#define QT602240_COMMAND_REPORTALL     3
-#define QT602240_COMMAND_DIAGNOSTIC    5
-
-/* QT602240_GEN_POWER field */
-#define QT602240_POWER_IDLEACQINT      0
-#define QT602240_POWER_ACTVACQINT      1
-#define QT602240_POWER_ACTV2IDLETO     2
-
-/* QT602240_GEN_ACQUIRE field */
-#define QT602240_ACQUIRE_CHRGTIME      0
-#define QT602240_ACQUIRE_TCHDRIFT      2
-#define QT602240_ACQUIRE_DRIFTST       3
-#define QT602240_ACQUIRE_TCHAUTOCAL    4
-#define QT602240_ACQUIRE_SYNC          5
-#define QT602240_ACQUIRE_ATCHCALST     6
-#define QT602240_ACQUIRE_ATCHCALSTHR   7
-
-/* QT602240_TOUCH_MULTI field */
-#define QT602240_TOUCH_CTRL            0
-#define QT602240_TOUCH_XORIGIN         1
-#define QT602240_TOUCH_YORIGIN         2
-#define QT602240_TOUCH_XSIZE           3
-#define QT602240_TOUCH_YSIZE           4
-#define QT602240_TOUCH_BLEN            6
-#define QT602240_TOUCH_TCHTHR          7
-#define QT602240_TOUCH_TCHDI           8
-#define QT602240_TOUCH_ORIENT          9
-#define QT602240_TOUCH_MOVHYSTI                11
-#define QT602240_TOUCH_MOVHYSTN                12
-#define QT602240_TOUCH_NUMTOUCH                14
-#define QT602240_TOUCH_MRGHYST         15
-#define QT602240_TOUCH_MRGTHR          16
-#define QT602240_TOUCH_AMPHYST         17
-#define QT602240_TOUCH_XRANGE_LSB      18
-#define QT602240_TOUCH_XRANGE_MSB      19
-#define QT602240_TOUCH_YRANGE_LSB      20
-#define QT602240_TOUCH_YRANGE_MSB      21
-#define QT602240_TOUCH_XLOCLIP         22
-#define QT602240_TOUCH_XHICLIP         23
-#define QT602240_TOUCH_YLOCLIP         24
-#define QT602240_TOUCH_YHICLIP         25
-#define QT602240_TOUCH_XEDGECTRL       26
-#define QT602240_TOUCH_XEDGEDIST       27
-#define QT602240_TOUCH_YEDGECTRL       28
-#define QT602240_TOUCH_YEDGEDIST       29
-#define QT602240_TOUCH_JUMPLIMIT       30      /* firmware ver 22 over */
-
-/* QT602240_PROCI_GRIPFACE field */
-#define QT602240_GRIPFACE_CTRL         0
-#define QT602240_GRIPFACE_XLOGRIP      1
-#define QT602240_GRIPFACE_XHIGRIP      2
-#define QT602240_GRIPFACE_YLOGRIP      3
-#define QT602240_GRIPFACE_YHIGRIP      4
-#define QT602240_GRIPFACE_MAXTCHS      5
-#define QT602240_GRIPFACE_SZTHR1       7
-#define QT602240_GRIPFACE_SZTHR2       8
-#define QT602240_GRIPFACE_SHPTHR1      9
-#define QT602240_GRIPFACE_SHPTHR2      10
-#define QT602240_GRIPFACE_SUPEXTTO     11
-
-/* QT602240_PROCI_NOISE field */
-#define QT602240_NOISE_CTRL            0
-#define QT602240_NOISE_OUTFLEN         1
-#define QT602240_NOISE_GCAFUL_LSB      3
-#define QT602240_NOISE_GCAFUL_MSB      4
-#define QT602240_NOISE_GCAFLL_LSB      5
-#define QT602240_NOISE_GCAFLL_MSB      6
-#define QT602240_NOISE_ACTVGCAFVALID   7
-#define QT602240_NOISE_NOISETHR                8
-#define QT602240_NOISE_FREQHOPSCALE    10
-#define QT602240_NOISE_FREQ0           11
-#define QT602240_NOISE_FREQ1           12
-#define QT602240_NOISE_FREQ2           13
-#define QT602240_NOISE_FREQ3           14
-#define QT602240_NOISE_FREQ4           15
-#define QT602240_NOISE_IDLEGCAFVALID   16
-
-/* QT602240_SPT_COMMSCONFIG */
-#define QT602240_COMMS_CTRL            0
-#define QT602240_COMMS_CMD             1
-
-/* QT602240_SPT_CTECONFIG field */
-#define QT602240_CTE_CTRL              0
-#define QT602240_CTE_CMD               1
-#define QT602240_CTE_MODE              2
-#define QT602240_CTE_IDLEGCAFDEPTH     3
-#define QT602240_CTE_ACTVGCAFDEPTH     4
-#define QT602240_CTE_VOLTAGE           5       /* firmware ver 21 over */
-
-#define QT602240_VOLTAGE_DEFAULT       2700000
-#define QT602240_VOLTAGE_STEP          10000
-
-/* Define for QT602240_GEN_COMMAND */
-#define QT602240_BOOT_VALUE            0xa5
-#define QT602240_BACKUP_VALUE          0x55
-#define QT602240_BACKUP_TIME           25      /* msec */
-#define QT602240_RESET_TIME            65      /* msec */
-
-#define QT602240_FWRESET_TIME          175     /* msec */
-
-/* Command to unlock bootloader */
-#define QT602240_UNLOCK_CMD_MSB                0xaa
-#define QT602240_UNLOCK_CMD_LSB                0xdc
-
-/* Bootloader mode status */
-#define QT602240_WAITING_BOOTLOAD_CMD  0xc0    /* valid 7 6 bit only */
-#define QT602240_WAITING_FRAME_DATA    0x80    /* valid 7 6 bit only */
-#define QT602240_FRAME_CRC_CHECK       0x02
-#define QT602240_FRAME_CRC_FAIL                0x03
-#define QT602240_FRAME_CRC_PASS                0x04
-#define QT602240_APP_CRC_FAIL          0x40    /* valid 7 8 bit only */
-#define QT602240_BOOT_STATUS_MASK      0x3f
-
-/* Touch status */
-#define QT602240_SUPPRESS              (1 << 1)
-#define QT602240_AMP                   (1 << 2)
-#define QT602240_VECTOR                        (1 << 3)
-#define QT602240_MOVE                  (1 << 4)
-#define QT602240_RELEASE               (1 << 5)
-#define QT602240_PRESS                 (1 << 6)
-#define QT602240_DETECT                        (1 << 7)
-
-/* Touchscreen absolute values */
-#define QT602240_MAX_XC                        0x3ff
-#define QT602240_MAX_YC                        0x3ff
-#define QT602240_MAX_AREA              0xff
-
-#define QT602240_MAX_FINGER            10
-
-/* Initial register values recommended from chip vendor */
-static const u8 init_vals_ver_20[] = {
-       /* QT602240_GEN_COMMAND(6) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_GEN_POWER(7) */
-       0x20, 0xff, 0x32,
-       /* QT602240_GEN_ACQUIRE(8) */
-       0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14,
-       /* QT602240_TOUCH_MULTI(9) */
-       0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64,
-       /* QT602240_TOUCH_KEYARRAY(15) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_SPT_GPIOPWM(19) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00,
-       /* QT602240_PROCI_GRIPFACE(20) */
-       0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04,
-       0x1e, 0x00,
-       /* QT602240_PROCG_NOISE(22) */
-       0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00,
-       0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8,
-       /* QT602240_TOUCH_PROXIMITY(23) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00,
-       /* QT602240_PROCI_ONETOUCH(24) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_SELFTEST(25) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_TWOTOUCH(27) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_CTECONFIG(28) */
-       0x00, 0x00, 0x00, 0x04, 0x08,
-};
-
-static const u8 init_vals_ver_21[] = {
-       /* QT602240_GEN_COMMAND(6) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_GEN_POWER(7) */
-       0x20, 0xff, 0x32,
-       /* QT602240_GEN_ACQUIRE(8) */
-       0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
-       /* QT602240_TOUCH_MULTI(9) */
-       0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_TOUCH_KEYARRAY(15) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_SPT_GPIOPWM(19) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_GRIPFACE(20) */
-       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
-       0x0f, 0x0a,
-       /* QT602240_PROCG_NOISE(22) */
-       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
-       0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
-       /* QT602240_TOUCH_PROXIMITY(23) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00,
-       /* QT602240_PROCI_ONETOUCH(24) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_SELFTEST(25) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_TWOTOUCH(27) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_CTECONFIG(28) */
-       0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
-};
-
-static const u8 init_vals_ver_22[] = {
-       /* QT602240_GEN_COMMAND(6) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_GEN_POWER(7) */
-       0x20, 0xff, 0x32,
-       /* QT602240_GEN_ACQUIRE(8) */
-       0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
-       /* QT602240_TOUCH_MULTI(9) */
-       0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
-       0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_TOUCH_KEYARRAY(15) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00,
-       /* QT602240_SPT_GPIOPWM(19) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_GRIPFACE(20) */
-       0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
-       0x0f, 0x0a,
-       /* QT602240_PROCG_NOISE(22) */
-       0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
-       0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
-       /* QT602240_TOUCH_PROXIMITY(23) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_ONETOUCH(24) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_SELFTEST(25) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       /* QT602240_PROCI_TWOTOUCH(27) */
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       /* QT602240_SPT_CTECONFIG(28) */
-       0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
-};
-
-struct qt602240_info {
-       u8 family_id;
-       u8 variant_id;
-       u8 version;
-       u8 build;
-       u8 matrix_xsize;
-       u8 matrix_ysize;
-       u8 object_num;
-};
-
-struct qt602240_object {
-       u8 type;
-       u16 start_address;
-       u8 size;
-       u8 instances;
-       u8 num_report_ids;
-
-       /* to map object and message */
-       u8 max_reportid;
-};
-
-struct qt602240_message {
-       u8 reportid;
-       u8 message[7];
-       u8 checksum;
-};
-
-struct qt602240_finger {
-       int status;
-       int x;
-       int y;
-       int area;
-};
-
-/* Each client has this additional data */
-struct qt602240_data {
-       struct i2c_client *client;
-       struct input_dev *input_dev;
-       const struct qt602240_platform_data *pdata;
-       struct qt602240_object *object_table;
-       struct qt602240_info info;
-       struct qt602240_finger finger[QT602240_MAX_FINGER];
-       unsigned int irq;
-};
-
-static bool qt602240_object_readable(unsigned int type)
-{
-       switch (type) {
-       case QT602240_GEN_MESSAGE:
-       case QT602240_GEN_COMMAND:
-       case QT602240_GEN_POWER:
-       case QT602240_GEN_ACQUIRE:
-       case QT602240_TOUCH_MULTI:
-       case QT602240_TOUCH_KEYARRAY:
-       case QT602240_TOUCH_PROXIMITY:
-       case QT602240_PROCI_GRIPFACE:
-       case QT602240_PROCG_NOISE:
-       case QT602240_PROCI_ONETOUCH:
-       case QT602240_PROCI_TWOTOUCH:
-       case QT602240_SPT_COMMSCONFIG:
-       case QT602240_SPT_GPIOPWM:
-       case QT602240_SPT_SELFTEST:
-       case QT602240_SPT_CTECONFIG:
-       case QT602240_SPT_USERDATA:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static bool qt602240_object_writable(unsigned int type)
-{
-       switch (type) {
-       case QT602240_GEN_COMMAND:
-       case QT602240_GEN_POWER:
-       case QT602240_GEN_ACQUIRE:
-       case QT602240_TOUCH_MULTI:
-       case QT602240_TOUCH_KEYARRAY:
-       case QT602240_TOUCH_PROXIMITY:
-       case QT602240_PROCI_GRIPFACE:
-       case QT602240_PROCG_NOISE:
-       case QT602240_PROCI_ONETOUCH:
-       case QT602240_PROCI_TWOTOUCH:
-       case QT602240_SPT_GPIOPWM:
-       case QT602240_SPT_SELFTEST:
-       case QT602240_SPT_CTECONFIG:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static void qt602240_dump_message(struct device *dev,
-                                 struct qt602240_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 qt602240_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 QT602240_WAITING_BOOTLOAD_CMD:
-       case QT602240_WAITING_FRAME_DATA:
-               val &= ~QT602240_BOOT_STATUS_MASK;
-               break;
-       case QT602240_FRAME_CRC_PASS:
-               if (val == QT602240_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 qt602240_unlock_bootloader(struct i2c_client *client)
-{
-       u8 buf[2];
-
-       buf[0] = QT602240_UNLOCK_CMD_LSB;
-       buf[1] = QT602240_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 qt602240_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 __qt602240_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 qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val)
-{
-       return __qt602240_read_reg(client, reg, 1, val);
-}
-
-static int qt602240_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 qt602240_read_object_table(struct i2c_client *client,
-                                     u16 reg, u8 *object_buf)
-{
-       return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE,
-                                  object_buf);
-}
-
-static struct qt602240_object *
-qt602240_get_object(struct qt602240_data *data, u8 type)
-{
-       struct qt602240_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 qt602240_read_message(struct qt602240_data *data,
-                                struct qt602240_message *message)
-{
-       struct qt602240_object *object;
-       u16 reg;
-
-       object = qt602240_get_object(data, QT602240_GEN_MESSAGE);
-       if (!object)
-               return -EINVAL;
-
-       reg = object->start_address;
-       return __qt602240_read_reg(data->client, reg,
-                       sizeof(struct qt602240_message), message);
-}
-
-static int qt602240_read_object(struct qt602240_data *data,
-                               u8 type, u8 offset, u8 *val)
-{
-       struct qt602240_object *object;
-       u16 reg;
-
-       object = qt602240_get_object(data, type);
-       if (!object)
-               return -EINVAL;
-
-       reg = object->start_address;
-       return __qt602240_read_reg(data->client, reg + offset, 1, val);
-}
-
-static int qt602240_write_object(struct qt602240_data *data,
-                                u8 type, u8 offset, u8 val)
-{
-       struct qt602240_object *object;
-       u16 reg;
-
-       object = qt602240_get_object(data, type);
-       if (!object)
-               return -EINVAL;
-
-       reg = object->start_address;
-       return qt602240_write_reg(data->client, reg + offset, val);
-}
-
-static void qt602240_input_report(struct qt602240_data *data, int single_id)
-{
-       struct qt602240_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 < QT602240_MAX_FINGER; id++) {
-               if (!finger[id].status)
-                       continue;
-
-               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
-                               finger[id].status != QT602240_RELEASE ?
-                               finger[id].area : 0);
-               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_mt_sync(input_dev);
-
-               if (finger[id].status == QT602240_RELEASE)
-                       finger[id].status = 0;
-               else
-                       finger_num++;
-       }
-
-       input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
-
-       if (status != QT602240_RELEASE) {
-               input_report_abs(input_dev, ABS_X, finger[single_id].x);
-               input_report_abs(input_dev, ABS_Y, finger[single_id].y);
-       }
-
-       input_sync(input_dev);
-}
-
-static void qt602240_input_touchevent(struct qt602240_data *data,
-                                     struct qt602240_message *message, int id)
-{
-       struct qt602240_finger *finger = data->finger;
-       struct device *dev = &data->client->dev;
-       u8 status = message->message[0];
-       int x;
-       int y;
-       int area;
-
-       /* Check the touch is present on the screen */
-       if (!(status & QT602240_DETECT)) {
-               if (status & QT602240_RELEASE) {
-                       dev_dbg(dev, "[%d] released\n", id);
-
-                       finger[id].status = QT602240_RELEASE;
-                       qt602240_input_report(data, id);
-               }
-               return;
-       }
-
-       /* Check only AMP detection */
-       if (!(status & (QT602240_PRESS | QT602240_MOVE)))
-               return;
-
-       x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
-       y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
-       area = message->message[4];
-
-       dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
-               status & QT602240_MOVE ? "moved" : "pressed",
-               x, y, area);
-
-       finger[id].status = status & QT602240_MOVE ?
-                               QT602240_MOVE : QT602240_PRESS;
-       finger[id].x = x;
-       finger[id].y = y;
-       finger[id].area = area;
-
-       qt602240_input_report(data, id);
-}
-
-static irqreturn_t qt602240_interrupt(int irq, void *dev_id)
-{
-       struct qt602240_data *data = dev_id;
-       struct qt602240_message message;
-       struct qt602240_object *object;
-       struct device *dev = &data->client->dev;
-       int id;
-       u8 reportid;
-       u8 max_reportid;
-       u8 min_reportid;
-
-       do {
-               if (qt602240_read_message(data, &message)) {
-                       dev_err(dev, "Failed to read message\n");
-                       goto end;
-               }
-
-               reportid = message.reportid;
-
-               /* whether reportid is thing of QT602240_TOUCH_MULTI */
-               object = qt602240_get_object(data, QT602240_TOUCH_MULTI);
-               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)
-                       qt602240_input_touchevent(data, &message, id);
-               else
-                       qt602240_dump_message(dev, &message);
-       } while (reportid != 0xff);
-
-end:
-       return IRQ_HANDLED;
-}
-
-static int qt602240_check_reg_init(struct qt602240_data *data)
-{
-       struct qt602240_object *object;
-       struct device *dev = &data->client->dev;
-       int index = 0;
-       int i, j;
-       u8 version = data->info.version;
-       u8 *init_vals;
-
-       switch (version) {
-       case QT602240_VER_20:
-               init_vals = (u8 *)init_vals_ver_20;
-               break;
-       case QT602240_VER_21:
-               init_vals = (u8 *)init_vals_ver_21;
-               break;
-       case QT602240_VER_22:
-               init_vals = (u8 *)init_vals_ver_22;
-               break;
-       default:
-               dev_err(dev, "Firmware version %d doesn't support\n", version);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < data->info.object_num; i++) {
-               object = data->object_table + i;
-
-               if (!qt602240_object_writable(object->type))
-                       continue;
-
-               for (j = 0; j < object->size + 1; j++)
-                       qt602240_write_object(data, object->type, j,
-                                       init_vals[index + j]);
-
-               index += object->size + 1;
-       }
-
-       return 0;
-}
-
-static int qt602240_check_matrix_size(struct qt602240_data *data)
-{
-       const struct qt602240_platform_data *pdata = data->pdata;
-       struct device *dev = &data->client->dev;
-       int mode = -1;
-       int error;
-       u8 val;
-
-       dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line);
-       dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line);
-
-       switch (pdata->x_line) {
-       case 0 ... 15:
-               if (pdata->y_line <= 14)
-                       mode = 0;
-               break;
-       case 16:
-               if (pdata->y_line <= 12)
-                       mode = 1;
-               if (pdata->y_line == 13 || pdata->y_line == 14)
-                       mode = 0;
-               break;
-       case 17:
-               if (pdata->y_line <= 11)
-                       mode = 2;
-               if (pdata->y_line == 12 || pdata->y_line == 13)
-                       mode = 1;
-               break;
-       case 18:
-               if (pdata->y_line <= 10)
-                       mode = 3;
-               if (pdata->y_line == 11 || pdata->y_line == 12)
-                       mode = 2;
-               break;
-       case 19:
-               if (pdata->y_line <= 9)
-                       mode = 4;
-               if (pdata->y_line == 10 || pdata->y_line == 11)
-                       mode = 3;
-               break;
-       case 20:
-               mode = 4;
-       }
-
-       if (mode < 0) {
-               dev_err(dev, "Invalid X/Y lines\n");
-               return -EINVAL;
-       }
-
-       error = qt602240_read_object(data, QT602240_SPT_CTECONFIG,
-                               QT602240_CTE_MODE, &val);
-       if (error)
-               return error;
-
-       if (mode == val)
-               return 0;
-
-       /* Change the CTE configuration */
-       qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                       QT602240_CTE_CTRL, 1);
-       qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                       QT602240_CTE_MODE, mode);
-       qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                       QT602240_CTE_CTRL, 0);
-
-       return 0;
-}
-
-static int qt602240_make_highchg(struct qt602240_data *data)
-{
-       struct device *dev = &data->client->dev;
-       int count = 10;
-       int error;
-       u8 val;
-
-       /* Read dummy message to make high CHG pin */
-       do {
-               error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val);
-               if (error)
-                       return error;
-       } while ((val != 0xff) && --count);
-
-       if (!count) {
-               dev_err(dev, "CHG pin isn't cleared\n");
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-static void qt602240_handle_pdata(struct qt602240_data *data)
-{
-       const struct qt602240_platform_data *pdata = data->pdata;
-       u8 voltage;
-
-       /* Set touchscreen lines */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE,
-                       pdata->x_line);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE,
-                       pdata->y_line);
-
-       /* Set touchscreen orient */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT,
-                       pdata->orient);
-
-       /* Set touchscreen burst length */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_BLEN, pdata->blen);
-
-       /* Set touchscreen threshold */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_TCHTHR, pdata->threshold);
-
-       /* Set touchscreen resolution */
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
-       qt602240_write_object(data, QT602240_TOUCH_MULTI,
-                       QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
-
-       /* Set touchscreen voltage */
-       if (data->info.version >= QT602240_VER_21 && pdata->voltage) {
-               if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) {
-                       voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) /
-                               QT602240_VOLTAGE_STEP;
-                       voltage = 0xff - voltage + 1;
-               } else
-                       voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) /
-                               QT602240_VOLTAGE_STEP;
-
-               qt602240_write_object(data, QT602240_SPT_CTECONFIG,
-                               QT602240_CTE_VOLTAGE, voltage);
-       }
-}
-
-static int qt602240_get_info(struct qt602240_data *data)
-{
-       struct i2c_client *client = data->client;
-       struct qt602240_info *info = &data->info;
-       int error;
-       u8 val;
-
-       error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val);
-       if (error)
-               return error;
-       info->family_id = val;
-
-       error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val);
-       if (error)
-               return error;
-       info->variant_id = val;
-
-       error = qt602240_read_reg(client, QT602240_VERSION, &val);
-       if (error)
-               return error;
-       info->version = val;
-
-       error = qt602240_read_reg(client, QT602240_BUILD, &val);
-       if (error)
-               return error;
-       info->build = val;
-
-       error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val);
-       if (error)
-               return error;
-       info->object_num = val;
-
-       return 0;
-}
-
-static int qt602240_get_object_table(struct qt602240_data *data)
-{
-       int error;
-       int i;
-       u16 reg;
-       u8 reportid = 0;
-       u8 buf[QT602240_OBJECT_SIZE];
-
-       for (i = 0; i < data->info.object_num; i++) {
-               struct qt602240_object *object = data->object_table + i;
-
-               reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i;
-               error = qt602240_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 qt602240_initialize(struct qt602240_data *data)
-{
-       struct i2c_client *client = data->client;
-       struct qt602240_info *info = &data->info;
-       int error;
-       u8 val;
-
-       error = qt602240_get_info(data);
-       if (error)
-               return error;
-
-       data->object_table = kcalloc(info->object_num,
-                                    sizeof(struct qt602240_object),
-                                    GFP_KERNEL);
-       if (!data->object_table) {
-               dev_err(&client->dev, "Failed to allocate memory\n");
-               return -ENOMEM;
-       }
-
-       /* Get object table information */
-       error = qt602240_get_object_table(data);
-       if (error)
-               return error;
-
-       /* Check register init values */
-       error = qt602240_check_reg_init(data);
-       if (error)
-               return error;
-
-       /* Check X/Y matrix size */
-       error = qt602240_check_matrix_size(data);
-       if (error)
-               return error;
-
-       error = qt602240_make_highchg(data);
-       if (error)
-               return error;
-
-       qt602240_handle_pdata(data);
-
-       /* Backup to memory */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_BACKUPNV,
-                       QT602240_BACKUP_VALUE);
-       msleep(QT602240_BACKUP_TIME);
-
-       /* Soft reset */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_RESET, 1);
-       msleep(QT602240_RESET_TIME);
-
-       /* Update matrix size at info struct */
-       error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val);
-       if (error)
-               return error;
-       info->matrix_xsize = val;
-
-       error = qt602240_read_reg(client, QT602240_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 ssize_t qt602240_object_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct qt602240_data *data = dev_get_drvdata(dev);
-       struct qt602240_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 += sprintf(buf + count,
-                               "Object Table Element %d(Type %d)\n",
-                               i + 1, object->type);
-
-               if (!qt602240_object_readable(object->type)) {
-                       count += sprintf(buf + count, "\n");
-                       continue;
-               }
-
-               for (j = 0; j < object->size + 1; j++) {
-                       error = qt602240_read_object(data,
-                                               object->type, j, &val);
-                       if (error)
-                               return error;
-
-                       count += sprintf(buf + count,
-                                       "  Byte %d: 0x%x (%d)\n", j, val, val);
-               }
-
-               count += sprintf(buf + count, "\n");
-       }
-
-       return count;
-}
-
-static int qt602240_load_fw(struct device *dev, const char *fn)
-{
-       struct qt602240_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 */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_RESET, QT602240_BOOT_VALUE);
-       msleep(QT602240_RESET_TIME);
-
-       /* Change to slave address of bootloader */
-       if (client->addr == QT602240_APP_LOW)
-               client->addr = QT602240_BOOT_LOW;
-       else
-               client->addr = QT602240_BOOT_HIGH;
-
-       ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD);
-       if (ret)
-               goto out;
-
-       /* Unlock bootloader */
-       qt602240_unlock_bootloader(client);
-
-       while (pos < fw->size) {
-               ret = qt602240_check_bootloader(client,
-                                               QT602240_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 */
-               qt602240_fw_write(client, fw->data + pos, frame_size);
-
-               ret = qt602240_check_bootloader(client,
-                                               QT602240_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 == QT602240_BOOT_LOW)
-               client->addr = QT602240_APP_LOW;
-       else
-               client->addr = QT602240_APP_HIGH;
-
-       return ret;
-}
-
-static ssize_t qt602240_update_fw_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count)
-{
-       struct qt602240_data *data = dev_get_drvdata(dev);
-       unsigned int version;
-       int error;
-
-       if (sscanf(buf, "%u", &version) != 1) {
-               dev_err(dev, "Invalid values\n");
-               return -EINVAL;
-       }
-
-       if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) {
-               dev_err(dev, "FW update supported starting with version 21\n");
-               return -EINVAL;
-       }
-
-       disable_irq(data->irq);
-
-       error = qt602240_load_fw(dev, QT602240_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(QT602240_FWRESET_TIME);
-
-               kfree(data->object_table);
-               data->object_table = NULL;
-
-               qt602240_initialize(data);
-       }
-
-       enable_irq(data->irq);
-
-       return count;
-}
-
-static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL);
-static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store);
-
-static struct attribute *qt602240_attrs[] = {
-       &dev_attr_object.attr,
-       &dev_attr_update_fw.attr,
-       NULL
-};
-
-static const struct attribute_group qt602240_attr_group = {
-       .attrs = qt602240_attrs,
-};
-
-static void qt602240_start(struct qt602240_data *data)
-{
-       /* Touch enable */
-       qt602240_write_object(data,
-                       QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83);
-}
-
-static void qt602240_stop(struct qt602240_data *data)
-{
-       /* Touch disable */
-       qt602240_write_object(data,
-                       QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0);
-}
-
-static int qt602240_input_open(struct input_dev *dev)
-{
-       struct qt602240_data *data = input_get_drvdata(dev);
-
-       qt602240_start(data);
-
-       return 0;
-}
-
-static void qt602240_input_close(struct input_dev *dev)
-{
-       struct qt602240_data *data = input_get_drvdata(dev);
-
-       qt602240_stop(data);
-}
-
-static int __devinit qt602240_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
-{
-       struct qt602240_data *data;
-       struct input_dev *input_dev;
-       int error;
-
-       if (!client->dev.platform_data)
-               return -EINVAL;
-
-       data = kzalloc(sizeof(struct qt602240_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 = "AT42QT602240/ATMXT224 Touchscreen";
-       input_dev->id.bustype = BUS_I2C;
-       input_dev->dev.parent = &client->dev;
-       input_dev->open = qt602240_input_open;
-       input_dev->close = qt602240_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, QT602240_MAX_XC, 0, 0);
-       input_set_abs_params(input_dev, ABS_Y,
-                            0, QT602240_MAX_YC, 0, 0);
-
-       /* For multi touch */
-       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
-                            0, QT602240_MAX_AREA, 0, 0);
-       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-                            0, QT602240_MAX_XC, 0, 0);
-       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-                            0, QT602240_MAX_YC, 0, 0);
-
-       input_set_drvdata(input_dev, data);
-
-       data->client = client;
-       data->input_dev = input_dev;
-       data->pdata = client->dev.platform_data;
-       data->irq = client->irq;
-
-       i2c_set_clientdata(client, data);
-
-       error = qt602240_initialize(data);
-       if (error)
-               goto err_free_object;
-
-       error = request_threaded_irq(client->irq, NULL, qt602240_interrupt,
-                       IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
-       if (error) {
-               dev_err(&client->dev, "Failed to register interrupt\n");
-               goto err_free_object;
-       }
-
-       error = input_register_device(input_dev);
-       if (error)
-               goto err_free_irq;
-
-       error = sysfs_create_group(&client->dev.kobj, &qt602240_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 qt602240_remove(struct i2c_client *client)
-{
-       struct qt602240_data *data = i2c_get_clientdata(client);
-
-       sysfs_remove_group(&client->dev.kobj, &qt602240_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 qt602240_suspend(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct qt602240_data *data = i2c_get_clientdata(client);
-       struct input_dev *input_dev = data->input_dev;
-
-       mutex_lock(&input_dev->mutex);
-
-       if (input_dev->users)
-               qt602240_stop(data);
-
-       mutex_unlock(&input_dev->mutex);
-
-       return 0;
-}
-
-static int qt602240_resume(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct qt602240_data *data = i2c_get_clientdata(client);
-       struct input_dev *input_dev = data->input_dev;
-
-       /* Soft reset */
-       qt602240_write_object(data, QT602240_GEN_COMMAND,
-                       QT602240_COMMAND_RESET, 1);
-
-       msleep(QT602240_RESET_TIME);
-
-       mutex_lock(&input_dev->mutex);
-
-       if (input_dev->users)
-               qt602240_start(data);
-
-       mutex_unlock(&input_dev->mutex);
-
-       return 0;
-}
-
-static const struct dev_pm_ops qt602240_pm_ops = {
-       .suspend        = qt602240_suspend,
-       .resume         = qt602240_resume,
-};
-#endif
-
-static const struct i2c_device_id qt602240_id[] = {
-       { "qt602240_ts", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, qt602240_id);
-
-static struct i2c_driver qt602240_driver = {
-       .driver = {
-               .name   = "qt602240_ts",
-               .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
-               .pm     = &qt602240_pm_ops,
-#endif
-       },
-       .probe          = qt602240_probe,
-       .remove         = __devexit_p(qt602240_remove),
-       .id_table       = qt602240_id,
-};
-
-static int __init qt602240_init(void)
-{
-       return i2c_add_driver(&qt602240_driver);
-}
-
-static void __exit qt602240_exit(void)
-{
-       i2c_del_driver(&qt602240_driver);
-}
-
-module_init(qt602240_init);
-module_exit(qt602240_exit);
-
-/* Module information */
-MODULE_AUTHOR("Joonyoung Shim <[email protected]>");
-MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
new file mode 100644 (file)
index 0000000..8742061
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ *
+ * Author: Lauri Leukkunen <[email protected]>
+ * based on TSC2301 driver by Klaus K. Pedersen <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 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(jiffies +
+                                       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 mode_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);
+       mode_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;
+
+       mutex_lock(&ts->mutex);
+
+       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:
+       /* re-arm the watchdog */
+       schedule_delayed_work(&ts->esd_work,
+                             round_jiffies(jiffies +
+                                       msecs_to_jiffies(ts->esd_timeout)));
+       mutex_unlock(&ts->mutex);
+}
+
+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;
+       }
+
+       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),
+};
+
+static int __init tsc2005_init(void)
+{
+       return spi_register_driver(&tsc2005_driver);
+}
+module_init(tsc2005_init);
+
+static void __exit tsc2005_exit(void)
+{
+       spi_unregister_driver(&tsc2005_driver);
+}
+module_exit(tsc2005_exit);
+
+MODULE_AUTHOR("Lauri Leukkunen <[email protected]>");
+MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
new file mode 100644 (file)
index 0000000..6ae054f
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Touchscreen driver for WM831x PMICs
+ *
+ * Copyright 2011 Wolfson Microelectronics plc.
+ * Author: Mark Brown <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#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;
+};
+
+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) {
+               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);
+       }
+
+       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;
+
+       /* 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);
+
+       input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1);
+       input_sync(wm831x_ts->input_dev);
+
+       wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1,
+                       WM831X_TCHPD_EINT, WM831X_TCHPD_EINT);
+
+       wm831x_ts->pen_down = true;
+       enable_irq(wm831x_ts->data_irq);
+
+       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;
+
+       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, 0);
+
+       if (wm831x_ts->pen_down)
+               disable_irq(wm831x_ts->data_irq);
+}
+
+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;
+
+       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;
+
+       /*
+        * 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);
+
+       error = request_threaded_irq(wm831x_ts->data_irq,
+                                    NULL, wm831x_ts_data_irq,
+                                    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);
+
+       error = request_threaded_irq(wm831x_ts->pd_irq,
+                                    NULL, wm831x_ts_pen_down_irq,
+                                    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),
+};
+
+static int __init wm831x_ts_init(void)
+{
+       return platform_driver_register(&wm831x_ts_driver);
+}
+module_init(wm831x_ts_init);
+
+static void __exit wm831x_ts_exit(void)
+{
+       platform_driver_unregister(&wm831x_ts_driver);
+}
+module_exit(wm831x_ts_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <[email protected]>");
+MODULE_DESCRIPTION("WM831x PMIC touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm831x-touch");
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c
deleted file mode 100644 (file)
index 7f85a86..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Xen para-virtual input device
- *
- * Copyright (C) 2005 Anthony Liguori <[email protected]>
- * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <[email protected]>
- *
- *  Based on linux/drivers/input/mouse/sermouse.c
- *
- *  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.
- */
-
-/*
- * TODO:
- *
- * Switch to grant tables together with xen-fbfront.c.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-
-#include <asm/xen/hypervisor.h>
-
-#include <xen/xen.h>
-#include <xen/events.h>
-#include <xen/page.h>
-#include <xen/interface/io/fbif.h>
-#include <xen/interface/io/kbdif.h>
-#include <xen/xenbus.h>
-
-struct xenkbd_info {
-       struct input_dev *kbd;
-       struct input_dev *ptr;
-       struct xenkbd_page *page;
-       int irq;
-       struct xenbus_device *xbdev;
-       char phys[32];
-};
-
-static int xenkbd_remove(struct xenbus_device *);
-static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
-static void xenkbd_disconnect_backend(struct xenkbd_info *);
-
-/*
- * Note: if you need to send out events, see xenfb_do_update() for how
- * to do that.
- */
-
-static irqreturn_t input_handler(int rq, void *dev_id)
-{
-       struct xenkbd_info *info = dev_id;
-       struct xenkbd_page *page = info->page;
-       __u32 cons, prod;
-
-       prod = page->in_prod;
-       if (prod == page->in_cons)
-               return IRQ_HANDLED;
-       rmb();                  /* ensure we see ring contents up to prod */
-       for (cons = page->in_cons; cons != prod; cons++) {
-               union xenkbd_in_event *event;
-               struct input_dev *dev;
-               event = &XENKBD_IN_RING_REF(page, cons);
-
-               dev = info->ptr;
-               switch (event->type) {
-               case XENKBD_TYPE_MOTION:
-                       input_report_rel(dev, REL_X, event->motion.rel_x);
-                       input_report_rel(dev, REL_Y, event->motion.rel_y);
-                       if (event->motion.rel_z)
-                               input_report_rel(dev, REL_WHEEL,
-                                                -event->motion.rel_z);
-                       break;
-               case XENKBD_TYPE_KEY:
-                       dev = NULL;
-                       if (test_bit(event->key.keycode, info->kbd->keybit))
-                               dev = info->kbd;
-                       if (test_bit(event->key.keycode, info->ptr->keybit))
-                               dev = info->ptr;
-                       if (dev)
-                               input_report_key(dev, event->key.keycode,
-                                                event->key.pressed);
-                       else
-                               pr_warning("unhandled keycode 0x%x\n",
-                                          event->key.keycode);
-                       break;
-               case XENKBD_TYPE_POS:
-                       input_report_abs(dev, ABS_X, event->pos.abs_x);
-                       input_report_abs(dev, ABS_Y, event->pos.abs_y);
-                       if (event->pos.rel_z)
-                               input_report_rel(dev, REL_WHEEL,
-                                                -event->pos.rel_z);
-                       break;
-               }
-               if (dev)
-                       input_sync(dev);
-       }
-       mb();                   /* ensure we got ring contents */
-       page->in_cons = cons;
-       notify_remote_via_irq(info->irq);
-
-       return IRQ_HANDLED;
-}
-
-static int __devinit xenkbd_probe(struct xenbus_device *dev,
-                                 const struct xenbus_device_id *id)
-{
-       int ret, i;
-       struct xenkbd_info *info;
-       struct input_dev *kbd, *ptr;
-
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info) {
-               xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
-               return -ENOMEM;
-       }
-       dev_set_drvdata(&dev->dev, info);
-       info->xbdev = dev;
-       info->irq = -1;
-       snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
-
-       info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
-       if (!info->page)
-               goto error_nomem;
-
-       /* keyboard */
-       kbd = input_allocate_device();
-       if (!kbd)
-               goto error_nomem;
-       kbd->name = "Xen Virtual Keyboard";
-       kbd->phys = info->phys;
-       kbd->id.bustype = BUS_PCI;
-       kbd->id.vendor = 0x5853;
-       kbd->id.product = 0xffff;
-       kbd->evbit[0] = BIT(EV_KEY);
-       for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
-               set_bit(i, kbd->keybit);
-       for (i = KEY_OK; i < KEY_MAX; i++)
-               set_bit(i, kbd->keybit);
-
-       ret = input_register_device(kbd);
-       if (ret) {
-               input_free_device(kbd);
-               xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
-               goto error;
-       }
-       info->kbd = kbd;
-
-       /* pointing device */
-       ptr = input_allocate_device();
-       if (!ptr)
-               goto error_nomem;
-       ptr->name = "Xen Virtual Pointer";
-       ptr->phys = info->phys;
-       ptr->id.bustype = BUS_PCI;
-       ptr->id.vendor = 0x5853;
-       ptr->id.product = 0xfffe;
-       ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
-       for (i = BTN_LEFT; i <= BTN_TASK; i++)
-               set_bit(i, ptr->keybit);
-       ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
-       input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
-       input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
-
-       ret = input_register_device(ptr);
-       if (ret) {
-               input_free_device(ptr);
-               xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
-               goto error;
-       }
-       info->ptr = ptr;
-
-       ret = xenkbd_connect_backend(dev, info);
-       if (ret < 0)
-               goto error;
-
-       return 0;
-
- error_nomem:
-       ret = -ENOMEM;
-       xenbus_dev_fatal(dev, ret, "allocating device memory");
- error:
-       xenkbd_remove(dev);
-       return ret;
-}
-
-static int xenkbd_resume(struct xenbus_device *dev)
-{
-       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
-
-       xenkbd_disconnect_backend(info);
-       memset(info->page, 0, PAGE_SIZE);
-       return xenkbd_connect_backend(dev, info);
-}
-
-static int xenkbd_remove(struct xenbus_device *dev)
-{
-       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
-
-       xenkbd_disconnect_backend(info);
-       if (info->kbd)
-               input_unregister_device(info->kbd);
-       if (info->ptr)
-               input_unregister_device(info->ptr);
-       free_page((unsigned long)info->page);
-       kfree(info);
-       return 0;
-}
-
-static int xenkbd_connect_backend(struct xenbus_device *dev,
-                                 struct xenkbd_info *info)
-{
-       int ret, evtchn;
-       struct xenbus_transaction xbt;
-
-       ret = xenbus_alloc_evtchn(dev, &evtchn);
-       if (ret)
-               return ret;
-       ret = bind_evtchn_to_irqhandler(evtchn, input_handler,
-                                       0, dev->devicetype, info);
-       if (ret < 0) {
-               xenbus_free_evtchn(dev, evtchn);
-               xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
-               return ret;
-       }
-       info->irq = ret;
-
- again:
-       ret = xenbus_transaction_start(&xbt);
-       if (ret) {
-               xenbus_dev_fatal(dev, ret, "starting transaction");
-               return ret;
-       }
-       ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
-                           virt_to_mfn(info->page));
-       if (ret)
-               goto error_xenbus;
-       ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
-                           evtchn);
-       if (ret)
-               goto error_xenbus;
-       ret = xenbus_transaction_end(xbt, 0);
-       if (ret) {
-               if (ret == -EAGAIN)
-                       goto again;
-               xenbus_dev_fatal(dev, ret, "completing transaction");
-               return ret;
-       }
-
-       xenbus_switch_state(dev, XenbusStateInitialised);
-       return 0;
-
- error_xenbus:
-       xenbus_transaction_end(xbt, 1);
-       xenbus_dev_fatal(dev, ret, "writing xenstore");
-       return ret;
-}
-
-static void xenkbd_disconnect_backend(struct xenkbd_info *info)
-{
-       if (info->irq >= 0)
-               unbind_from_irqhandler(info->irq, info);
-       info->irq = -1;
-}
-
-static void xenkbd_backend_changed(struct xenbus_device *dev,
-                                  enum xenbus_state backend_state)
-{
-       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
-       int ret, val;
-
-       switch (backend_state) {
-       case XenbusStateInitialising:
-       case XenbusStateInitialised:
-       case XenbusStateReconfiguring:
-       case XenbusStateReconfigured:
-       case XenbusStateUnknown:
-       case XenbusStateClosed:
-               break;
-
-       case XenbusStateInitWait:
-InitWait:
-               ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                                  "feature-abs-pointer", "%d", &val);
-               if (ret < 0)
-                       val = 0;
-               if (val) {
-                       ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
-                                           "request-abs-pointer", "1");
-                       if (ret)
-                               pr_warning("can't request abs-pointer\n");
-               }
-               xenbus_switch_state(dev, XenbusStateConnected);
-               break;
-
-       case XenbusStateConnected:
-               /*
-                * Work around xenbus race condition: If backend goes
-                * through InitWait to Connected fast enough, we can
-                * get Connected twice here.
-                */
-               if (dev->state != XenbusStateConnected)
-                       goto InitWait; /* no InitWait seen yet, fudge it */
-
-               /* Set input abs params to match backend screen res */
-               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                                "width", "%d", &val) > 0)
-                       input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
-
-               if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                                "height", "%d", &val) > 0)
-                       input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
-
-               break;
-
-       case XenbusStateClosing:
-               xenbus_frontend_closed(dev);
-               break;
-       }
-}
-
-static const struct xenbus_device_id xenkbd_ids[] = {
-       { "vkbd" },
-       { "" }
-};
-
-static struct xenbus_driver xenkbd_driver = {
-       .name = "vkbd",
-       .owner = THIS_MODULE,
-       .ids = xenkbd_ids,
-       .probe = xenkbd_probe,
-       .remove = xenkbd_remove,
-       .resume = xenkbd_resume,
-       .otherend_changed = xenkbd_backend_changed,
-};
-
-static int __init xenkbd_init(void)
-{
-       if (!xen_pv_domain())
-               return -ENODEV;
-
-       /* Nothing to do if running in dom0. */
-       if (xen_initial_domain())
-               return -ENODEV;
-
-       return xenbus_register_frontend(&xenkbd_driver);
-}
-
-static void __exit xenkbd_cleanup(void)
-{
-       xenbus_unregister_driver(&xenkbd_driver);
-}
-
-module_init(xenkbd_init);
-module_exit(xenkbd_cleanup);
-
-MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("xen:vkbd");
index 23005b3cf30bedaea413a1afba3627fe28d0d400..b2b9415d874d02142a9944c283c0f613cda1e9b6 100644 (file)
@@ -8,60 +8,71 @@
 #include "dvb-usb-common.h"
 #include <linux/usb/input.h>
 
+static unsigned int
+legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke,
+                               struct rc_map_table *keymap,
+                               unsigned int keymap_size)
+{
+       unsigned int index;
+       unsigned int scancode;
+
+       if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+               index = ke->index;
+       } else {
+               if (input_scancode_to_scalar(ke, &scancode))
+                       return keymap_size;
+
+               /* See if we can match the raw key code. */
+               for (index = 0; index < keymap_size; index++)
+                       if (keymap[index].scancode == scancode)
+                               break;
+
+               /* See if there is an unused hole in the map */
+               if (index >= keymap_size) {
+                       for (index = 0; index < keymap_size; index++) {
+                               if (keymap[index].keycode == KEY_RESERVED ||
+                                   keymap[index].keycode == KEY_UNKNOWN) {
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       return index;
+}
+
 static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int *keycode)
+                                    struct input_keymap_entry *ke)
 {
        struct dvb_usb_device *d = input_get_drvdata(dev);
-
        struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-       int i;
+       unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+       unsigned int index;
 
-       /* See if we can match the raw key code. */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].scancode == scancode) {
-                       *keycode = keymap[i].keycode;
-                       return 0;
-               }
+       index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
+       if (index >= keymap_size)
+               return -EINVAL;
 
-       /*
-        * If is there extra space, returns KEY_RESERVED,
-        * otherwise, input core won't let legacy_dvb_usb_setkeycode
-        * to work
-        */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].keycode == KEY_RESERVED ||
-                   keymap[i].keycode == KEY_UNKNOWN) {
-                       *keycode = KEY_RESERVED;
-                       return 0;
-               }
+       ke->keycode = keymap[index].keycode;
+       if (ke->keycode == KEY_UNKNOWN)
+               ke->keycode = KEY_RESERVED;
+       ke->len = sizeof(keymap[index].scancode);
+       memcpy(&ke->scancode, &keymap[index].scancode, ke->len);
+       ke->index = index;
 
-       return -EINVAL;
+       return 0;
 }
 
 static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
-                               unsigned int scancode, unsigned int keycode)
+                                    const struct input_keymap_entry *ke,
+                                    unsigned int *old_keycode)
 {
        struct dvb_usb_device *d = input_get_drvdata(dev);
-
        struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-       int i;
-
-       /* Search if it is replacing an existing keycode */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].scancode == scancode) {
-                       keymap[i].keycode = keycode;
-                       return 0;
-               }
-
-       /* Search if is there a clean entry. If so, use it */
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
-               if (keymap[i].keycode == KEY_RESERVED ||
-                   keymap[i].keycode == KEY_UNKNOWN) {
-                       keymap[i].scancode = scancode;
-                       keymap[i].keycode = keycode;
-                       return 0;
-               }
+       unsigned int keymap_size = d->props.rc.legacy.rc_map_size;
+       unsigned int index;
 
+       index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size);
        /*
         * FIXME: Currently, it is not possible to increase the size of
         * scancode table. For it to happen, one possibility
@@ -69,8 +80,24 @@ static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
         * copying data, appending the new key on it, and freeing
         * the old one - or maybe just allocating some spare space
         */
+       if (index >= keymap_size)
+               return -EINVAL;
+
+       *old_keycode = keymap[index].keycode;
+       keymap->keycode = ke->keycode;
+       __set_bit(ke->keycode, dev->keybit);
+
+       if (*old_keycode != KEY_RESERVED) {
+               __clear_bit(*old_keycode, dev->keybit);
+               for (index = 0; index < keymap_size; index++) {
+                       if (keymap[index].keycode == *old_keycode) {
+                               __set_bit(*old_keycode, dev->keybit);
+                               break;
+                       }
+               }
+       }
 
-       return -EINVAL;
+       return 0;
 }
 
 /* Remote-control poll function - called every dib->rc_query_interval ms to see
index 5b4422ef4e6d4705566bc8f45a23cf6a9e9719fc..5ac1baf45c8e8514a2a4c12e29bb26f30bb3b0d7 100644 (file)
@@ -966,8 +966,8 @@ struct rc_dev *rc_allocate_device(void)
                return NULL;
        }
 
-       dev->input_dev->getkeycode_new = ir_getkeycode;
-       dev->input_dev->setkeycode_new = ir_setkeycode;
+       dev->input_dev->getkeycode = ir_getkeycode;
+       dev->input_dev->setkeycode = ir_setkeycode;
        input_set_drvdata(dev->input_dev, dev);
 
        spin_lock_init(&dev->rc_map.lock);
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
new file mode 100644 (file)
index 0000000..f027f7a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Atmel maXTouch Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __LINUX_ATMEL_MXT_TS_H
+#define __LINUX_ATMEL_MXT_TS_H
+
+#include <linux/types.h>
+
+/* Orient */
+#define MXT_NORMAL             0x0
+#define MXT_DIAGONAL           0x1
+#define MXT_HORIZONTAL_FLIP    0x2
+#define MXT_ROTATED_90_COUNTER 0x3
+#define MXT_VERTICAL_FLIP      0x4
+#define MXT_ROTATED_90         0x5
+#define MXT_ROTATED_180                0x6
+#define MXT_DIAGONAL_COUNTER   0x7
+
+/* The platform data for the Atmel maXTouch touchscreen driver */
+struct mxt_platform_data {
+       const u8 *config;
+       size_t config_length;
+
+       unsigned int x_line;
+       unsigned int y_line;
+       unsigned int x_size;
+       unsigned int y_size;
+       unsigned int blen;
+       unsigned int threshold;
+       unsigned int voltage;
+       unsigned char orient;
+       unsigned long irqflags;
+};
+
+#endif /* __LINUX_ATMEL_MXT_TS_H */
index 725ae7c313ff3914ecd077df1e33b2c2a8e8b7d2..61bb18a4fd3c9946a19d90ea293f1d966042c0a4 100644 (file)
@@ -18,6 +18,7 @@
 #define MCS_KEY_CODE(v)                ((v) & 0xffff)
 
 struct mcs_platform_data {
+       void (*poweron)(bool);
        void (*cfg_pin)(void);
 
        /* touchscreen */
diff --git a/include/linux/i2c/qt602240_ts.h b/include/linux/i2c/qt602240_ts.h
deleted file mode 100644 (file)
index c5033e1..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * AT42QT602240/ATMXT224 Touchscreen driver
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <[email protected]>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef __LINUX_QT602240_TS_H
-#define __LINUX_QT602240_TS_H
-
-/* Orient */
-#define QT602240_NORMAL                        0x0
-#define QT602240_DIAGONAL              0x1
-#define QT602240_HORIZONTAL_FLIP       0x2
-#define QT602240_ROTATED_90_COUNTER    0x3
-#define QT602240_VERTICAL_FLIP         0x4
-#define QT602240_ROTATED_90            0x5
-#define QT602240_ROTATED_180           0x6
-#define QT602240_DIAGONAL_COUNTER      0x7
-
-/* The platform data for the AT42QT602240/ATMXT224 touchscreen driver */
-struct qt602240_platform_data {
-       unsigned int x_line;
-       unsigned int y_line;
-       unsigned int x_size;
-       unsigned int y_size;
-       unsigned int blen;
-       unsigned int threshold;
-       unsigned int voltage;
-       unsigned char orient;
-};
-
-#endif /* __LINUX_QT602240_TS_H */
index 5e3dddf8f562651f488dd4b3061fbfefabb98f7a..ce0b72464eb814bf5902e3daf423522934963b8c 100644 (file)
  * @poll: driver-supplied method that polls the device and posts
  *     input events (mandatory).
  * @poll_interval: specifies how often the poll() method should be called.
- *     Defaults to 500 msec unless overriden when registering the device.
+ *     Defaults to 500 msec unless overridden when registering the device.
  * @poll_interval_max: specifies upper bound for the poll interval.
  *     Defaults to the initial value of @poll_interval.
  * @poll_interval_min: specifies lower bound for the poll interval.
  *     Defaults to 0.
- * @input: input device structire associated with the polled device.
+ * @input: input device structure associated with the polled device.
  *     Must be properly initialized by the driver (id, name, phys, bits).
  *
  * Polled input device provides a skeleton for supporting simple input
index e428382ca28a59aac1a16f1f5926f28a3c7fb24b..056ae8a5bd9b8bb3424c431ff60bcc22c155b4da 100644 (file)
@@ -1154,8 +1154,6 @@ struct ff_effect {
  *     sparse keymaps. If not supplied default mechanism will be used.
  *     The method is being called while holding event_lock and thus must
  *     not sleep
- * @getkeycode_new: transition method
- * @setkeycode_new: transition method
  * @ff: force feedback structure associated with the device if device
  *     supports force feedback effects
  * @repeat_key: stores key code of the last key pressed; used to implement
@@ -1234,14 +1232,10 @@ struct input_dev {
        void *keycode;
 
        int (*setkeycode)(struct input_dev *dev,
-                         unsigned int scancode, unsigned int keycode);
+                         const struct input_keymap_entry *ke,
+                         unsigned int *old_keycode);
        int (*getkeycode)(struct input_dev *dev,
-                         unsigned int scancode, unsigned int *keycode);
-       int (*setkeycode_new)(struct input_dev *dev,
-                             const struct input_keymap_entry *ke,
-                             unsigned int *old_keycode);
-       int (*getkeycode_new)(struct input_dev *dev,
-                             struct input_keymap_entry *ke);
+                         struct input_keymap_entry *ke);
 
        struct ff_device *ff;
 
index fd322aca33ba89a9cec62eb7f3909f813b2267a5..173086d42af4dc2634fea9d62804e7a5c0312f8f 100644 (file)
@@ -80,7 +80,8 @@ struct wm831x_touch_pdata {
        int isel;              /** Current for pen down (uA) */
        int rpu;               /** Pen down sensitivity resistor divider */
        int pressure;          /** Report pressure (boolean) */
-       int data_irq;          /** Touch data ready IRQ */
+       unsigned int data_irq; /** Touch data ready IRQ */
+       unsigned int pd_irq;   /** Touch pendown detect IRQ */
 };
 
 enum wm831x_watchdog_action {
diff --git a/include/linux/spi/tsc2005.h b/include/linux/spi/tsc2005.h
new file mode 100644 (file)
index 0000000..d9b0c84
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * This file is part of TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Aaro Koskinen <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _LINUX_SPI_TSC2005_H
+#define _LINUX_SPI_TSC2005_H
+
+#include <linux/types.h>
+
+struct tsc2005_platform_data {
+       int             ts_pressure_max;
+       int             ts_pressure_fudge;
+       int             ts_x_max;
+       int             ts_x_fudge;
+       int             ts_y_max;
+       int             ts_y_fudge;
+       int             ts_x_plate_ohm;
+       unsigned int    esd_timeout_ms;
+       void            (*set_reset)(bool enable);
+};
+
+#endif
This page took 0.306037 seconds and 4 git commands to generate.