Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Sun, 11 Feb 2007 19:50:24 +0000 (11:50 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sun, 11 Feb 2007 19:50:24 +0000 (11:50 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: remove scan_keyb driver
  Input: i8042 - fix AUX IRQ delivery check
  Input: wistron - add support for Fujitsu-Siemens Amilo D88x0
  Input: inport - use correct config option for ATIXL
  Input: HIL - handle erros from input_register_device()
  Input: tsdev - schedule removal
  Input: add Atlas button driver
  Input: ads7846 - be more compatible with the hwmon framework
  Input: ads7846 - detect pen up from GPIO state
  Input: ads7846 - select correct SPI mode
  Input: ads7846 - switch to using hrtimer
  Input: ads7846 - optionally leave Vref on during differential measurements
  Input: ads7846 - pluggable filtering logic
  Input: gpio-keys - keyboard driver for GPIO buttons
  Input: hid-ff - add support for Logitech Momo racing wheel
  Input: i8042 - really suppress ACK/NAK during panic blink
  Input: pc110pad - return proper error

21 files changed:
Documentation/feature-removal-schedule.txt
drivers/char/scan_keyb.c [deleted file]
drivers/char/scan_keyb.h [deleted file]
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/gpio_keys.c [new file with mode: 0644]
drivers/input/keyboard/hilkbd.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/atlas_btns.c [new file with mode: 0644]
drivers/input/misc/wistron_btns.c
drivers/input/mouse/inport.c
drivers/input/mouse/pc110pad.c
drivers/input/serio/i8042.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/ads7846.c
drivers/input/tsdev.c
drivers/usb/input/hid-ff.c
drivers/usb/input/hid-lgff.c
include/asm-arm/hardware/gpio_keys.h [new file with mode: 0644]
include/linux/spi/ads7846.h

index 8247a4b79d09e73775cb139de8dc2fedde44f86a..c585aa8d62b430fc4c052253f8db7fd38bd0e2cc 100644 (file)
@@ -319,3 +319,18 @@ Why:    In kernel tree version of driver is unmaintained. Sk98lin driver
        replaced by the skge driver. 
 Who:    Stephen Hemminger <shemminger@osdl.org>
 
+---------------------------
+
+What:  Compaq touchscreen device emulation
+When:  Oct 2007
+Files: drivers/input/tsdev.c
+Why:   The code says it was obsolete when it was written in 2001.
+       tslib is a userspace library which does anything tsdev can do and
+       much more besides in userspace where this code belongs. There is no
+       longer any need for tsdev and applications should have converted to
+       use tslib by now.
+       The name "tsdev" is also extremely confusing and lots of people have
+       it loaded when they don't need/use it.
+Who:   Richard Purdie <rpurdie@rpsys.net>
+
+---------------------------
diff --git a/drivers/char/scan_keyb.c b/drivers/char/scan_keyb.c
deleted file mode 100644 (file)
index 2b5bb4f..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *     $Id: scan_keyb.c,v 1.2 2000/07/04 06:24:42 yaegashi Exp $ 
- *     Copyright (C) 2000 YAEGASHI Takeshi
- *     Generic scan keyboard driver
- */
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/kbd_kern.h>
-#include <linux/timer.h>
-
-#define SCANHZ (HZ/20)
-
-struct scan_keyboard {
-       struct scan_keyboard *next;
-       int (*scan)(unsigned char *buffer);
-       const unsigned char *table;
-       unsigned char *s0, *s1;
-       int length;
-};
-
-static int scan_jiffies=0;
-static struct scan_keyboard *keyboards=NULL;
-struct timer_list scan_timer;
-
-static void check_kbd(const unsigned char *table,
-                     unsigned char *new, unsigned char *old, int length)
-{
-       int need_tasklet_schedule=0;
-       unsigned int xor, bit;
-       
-       while(length-->0) {
-               if((xor=*new^*old)==0) {
-                       table+=8;
-               }
-               else {
-                       for(bit=0x01; bit<0x100; bit<<=1) {
-                               if(xor&bit) {
-                                       handle_scancode(*table, !(*new&bit));
-                                       need_tasklet_schedule=1;
-#if 0
-                                       printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed");
-#endif
-                               }
-                               table++;
-                       }
-               }
-               new++; old++;
-       }
-
-       if(need_tasklet_schedule)
-               tasklet_schedule(&keyboard_tasklet);
-}
-
-
-static void scan_kbd(unsigned long dummy)
-{
-       struct scan_keyboard *kbd;
-
-       scan_jiffies++;
-
-       for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) {
-               if(scan_jiffies&1) {
-                       if(!kbd->scan(kbd->s0))
-                               check_kbd(kbd->table,
-                                         kbd->s0, kbd->s1, kbd->length);
-                       else
-                               memcpy(kbd->s0, kbd->s1, kbd->length);
-               }
-               else {
-                       if(!kbd->scan(kbd->s1))
-                               check_kbd(kbd->table,
-                                         kbd->s1, kbd->s0, kbd->length);
-                       else
-                               memcpy(kbd->s1, kbd->s0, kbd->length);
-               }
-               
-       }
-
-       init_timer(&scan_timer);
-       scan_timer.expires = jiffies + SCANHZ;
-       scan_timer.data = 0;
-       scan_timer.function = scan_kbd;
-       add_timer(&scan_timer);
-}
-
-
-int register_scan_keyboard(int (*scan)(unsigned char *buffer),
-                          const unsigned char *table,
-                          int length)
-{
-       struct scan_keyboard *kbd;
-
-       kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL);
-       if (kbd == NULL)
-               goto error_out;
-
-       kbd->scan=scan;
-       kbd->table=table;
-       kbd->length=length;
-
-       kbd->s0 = kmalloc(length, GFP_KERNEL);
-       if (kbd->s0 == NULL)
-               goto error_free_kbd;
-
-       kbd->s1 = kmalloc(length, GFP_KERNEL);
-       if (kbd->s1 == NULL)
-               goto error_free_s0;
-
-       memset(kbd->s0, -1, kbd->length);
-       memset(kbd->s1, -1, kbd->length);
-       
-       kbd->next=keyboards;
-       keyboards=kbd;
-
-       return 0;
-
- error_free_s0:
-       kfree(kbd->s0);
-
- error_free_kbd:
-       kfree(kbd);
-
- error_out:
-       return -ENOMEM;
-}
-                             
-                             
-void __init scan_kbd_init(void)
-{
-       init_timer(&scan_timer);
-       scan_timer.expires = jiffies + SCANHZ;
-       scan_timer.data = 0;
-       scan_timer.function = scan_kbd;
-       add_timer(&scan_timer);
-
-       printk(KERN_INFO "Generic scan keyboard driver initialized\n");
-}
diff --git a/drivers/char/scan_keyb.h b/drivers/char/scan_keyb.h
deleted file mode 100644 (file)
index b4b6112..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef        __DRIVER_CHAR_SCAN_KEYB_H
-#define        __DRIVER_CHAR_SCAN_KEYB_H
-/*
- *     $Id: scan_keyb.h,v 1.1 2000/06/10 21:45:30 yaegashi Exp $
- *     Copyright (C) 2000 YAEGASHI Takeshi
- *     Generic scan keyboard driver
- */
-
-int register_scan_keyboard(int (*scan)(unsigned char *buffer),
-                          const unsigned char *table,
-                          int length);
-
-void __init scan_kbd_init(void);
-
-#endif
index 049f2f544e75e94a9d40aee991df4cf8d45510f4..1b81a72e19d92c7fc7bdfa41a215cbda7039d9a7 100644 (file)
@@ -135,12 +135,12 @@ config KEYBOARD_STOWAWAY
 config KEYBOARD_CORGI
        tristate "Corgi keyboard"
        depends on PXA_SHARPSL
-       default y       
+       default y
        help
-         Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx 
+         Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
          series of PDAs.
 
-         To compile this driver as a module, choose M here: the 
+         To compile this driver as a module, choose M here: the
          module will be called corgikbd.
 
 config KEYBOARD_SPITZ
@@ -214,4 +214,17 @@ config KEYBOARD_AAED2000
          To compile this driver as a module, choose M here: the
          module will be called aaed2000_kbd.
 
+config KEYBOARD_GPIO
+        tristate "Buttons on CPU GPIOs (PXA)"
+        depends on ARCH_PXA
+       help
+         This driver implements support for buttons connected
+         directly to GPIO pins of PXA CPUs.
+
+         Say Y here if your device has buttons connected
+         directly to GPIO pins of the CPU.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gpio-keys.
+
 endif
index 568797907347b9e0ace4898ab425e8a9ba16683d..586a0fe53be604bc1e67c6001b98df90e99b7e2f 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_KEYBOARD_CORGI)          += corgikbd.o
 obj-$(CONFIG_KEYBOARD_SPITZ)           += spitzkbd.o
 obj-$(CONFIG_KEYBOARD_HIL)             += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)         += hilkbd.o
-obj-$(CONFIG_KEYBOARD_OMAP)             += omap-keypad.o
-obj-$(CONFIG_KEYBOARD_AAED2000)         += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
 
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
new file mode 100644 (file)
index 0000000..3a8f1b4
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Driver for keys on GPIO lines capable of generating interrupts.
+ *
+ * Copyright 2005 Phil Blundell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/hardware/gpio_keys.h>
+
+static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
+{
+       int i;
+       struct platform_device *pdev = dev_id;
+       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+       struct input_dev *input = platform_get_drvdata(pdev);
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               int gpio = pdata->buttons[i].gpio;
+               if (irq == IRQ_GPIO(gpio)) {
+                       int state = ((GPLR(gpio) & GPIO_bit(gpio)) ? 1 : 0) ^ (pdata->buttons[i].active_low);
+
+                       input_report_key(input, pdata->buttons[i].keycode, state);
+                       input_sync(input);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit gpio_keys_probe(struct platform_device *pdev)
+{
+       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+       struct input_dev *input;
+       int i, error;
+
+       input = input_allocate_device();
+       if (!input)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, input);
+
+       input->evbit[0] = BIT(EV_KEY);
+
+       input->name = pdev->name;
+       input->phys = "gpio-keys/input0";
+       input->cdev.dev = &pdev->dev;
+       input->private = pdata;
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               int code = pdata->buttons[i].keycode;
+               int irq = IRQ_GPIO(pdata->buttons[i].gpio);
+
+               set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
+               error = request_irq(irq, gpio_keys_isr, SA_SAMPLE_RANDOM,
+                                    pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys",
+                                    pdev);
+               if (error) {
+                       printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, ret);
+                       goto fail;
+               }
+               set_bit(code, input->keybit);
+       }
+
+       error = input_register_device(input);
+       if (error) {
+               printk(KERN_ERR "Unable to register gpio-keys input device\n");
+               goto fail;
+       }
+
+       return 0;
+
+ fail:
+       for (i = i - 1; i >= 0; i--)
+               free_irq(IRQ_GPIO(pdata->buttons[i].gpio), pdev);
+
+       input_free_device(input);
+
+       return error;
+}
+
+static int __devexit gpio_keys_remove(struct platform_device *pdev)
+{
+       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+       struct input_dev *input = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               int irq = IRQ_GPIO(pdata->buttons[i].gpio);
+               free_irq(irq, pdev);
+       }
+
+       input_unregister_device(input);
+
+       return 0;
+}
+
+struct platform_driver gpio_keys_device_driver = {
+       .probe          = gpio_keys_probe,
+       .remove         = __devexit_p(gpio_keys_remove),
+       .driver         = {
+               .name   = "gpio-keys",
+       }
+};
+
+static int __init gpio_keys_init(void)
+{
+       return platform_driver_register(&gpio_keys_device_driver);
+}
+
+static void __exit gpio_keys_exit(void)
+{
+       platform_driver_unregister(&gpio_keys_device_driver);
+}
+
+module_init(gpio_keys_init);
+module_exit(gpio_keys_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
+MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
index 35461eab2fafc3f88d454120637562abdff84a85..255a6ec75a4826a66db9d630a0dbd51aa5fdfe69 100644 (file)
@@ -6,10 +6,10 @@
  *  Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
  *
  *  Very basic HP Human Interface Loop (HIL) driver.
- *  This driver handles the keyboard on HP300 (m68k) and on some 
+ *  This driver handles the keyboard on HP300 (m68k) and on some
  *  HP700 (parisc) series machines.
  *
- * 
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License version 2.  See the file COPYING in the main directory of this
  * archive for more details.
@@ -64,9 +64,9 @@ MODULE_LICENSE("GPL v2");
 #endif
 
 
+
 /* HIL helper functions */
+
 #define hil_busy()              (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)
 #define hil_data_available()    (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
 #define hil_status()            (hil_readb(HILBASE + HIL_CMD))
@@ -75,7 +75,7 @@ MODULE_LICENSE("GPL v2");
 #define hil_write_data(x)       do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)
 
 /* HIL constants */
+
 #define        HIL_BUSY                0x02
 #define        HIL_DATA_RDY            0x01
 
@@ -86,10 +86,10 @@ MODULE_LICENSE("GPL v2");
 #define        HIL_INTON               0x5C            /* Turn on interrupts. */
 #define        HIL_INTOFF              0x5D            /* Turn off interrupts. */
 
-#define        HIL_READKBDSADR         0xF9
-#define        HIL_WRITEKBDSADR        0xE9
+#define        HIL_READKBDSADR         0xF9
+#define        HIL_WRITEKBDSADR        0xE9
 
-static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = 
+static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
        { HIL_KEYCODES_SET1 };
 
 /* HIL structure */
@@ -97,11 +97,11 @@ static struct {
        struct input_dev *dev;
 
        unsigned int curdev;
-       
+
        unsigned char s;
        unsigned char c;
        int valid;
-       
+
        unsigned char data[16];
        unsigned int ptr;
        spinlock_t lock;
@@ -115,7 +115,7 @@ static void poll_finished(void)
        int down;
        int key;
        unsigned char scode;
-       
+
        switch (hil_dev.data[0]) {
        case 0x40:
                down = (hil_dev.data[1] & 1) == 0;
@@ -127,6 +127,7 @@ static void poll_finished(void)
        hil_dev.curdev = 0;
 }
 
+
 static inline void handle_status(unsigned char s, unsigned char c)
 {
        if (c & 0x8) {
@@ -143,6 +144,7 @@ static inline void handle_status(unsigned char s, unsigned char c)
        }
 }
 
+
 static inline void handle_data(unsigned char s, unsigned char c)
 {
        if (hil_dev.curdev) {
@@ -152,13 +154,11 @@ static inline void handle_data(unsigned char s, unsigned char c)
 }
 
 
-/* 
- * Handle HIL interrupts.
- */
+/* handle HIL interrupts */
 static irqreturn_t hil_interrupt(int irq, void *handle)
 {
        unsigned char s, c;
-       
+
        s = hil_status();
        c = hil_read_data();
 
@@ -179,10 +179,8 @@ static irqreturn_t hil_interrupt(int irq, void *handle)
        return IRQ_HANDLED;
 }
 
-/*
- * Send a command to the HIL
- */
 
+/* send a command to the HIL */
 static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
 {
        unsigned long flags;
@@ -200,16 +198,14 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
 }
 
 
-/*
- * Initialise HIL. 
- */
-
+/* initialise HIL */
 static int __init
 hil_keyb_init(void)
 {
        unsigned char c;
        unsigned int i, kbid;
        wait_queue_head_t hil_wait;
+       int err;
 
        if (hil_dev.dev) {
                return -ENODEV; /* already initialized */
@@ -219,15 +215,25 @@ hil_keyb_init(void)
        if (!hil_dev.dev)
                return -ENOMEM;
        hil_dev.dev->private = &hil_dev;
-       
+
 #if defined(CONFIG_HP300)
-       if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
-               return -ENODEV;
-       
-       request_region(HILBASE+HIL_DATA, 2, "hil");
+       if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
+               printk(KERN_ERR "HIL: hardware register was not found\n");
+               err = -ENODEV;
+               goto err1;
+       }
+       if (!request_region(HILBASE + HIL_DATA, 2, "hil")) {
+               printk(KERN_ERR "HIL: IOPORT region already used\n");
+               err = -EIO;
+               goto err1;
+       }
 #endif
-       
-       request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+
+       err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+       if (err) {
+               printk(KERN_ERR "HIL: Can't get IRQ\n");
+               goto err2;
+       }
 
        /* Turn on interrupts */
        hil_do(HIL_INTON, NULL, 0);
@@ -239,47 +245,63 @@ hil_keyb_init(void)
        init_waitqueue_head(&hil_wait);
        wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ);
        if (!hil_dev.valid) {
-               printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n");
+               printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n");
        }
 
-       c = hil_dev.c; 
+       c = hil_dev.c;
        hil_dev.valid = 0;
        if (c == 0) {
                kbid = -1;
-               printk(KERN_WARNING "HIL: no keyboard present.\n");
+               printk(KERN_WARNING "HIL: no keyboard present\n");
        } else {
                kbid = ffz(~c);
-               /* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */
+               printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid);
        }
 
        /* set it to raw mode */
        c = 0;
        hil_do(HIL_WRITEKBDSADR, &c, 1);
-       
+
        for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
                if (hphilkeyb_keycode[i] != KEY_RESERVED)
                        set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
 
-       hil_dev.dev->evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
-       hil_dev.dev->ledbit[0]   = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-       hil_dev.dev->keycodemax  = HIL_KEYCODES_SET1_TBLSIZE;
-       hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]);
-       hil_dev.dev->keycode     = hphilkeyb_keycode;
-       hil_dev.dev->name       = "HIL keyboard";
-       hil_dev.dev->phys       = "hpkbd/input0";
+       hil_dev.dev->evbit[0]   = BIT(EV_KEY) | BIT(EV_REP);
+       hil_dev.dev->ledbit[0]  = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+       hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
+       hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]);
+       hil_dev.dev->keycode    = hphilkeyb_keycode;
+       hil_dev.dev->name       = "HIL keyboard";
+       hil_dev.dev->phys       = "hpkbd/input0";
 
        hil_dev.dev->id.bustype = BUS_HIL;
        hil_dev.dev->id.vendor  = PCI_VENDOR_ID_HP;
        hil_dev.dev->id.product = 0x0001;
        hil_dev.dev->id.version = 0x0010;
 
-       input_register_device(hil_dev.dev);
+       err = input_register_device(hil_dev.dev);
+       if (err) {
+               printk(KERN_ERR "HIL: Can't register device\n");
+               goto err3;
+       }
        printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
-               hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
+              hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
 
        return 0;
+
+err3:
+       hil_do(HIL_INTOFF, NULL, 0);
+       disable_irq(HIL_IRQ);
+       free_irq(HIL_IRQ, hil_dev.dev_id);
+err2:
+       release_region(HILBASE + HIL_DATA, 2);
+err1:
+       input_free_device(hil_dev.dev);
+       hil_dev.dev = NULL;
+       return err;
 }
 
+
 #if defined(CONFIG_PARISC)
 static int __init
 hil_init_chip(struct parisc_device *dev)
@@ -292,7 +314,7 @@ hil_init_chip(struct parisc_device *dev)
        hil_base = dev->hpa.start;
        hil_irq  = dev->irq;
        hil_dev.dev_id = dev;
-       
+
        printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq);
 
        return hil_keyb_init();
@@ -313,9 +335,6 @@ static struct parisc_driver hil_driver = {
 #endif /* CONFIG_PARISC */
 
 
-
-
-
 static int __init hil_init(void)
 {
 #if defined(CONFIG_PARISC)
@@ -349,4 +368,3 @@ static void __exit hil_exit(void)
 
 module_init(hil_init);
 module_exit(hil_exit);
-
index ba0e88c64e1ef93befa1c6e0f4483845cb88ebb2..41b42587f5e96e330df17404623cef2a74246554 100644 (file)
@@ -50,6 +50,16 @@ config INPUT_WISTRON_BTNS
          To compile this driver as a module, choose M here: the module will
          be called wistron_btns.
 
+config INPUT_ATLAS_BTNS
+       tristate "x86 Atlas button interface"
+       depends on X86 && ACPI
+       help
+         Say Y here for support of Atlas wallmount touchscreen buttons.
+         The events will show up as scancodes F1 through F9 via evdev.
+
+         To compile this driver as a module, choose M here: the module will
+         be called atlas_btns.
+
 config INPUT_IXP4XX_BEEPER
        tristate "IXP4XX Beeper support"
        depends on ARCH_IXP4XX
index 415c49178985d6fe0f4547e3457f090d4a18820a..e0a8d58c9e9b3125a6531f64b0043a66385dfd42 100644 (file)
@@ -9,5 +9,6 @@ obj-$(CONFIG_INPUT_PCSPKR)              += pcspkr.o
 obj-$(CONFIG_INPUT_M68K_BEEP)          += m68kspkr.o
 obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)       += wistron_btns.o
+obj-$(CONFIG_INPUT_ATLAS_BTNS)         += atlas_btns.o
 obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
new file mode 100644 (file)
index 0000000..0acc3a1
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras
+ *
+ *  Copyright (C) 2006 Jaya Kumar
+ *  Based on Toshiba ACPI by John Belmonte and ASUS ACPI
+ *  This work was sponsored by CIS(M) Sdn Bhd.
+ *
+ *  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/init.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_ATLAS_NAME                        "Atlas ACPI"
+#define ACPI_ATLAS_CLASS               "Atlas"
+#define ACPI_ATLAS_BUTTON_HID          "ASIM0000"
+
+static struct input_dev *input_dev;
+
+/* button handling code */
+static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
+                   u32 function, void *handler_context, void **return_context)
+{
+       *return_context =
+               (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
+
+       return AE_OK;
+}
+
+static acpi_status acpi_atlas_button_handler(u32 function,
+                     acpi_physical_address address,
+                     u32 bit_width, acpi_integer *value,
+                     void *handler_context, void *region_context)
+{
+       acpi_status status;
+       int keycode;
+
+       if (function == ACPI_WRITE) {
+               keycode = KEY_F1 + (address & 0x0F);
+               input_report_key(input_dev, keycode, !(address & 0x10));
+               input_sync(input_dev);
+               status = 0;
+       } else {
+               printk(KERN_WARNING "atlas: shrugged on unexpected function"
+                       ":function=%x,address=%lx,value=%x\n",
+                       function, (unsigned long)address, (u32)*value);
+               status = -EINVAL;
+       }
+
+       return status;
+}
+
+static int atlas_acpi_button_add(struct acpi_device *device)
+{
+       acpi_status status;
+       int err;
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               printk(KERN_ERR "atlas: unable to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       input_dev->name = "Atlas ACPI button driver";
+       input_dev->phys = "ASIM0000/atlas/input0";
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
+
+       set_bit(KEY_F1, input_dev->keybit);
+       set_bit(KEY_F2, input_dev->keybit);
+       set_bit(KEY_F3, input_dev->keybit);
+       set_bit(KEY_F4, input_dev->keybit);
+       set_bit(KEY_F5, input_dev->keybit);
+       set_bit(KEY_F6, input_dev->keybit);
+       set_bit(KEY_F7, input_dev->keybit);
+       set_bit(KEY_F8, input_dev->keybit);
+       set_bit(KEY_F9, input_dev->keybit);
+
+       err = input_register_device(input_dev);
+       if (err) {
+               printk(KERN_ERR "atlas: couldn't register input device\n");
+               input_free_device(input_dev);
+               return err;
+       }
+
+       /* hookup button handler */
+       status = acpi_install_address_space_handler(device->handle,
+                               0x81, &acpi_atlas_button_handler,
+                               &acpi_atlas_button_setup, device);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
+               input_unregister_device(input_dev);
+               status = -EINVAL;
+       }
+
+       return status;
+}
+
+static int atlas_acpi_button_remove(struct acpi_device *device, int type)
+{
+       acpi_status status;
+
+       status = acpi_remove_address_space_handler(device->handle,
+                               0x81, &acpi_atlas_button_handler);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
+               status = -EINVAL;
+       }
+
+       input_unregister_device(input_dev);
+
+       return status;
+}
+
+static struct acpi_driver atlas_acpi_driver = {
+       .name   = ACPI_ATLAS_NAME,
+       .class  = ACPI_ATLAS_CLASS,
+       .ids    = ACPI_ATLAS_BUTTON_HID,
+       .ops    = {
+               .add    = atlas_acpi_button_add,
+               .remove = atlas_acpi_button_remove,
+       },
+};
+
+static int __init atlas_acpi_init(void)
+{
+       int result;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       result = acpi_bus_register_driver(&atlas_acpi_driver);
+       if (result < 0) {
+               printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit atlas_acpi_exit(void)
+{
+       acpi_bus_unregister_driver(&atlas_acpi_driver);
+}
+
+module_init(atlas_acpi_init);
+module_exit(atlas_acpi_exit);
+
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atlas button driver");
+
index 7b9d1c1da41a7d676737e7adc92c1f1700e1d6a1..e1183aeb8ed5ce4708b585acb1b500394d3e628e 100644 (file)
@@ -335,6 +335,17 @@ static struct key_entry keymap_aopen_1559as[] = {
        { KE_END,  0 },
 };
 
+static struct key_entry keymap_fs_amilo_d88x0[] = {
+       { KE_KEY, 0x01, KEY_HELP },
+       { KE_KEY, 0x08, KEY_MUTE },
+       { KE_KEY, 0x31, KEY_MAIL },
+       { KE_KEY, 0x36, KEY_WWW },
+       { KE_KEY, 0x11, KEY_PROG1 },
+       { KE_KEY, 0x12, KEY_PROG2 },
+       { KE_KEY, 0x13, KEY_PROG3 },
+       { KE_END, 0 }
+};
+
 /*
  * If your machine is not here (which is currently rather likely), please send
  * a list of buttons and their key codes (reported when loading this module
@@ -413,6 +424,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
                },
                .driver_data = keymap_wistron_ms2111
        },
+       {
+               .callback = dmi_matched,
+               .ident = "Fujitsu Siemens Amilo D88x0",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
+               },
+               .driver_data = keymap_fs_amilo_d88x0
+       },
        { NULL, }
 };
 
index 13dd96785e397bf81d632993512e9457ae3e0053..701ebd5473cfe8745ca8ef4e82e2f6a7647d352c 100644 (file)
@@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
 #define INPORT_REG_MODE                0x07
 #define INPORT_RESET           0x80
 
-#ifdef CONFIG_INPUT_ATIXL
+#ifdef CONFIG_MOUSE_ATIXL
 #define INPORT_NAME            "ATI XL Mouse"
 #define INPORT_VENDOR          0x0002
 #define INPORT_SPEED_30HZ      0x01
index f155c1fea04e3bd2e3181106886782011f3d64e7..05d992e514f0bd5452dc0a6f0c9161b01a01c753 100644 (file)
@@ -113,7 +113,7 @@ static int __init pc110pad_init(void)
        dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
        if (dev) {
                pci_dev_put(dev);
-               return -ENOENT;
+               return -ENODEV;
        }
 
        if (!request_region(pc110pad_io, 4, "pc110pad")) {
index debe9445488c0cfefc221823da9fe205a5515d9f..c3fdfc1f342a2fdd38b35e1294adc77ca0d44d9e 100644 (file)
@@ -371,7 +371,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
        if (unlikely(i8042_suppress_kbd_ack))
                if (port_no == I8042_KBD_PORT_NO &&
                    (data == 0xfa || data == 0xfe)) {
-                       i8042_suppress_kbd_ack = 0;
+                       i8042_suppress_kbd_ack--;
                        goto out;
                }
 
@@ -543,6 +543,7 @@ static int __devinit i8042_check_aux(void)
 {
        int retval = -1;
        int irq_registered = 0;
+       int aux_loop_broken = 0;
        unsigned long flags;
        unsigned char param;
 
@@ -572,6 +573,8 @@ static int __devinit i8042_check_aux(void)
                if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
                    (param && param != 0xfa && param != 0xff))
                        return -1;
+
+               aux_loop_broken = 1;
        }
 
 /*
@@ -595,7 +598,7 @@ static int __devinit i8042_check_aux(void)
  * used it for a PCI card or somethig else.
  */
 
-       if (i8042_noloop) {
+       if (i8042_noloop || aux_loop_broken) {
 /*
  * Without LOOP command we can't test AUX IRQ delivery. Assume the port
  * is working and hope we are right.
@@ -838,13 +841,14 @@ static long i8042_panic_blink(long count)
        led ^= 0x01 | 0x04;
        while (i8042_read_status() & I8042_STR_IBF)
                DELAY;
-       i8042_suppress_kbd_ack = 1;
+       dbg("%02x -> i8042 (panic blink)", 0xed);
+       i8042_suppress_kbd_ack = 2;
        i8042_write_data(0xed); /* set leds */
        DELAY;
        while (i8042_read_status() & I8042_STR_IBF)
                DELAY;
        DELAY;
-       i8042_suppress_kbd_ack = 1;
+       dbg("%02x -> i8042 (panic blink)", led);
        i8042_write_data(led);
        DELAY;
        last_blink = count;
index 6b46c9bf1d2045c7bf79a1c2c977bdf92a6db27e..971618059a6f6a25648cf3f031548f1d5bc4a20d 100644 (file)
@@ -12,13 +12,18 @@ menuconfig INPUT_TOUCHSCREEN
 if INPUT_TOUCHSCREEN
 
 config TOUCHSCREEN_ADS7846
-       tristate "ADS 7846 based touchscreens"
+       tristate "ADS 7846/7843 based touchscreens"
        depends on SPI_MASTER
+       depends on HWMON = n || HWMON
        help
          Say Y here if you have a touchscreen interface using the
-         ADS7846 controller, and your board-specific initialization
+         ADS7846 or ADS7843 controller, and your board-specific setup
          code includes that in its table of SPI devices.
 
+         If HWMON is selected, and the driver is told the reference voltage
+         on your board, you will also get hwmon interfaces for the voltage
+         (and on ads7846, temperature) sensors of this chip.
+
          If unsure, say N (but it's safe to say "Y").
 
          To compile this driver as a module, choose M here: the
index c6164b6f476a3ecb5fde27af07ddd05c38557d01..cd251efda41062cb6705f0cc6e5ba06af9ceafaf 100644 (file)
@@ -17,8 +17,9 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
-#include <linux/device.h>
+#include <linux/hwmon.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
@@ -54,7 +55,8 @@
  * files.
  */
 
-#define        TS_POLL_PERIOD  msecs_to_jiffies(10)
+#define TS_POLL_DELAY  (1 * 1000000)   /* ns delay before the first sample */
+#define TS_POLL_PERIOD (5 * 1000000)   /* ns delay between samples */
 
 /* this driver doesn't aim at the peak continuous sample rate */
 #define        SAMPLE_BITS     (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
@@ -63,12 +65,12 @@ struct ts_event {
        /* For portability, we can't read 12 bit values using SPI (which
         * would make the controller deliver them as native byteorder u16
         * with msbs zeroed).  Instead, we read them as two 8-bit values,
-        * which need byteswapping then range adjustment.
+        * *** WHICH NEED BYTESWAPPING *** and range adjustment.
         */
-       __be16 x;
-       __be16 y;
-       __be16 z1, z2;
-       int    ignore;
+       u16     x;
+       u16     y;
+       u16     z1, z2;
+       int     ignore;
 };
 
 struct ads7846 {
@@ -76,7 +78,12 @@ struct ads7846 {
        char                    phys[32];
 
        struct spi_device       *spi;
+
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
        struct attribute_group  *attr_group;
+       struct class_device     *hwmon;
+#endif
+
        u16                     model;
        u16                     vref_delay_usecs;
        u16                     x_plate_ohms;
@@ -99,13 +106,16 @@ struct ads7846 {
        u16                     debounce_rep;
 
        spinlock_t              lock;
-       struct timer_list       timer;          /* P: lock */
+       struct hrtimer          timer;
        unsigned                pendown:1;      /* P: lock */
        unsigned                pending:1;      /* P: lock */
 // FIXME remove "irq_disabled"
        unsigned                irq_disabled:1; /* P: lock */
        unsigned                disabled:1;
 
+       int                     (*filter)(void *data, int data_idx, int *val);
+       void                    *filter_data;
+       void                    (*filter_cleanup)(void *data);
        int                     (*get_pendown_state)(void);
 };
 
@@ -142,15 +152,16 @@ struct ads7846 {
 #define        MAX_12BIT       ((1<<12)-1)
 
 /* leave ADC powered up (disables penirq) between differential samples */
-#define        READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
-       | ADS_12_BIT | ADS_DFR)
+#define        READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
+       | ADS_12_BIT | ADS_DFR | \
+       (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
 
-#define        READ_Y  (READ_12BIT_DFR(y)  | ADS_PD10_ADC_ON)
-#define        READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
-#define        READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
+#define        READ_Y(vref)    (READ_12BIT_DFR(y,  1, vref))
+#define        READ_Z1(vref)   (READ_12BIT_DFR(z1, 1, vref))
+#define        READ_Z2(vref)   (READ_12BIT_DFR(z2, 1, vref))
 
-#define        READ_X  (READ_12BIT_DFR(x)  | ADS_PD10_ADC_ON)
-#define        PWRDOWN (READ_12BIT_DFR(y)  | ADS_PD10_PDOWN)   /* LAST */
+#define        READ_X(vref)    (READ_12BIT_DFR(x,  1, vref))
+#define        PWRDOWN         (READ_12BIT_DFR(y,  0, 0))      /* LAST */
 
 /* single-ended samples need to first power up reference voltage;
  * we leave both ADC and VREF powered
@@ -158,14 +169,19 @@ struct ads7846 {
 #define        READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
        | ADS_12_BIT | ADS_SER)
 
-#define        REF_ON  (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
-#define        REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN)
+#define        REF_ON  (READ_12BIT_DFR(x, 1, 1))
+#define        REF_OFF (READ_12BIT_DFR(y, 0, 0))
 
 /*--------------------------------------------------------------------------*/
 
 /*
  * Non-touchscreen sensors only use single-ended conversions.
+ * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
+ * ads7846 lets that pin be unconnected, to use internal vREF.
  */
+static unsigned vREF_mV;
+module_param(vREF_mV, uint, 0);
+MODULE_PARM_DESC(vREF_mV, "external vREF voltage, in milliVolts");
 
 struct ser_req {
        u8                      ref_on;
@@ -193,50 +209,55 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        struct ser_req          *req = kzalloc(sizeof *req, GFP_KERNEL);
        int                     status;
        int                     sample;
-       int                     i;
+       int                     use_internal;
 
        if (!req)
                return -ENOMEM;
 
        spi_message_init(&req->msg);
 
-       /* activate reference, so it has time to settle; */
-       req->ref_on = REF_ON;
-       req->xfer[0].tx_buf = &req->ref_on;
-       req->xfer[0].len = 1;
-       req->xfer[1].rx_buf = &req->scratch;
-       req->xfer[1].len = 2;
-
-       /*
-        * for external VREF, 0 usec (and assume it's always on);
-        * for 1uF, use 800 usec;
-        * no cap, 100 usec.
-        */
-       req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+       /* FIXME boards with ads7846 might use external vref instead ... */
+       use_internal = (ts->model == 7846);
+
+       /* maybe turn on internal vREF, and let it settle */
+       if (use_internal) {
+               req->ref_on = REF_ON;
+               req->xfer[0].tx_buf = &req->ref_on;
+               req->xfer[0].len = 1;
+               spi_message_add_tail(&req->xfer[0], &req->msg);
+
+               req->xfer[1].rx_buf = &req->scratch;
+               req->xfer[1].len = 2;
+
+               /* for 1uF, settle for 800 usec; no cap, 100 usec.  */
+               req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+               spi_message_add_tail(&req->xfer[1], &req->msg);
+       }
 
        /* take sample */
        req->command = (u8) command;
        req->xfer[2].tx_buf = &req->command;
        req->xfer[2].len = 1;
+       spi_message_add_tail(&req->xfer[2], &req->msg);
+
        req->xfer[3].rx_buf = &req->sample;
        req->xfer[3].len = 2;
+       spi_message_add_tail(&req->xfer[3], &req->msg);
 
        /* REVISIT:  take a few more samples, and compare ... */
 
-       /* turn off reference */
-       req->ref_off = REF_OFF;
-       req->xfer[4].tx_buf = &req->ref_off;
-       req->xfer[4].len = 1;
-       req->xfer[5].rx_buf = &req->scratch;
-       req->xfer[5].len = 2;
-
-       CS_CHANGE(req->xfer[5]);
-
-       /* group all the transfers together, so we can't interfere with
-        * reading touchscreen state; disable penirq while sampling
-        */
-       for (i = 0; i < 6; i++)
-               spi_message_add_tail(&req->xfer[i], &req->msg);
+       /* maybe off internal vREF */
+       if (use_internal) {
+               req->ref_off = REF_OFF;
+               req->xfer[4].tx_buf = &req->ref_off;
+               req->xfer[4].len = 1;
+               spi_message_add_tail(&req->xfer[4], &req->msg);
+
+               req->xfer[5].rx_buf = &req->scratch;
+               req->xfer[5].len = 2;
+               CS_CHANGE(req->xfer[5]);
+               spi_message_add_tail(&req->xfer[5], &req->msg);
+       }
 
        ts->irq_disabled = 1;
        disable_irq(spi->irq);
@@ -256,25 +277,173 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        return status ? status : sample;
 }
 
-#define SHOW(name) static ssize_t \
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
+
+#define SHOW(name, var, adjust) static ssize_t \
 name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
+       struct ads7846 *ts = dev_get_drvdata(dev); \
        ssize_t v = ads7846_read12_ser(dev, \
-                       READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+                       READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
        if (v < 0) \
                return v; \
-       return sprintf(buf, "%u\n", (unsigned) v); \
+       return sprintf(buf, "%u\n", adjust(ts, v)); \
 } \
 static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
 
-SHOW(temp0)
-SHOW(temp1)
-SHOW(vaux)
-SHOW(vbatt)
+
+/* Sysfs conventions report temperatures in millidegrees Celcius.
+ * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
+ * accuracy scheme without calibration data.  For now we won't try either;
+ * userspace sees raw sensor values, and must scale/calibrate appropriately.
+ */
+static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
+{
+       return v;
+}
+
+SHOW(temp0, temp0, null_adjust)                /* temp1_input */
+SHOW(temp1, temp1, null_adjust)                /* temp2_input */
+
+
+/* sysfs conventions report voltages in millivolts.  We can convert voltages
+ * if we know vREF.  userspace may need to scale vAUX to match the board's
+ * external resistors; we assume that vBATT only uses the internal ones.
+ */
+static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
+{
+       unsigned retval = v;
+
+       /* external resistors may scale vAUX into 0..vREF */
+       retval *= vREF_mV;
+       retval = retval >> 12;
+       return retval;
+}
+
+static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
+{
+       unsigned retval = vaux_adjust(ts, v);
+
+       /* ads7846 has a resistor ladder to scale this signal down */
+       if (ts->model == 7846)
+               retval *= 4;
+       return retval;
+}
+
+SHOW(in0_input, vaux, vaux_adjust)
+SHOW(in1_input, vbatt, vbatt_adjust)
+
+
+static struct attribute *ads7846_attributes[] = {
+       &dev_attr_temp0.attr,
+       &dev_attr_temp1.attr,
+       &dev_attr_in0_input.attr,
+       &dev_attr_in1_input.attr,
+       NULL,
+};
+
+static struct attribute_group ads7846_attr_group = {
+       .attrs = ads7846_attributes,
+};
+
+static struct attribute *ads7843_attributes[] = {
+       &dev_attr_in0_input.attr,
+       &dev_attr_in1_input.attr,
+       NULL,
+};
+
+static struct attribute_group ads7843_attr_group = {
+       .attrs = ads7843_attributes,
+};
+
+static struct attribute *ads7845_attributes[] = {
+       &dev_attr_in0_input.attr,
+       NULL,
+};
+
+static struct attribute_group ads7845_attr_group = {
+       .attrs = ads7845_attributes,
+};
+
+static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
+{
+       struct class_device *hwmon;
+       int err;
+
+       /* hwmon sensors need a reference voltage */
+       switch (ts->model) {
+       case 7846:
+               if (!vREF_mV) {
+                       dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
+                       vREF_mV = 2500;
+               }
+               break;
+       case 7845:
+       case 7843:
+               if (!vREF_mV) {
+                       dev_warn(&spi->dev,
+                               "external vREF for ADS%d not specified\n",
+                               ts->model);
+                       return 0;
+               }
+               break;
+       }
+
+       /* different chips have different sensor groups */
+       switch (ts->model) {
+       case 7846:
+               ts->attr_group = &ads7846_attr_group;
+               break;
+       case 7845:
+               ts->attr_group = &ads7845_attr_group;
+               break;
+       case 7843:
+               ts->attr_group = &ads7843_attr_group;
+               break;
+       default:
+               dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model);
+               return 0;
+       }
+
+       err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+       if (err)
+               return err;
+
+       hwmon = hwmon_device_register(&spi->dev);
+       if (IS_ERR(hwmon)) {
+               sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+               return PTR_ERR(hwmon);
+       }
+
+       ts->hwmon = hwmon;
+       return 0;
+}
+
+static void ads784x_hwmon_unregister(struct spi_device *spi,
+                                    struct ads7846 *ts)
+{
+       if (ts->hwmon) {
+               sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+               hwmon_device_unregister(ts->hwmon);
+       }
+}
+
+#else
+static inline int ads784x_hwmon_register(struct spi_device *spi,
+                                        struct ads7846 *ts)
+{
+       return 0;
+}
+
+static inline void ads784x_hwmon_unregister(struct spi_device *spi,
+                                           struct ads7846 *ts)
+{
+}
+#endif
 
 static int is_pen_down(struct device *dev)
 {
-       struct ads7846          *ts = dev_get_drvdata(dev);
+       struct ads7846  *ts = dev_get_drvdata(dev);
 
        return ts->pendown;
 }
@@ -318,46 +487,14 @@ static ssize_t ads7846_disable_store(struct device *dev,
 
 static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
 
-static struct attribute *ads7846_attributes[] = {
-       &dev_attr_temp0.attr,
-       &dev_attr_temp1.attr,
-       &dev_attr_vbatt.attr,
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
-
-static struct attribute_group ads7846_attr_group = {
-       .attrs = ads7846_attributes,
-};
-
-/*
- * ads7843/7845 don't have temperature sensors, and
- * use the other sensors a bit differently too
- */
-
-static struct attribute *ads7843_attributes[] = {
-       &dev_attr_vbatt.attr,
-       &dev_attr_vaux.attr,
+static struct attribute *ads784x_attributes[] = {
        &dev_attr_pen_down.attr,
        &dev_attr_disable.attr,
        NULL,
 };
 
-static struct attribute_group ads7843_attr_group = {
-       .attrs = ads7843_attributes,
-};
-
-static struct attribute *ads7845_attributes[] = {
-       &dev_attr_vaux.attr,
-       &dev_attr_pen_down.attr,
-       &dev_attr_disable.attr,
-       NULL,
-};
-
-static struct attribute_group ads7845_attr_group = {
-       .attrs = ads7845_attributes,
+static struct attribute_group ads784x_attr_group = {
+       .attrs = ads784x_attributes,
 };
 
 /*--------------------------------------------------------------------------*/
@@ -373,25 +510,22 @@ static struct attribute_group ads7845_attr_group = {
 static void ads7846_rx(void *ads)
 {
        struct ads7846          *ts = ads;
-       struct input_dev        *input_dev = ts->input;
        unsigned                Rt;
-       unsigned                sync = 0;
        u16                     x, y, z1, z2;
-       unsigned long           flags;
 
-       /* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
-        * built from two 8 bit values written msb-first.
+       /* ads7846_rx_val() did in-place conversion (including byteswap) from
+        * on-the-wire format as part of debouncing to get stable readings.
         */
-       x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
-       y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
-       z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
-       z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
+       x = ts->tc.x;
+       y = ts->tc.y;
+       z1 = ts->tc.z1;
+       z2 = ts->tc.z2;
 
        /* range filtering */
        if (x == MAX_12BIT)
                x = 0;
 
-       if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
+       if (likely(x && z1)) {
                /* compute touch pressure resistance using equation #2 */
                Rt = z2;
                Rt -= z1;
@@ -403,100 +537,129 @@ static void ads7846_rx(void *ads)
                Rt = 0;
 
        /* Sample found inconsistent by debouncing or pressure is beyond
-       * the maximum. Don't report it to user space, repeat at least
-       * once more the measurement */
+        * the maximum. Don't report it to user space, repeat at least
+        * once more the measurement
+        */
        if (ts->tc.ignore || Rt > ts->pressure_max) {
-               mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+#ifdef VERBOSE
+               pr_debug("%s: ignored %d pressure %d\n",
+                       ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+#endif
+               hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+                             HRTIMER_REL);
                return;
        }
 
-       /* NOTE:  "pendown" is inferred from pressure; we don't rely on
-        * being able to check nPENIRQ status, or "friendly" trigger modes
-        * (both-edges is much better than just-falling or low-level).
+       /* NOTE: We can't rely on the pressure to determine the pen down
+        * state, even this controller has a pressure sensor.  The pressure
+        * value can fluctuate for quite a while after lifting the pen and
+        * in some cases may not even settle at the expected value.
         *
-        * REVISIT:  some boards may require reading nPENIRQ; it's
-        * needed on 7843.  and 7845 reads pressure differently...
-        *
-        * REVISIT:  the touchscreen might not be connected; this code
-        * won't notice that, even if nPENIRQ never fires ...
+        * The only safe way to check for the pen up condition is in the
+        * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
         */
-       if (!ts->pendown && Rt != 0) {
-               input_report_key(input_dev, BTN_TOUCH, 1);
-               sync = 1;
-       } else if (ts->pendown && Rt == 0) {
-               input_report_key(input_dev, BTN_TOUCH, 0);
-               sync = 1;
-       }
-
        if (Rt) {
-               input_report_abs(input_dev, ABS_X, x);
-               input_report_abs(input_dev, ABS_Y, y);
-               sync = 1;
-       }
-
-       if (sync) {
-               input_report_abs(input_dev, ABS_PRESSURE, Rt);
-               input_sync(input_dev);
-       }
+               struct input_dev *input = ts->input;
 
-#ifdef VERBOSE
-       if (Rt || ts->pendown)
-               pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
-                       x, y, Rt, Rt ? "" : " UP");
+               if (!ts->pendown) {
+                       input_report_key(input, BTN_TOUCH, 1);
+                       ts->pendown = 1;
+#ifdef VERBOSE
+                       dev_dbg(&ts->spi->dev, "DOWN\n");
 #endif
+               }
+               input_report_abs(input, ABS_X, x);
+               input_report_abs(input, ABS_Y, y);
+               input_report_abs(input, ABS_PRESSURE, Rt);
 
-       spin_lock_irqsave(&ts->lock, flags);
-
-       ts->pendown = (Rt != 0);
-       mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+               input_sync(input);
+#ifdef VERBOSE
+               dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
+#endif
+       }
 
-       spin_unlock_irqrestore(&ts->lock, flags);
+       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
 }
 
-static void ads7846_debounce(void *ads)
+static int ads7846_debounce(void *ads, int data_idx, int *val)
 {
        struct ads7846          *ts = ads;
-       struct spi_message      *m;
-       struct spi_transfer     *t;
-       int                     val;
-       int                     status;
 
-       m = &ts->msg[ts->msg_idx];
-       t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-       val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
-       if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+       if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+               /* Start over collecting consistent readings. */
+               ts->read_rep = 0;
                /* Repeat it, if this was the first read or the read
                 * wasn't consistent enough. */
                if (ts->read_cnt < ts->debounce_max) {
-                       ts->last_read = val;
+                       ts->last_read = *val;
                        ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
                } else {
                        /* Maximum number of debouncing reached and still
                         * not enough number of consistent readings. Abort
                         * the whole sample, repeat it in the next sampling
                         * period.
                         */
-                       ts->tc.ignore = 1;
                        ts->read_cnt = 0;
-                       /* Last message will contain ads7846_rx() as the
-                        * completion function.
-                        */
-                       m = ts->last_msg;
+                       return ADS7846_FILTER_IGNORE;
                }
-               /* Start over collecting consistent readings. */
-               ts->read_rep = 0;
        } else {
                if (++ts->read_rep > ts->debounce_rep) {
                        /* Got a good reading for this coordinate,
                         * go for the next one. */
-                       ts->tc.ignore = 0;
-                       ts->msg_idx++;
                        ts->read_cnt = 0;
                        ts->read_rep = 0;
-                       m++;
-               } else
+                       return ADS7846_FILTER_OK;
+               } else {
                        /* Read more values that are consistent. */
                        ts->read_cnt++;
+                       return ADS7846_FILTER_REPEAT;
+               }
+       }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+       return ADS7846_FILTER_OK;
+}
+
+static void ads7846_rx_val(void *ads)
+{
+       struct ads7846 *ts = ads;
+       struct spi_message *m;
+       struct spi_transfer *t;
+       u16 *rx_val;
+       int val;
+       int action;
+       int status;
+
+       m = &ts->msg[ts->msg_idx];
+       t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+       rx_val = t->rx_buf;
+
+       /* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
+        * built from two 8 bit values written msb-first.
+        */
+       val = be16_to_cpu(*rx_val) >> 3;
+
+       action = ts->filter(ts->filter_data, ts->msg_idx, &val);
+       switch (action) {
+       case ADS7846_FILTER_REPEAT:
+               break;
+       case ADS7846_FILTER_IGNORE:
+               ts->tc.ignore = 1;
+               /* Last message will contain ads7846_rx() as the
+                * completion function.
+                */
+               m = ts->last_msg;
+               break;
+       case ADS7846_FILTER_OK:
+               *rx_val = val;
+               ts->tc.ignore = 0;
+               m = &ts->msg[++ts->msg_idx];
+               break;
+       default:
+               BUG();
        }
        status = spi_async(ts->spi, m);
        if (status)
@@ -504,21 +667,34 @@ static void ads7846_debounce(void *ads)
                                status);
 }
 
-static void ads7846_timer(unsigned long handle)
+static int ads7846_timer(struct hrtimer *handle)
 {
-       struct ads7846  *ts = (void *)handle;
+       struct ads7846  *ts = container_of(handle, struct ads7846, timer);
        int             status = 0;
 
        spin_lock_irq(&ts->lock);
 
-       if (unlikely(ts->msg_idx && !ts->pendown)) {
+       if (unlikely(!ts->get_pendown_state() ||
+                    device_suspended(&ts->spi->dev))) {
+               if (ts->pendown) {
+                       struct input_dev *input = ts->input;
+
+                       input_report_key(input, BTN_TOUCH, 0);
+                       input_report_abs(input, ABS_PRESSURE, 0);
+                       input_sync(input);
+
+                       ts->pendown = 0;
+#ifdef VERBOSE
+                       dev_dbg(&ts->spi->dev, "UP\n");
+#endif
+               }
+
                /* measurement cycle ended */
                if (!device_suspended(&ts->spi->dev)) {
                        ts->irq_disabled = 0;
                        enable_irq(ts->spi->irq);
                }
                ts->pending = 0;
-               ts->msg_idx = 0;
        } else {
                /* pen is still down, continue with the measurement */
                ts->msg_idx = 0;
@@ -528,6 +704,7 @@ static void ads7846_timer(unsigned long handle)
        }
 
        spin_unlock_irq(&ts->lock);
+       return HRTIMER_NORESTART;
 }
 
 static irqreturn_t ads7846_irq(int irq, void *handle)
@@ -546,7 +723,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
                        ts->irq_disabled = 1;
                        disable_irq(ts->spi->irq);
                        ts->pending = 1;
-                       mod_timer(&ts->timer, jiffies);
+                       hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
+                                       HRTIMER_REL);
                }
        }
        spin_unlock_irqrestore(&ts->lock, flags);
@@ -632,6 +810,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        struct ads7846_platform_data    *pdata = spi->dev.platform_data;
        struct spi_message              *m;
        struct spi_transfer             *x;
+       int                             vref;
        int                             err;
 
        if (!spi->irq) {
@@ -665,6 +844,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
         * may not.  So we stick to very-portable 8 bit words, both RX and TX.
         */
        spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_1;
+       err = spi_setup(spi);
+       if (err < 0)
+               return err;
 
        ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
        input_dev = input_allocate_device();
@@ -679,8 +862,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        ts->spi = spi;
        ts->input = input_dev;
 
-       init_timer(&ts->timer);
-       ts->timer.data = (unsigned long) ts;
+       hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
        ts->timer.function = ads7846_timer;
 
        spin_lock_init(&ts->lock);
@@ -689,14 +871,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
        ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
        ts->pressure_max = pdata->pressure_max ? : ~0;
-       if (pdata->debounce_max) {
+
+       if (pdata->filter != NULL) {
+               if (pdata->filter_init != NULL) {
+                       err = pdata->filter_init(pdata, &ts->filter_data);
+                       if (err < 0)
+                               goto err_free_mem;
+               }
+               ts->filter = pdata->filter;
+               ts->filter_cleanup = pdata->filter_cleanup;
+       } else if (pdata->debounce_max) {
                ts->debounce_max = pdata->debounce_max;
+               if (ts->debounce_max < 2)
+                       ts->debounce_max = 2;
                ts->debounce_tol = pdata->debounce_tol;
                ts->debounce_rep = pdata->debounce_rep;
-               if (ts->debounce_rep > ts->debounce_max + 1)
-                       ts->debounce_rep = ts->debounce_max - 1;
+               ts->filter = ads7846_debounce;
+               ts->filter_data = ts;
        } else
-               ts->debounce_tol = ~0;
+               ts->filter = ads7846_no_filter;
        ts->get_pendown_state = pdata->get_pendown_state;
 
        snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
@@ -718,6 +911,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        input_set_abs_params(input_dev, ABS_PRESSURE,
                        pdata->pressure_min, pdata->pressure_max, 0, 0);
 
+       vref = pdata->keep_vref_on;
+
        /* set up the transfers to read touchscreen state; this assumes we
         * use formula #2 for pressure, not #3.
         */
@@ -727,7 +922,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        spi_message_init(m);
 
        /* y- still on; turn on only y+ (and ADC) */
-       ts->read_y = READ_Y;
+       ts->read_y = READ_Y(vref);
        x->tx_buf = &ts->read_y;
        x->len = 1;
        spi_message_add_tail(x, m);
@@ -737,7 +932,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
-       m->complete = ads7846_debounce;
+       m->complete = ads7846_rx_val;
        m->context = ts;
 
        m++;
@@ -745,7 +940,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        /* turn y- off, x+ on, then leave in lowpower */
        x++;
-       ts->read_x = READ_X;
+       ts->read_x = READ_X(vref);
        x->tx_buf = &ts->read_x;
        x->len = 1;
        spi_message_add_tail(x, m);
@@ -755,7 +950,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
-       m->complete = ads7846_debounce;
+       m->complete = ads7846_rx_val;
        m->context = ts;
 
        /* turn y+ off, x- on; we'll use formula #2 */
@@ -764,7 +959,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                spi_message_init(m);
 
                x++;
-               ts->read_z1 = READ_Z1;
+               ts->read_z1 = READ_Z1(vref);
                x->tx_buf = &ts->read_z1;
                x->len = 1;
                spi_message_add_tail(x, m);
@@ -774,14 +969,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
-               m->complete = ads7846_debounce;
+               m->complete = ads7846_rx_val;
                m->context = ts;
 
                m++;
                spi_message_init(m);
 
                x++;
-               ts->read_z2 = READ_Z2;
+               ts->read_z2 = READ_Z2(vref);
                x->tx_buf = &ts->read_z2;
                x->len = 1;
                spi_message_add_tail(x, m);
@@ -791,7 +986,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
-               m->complete = ads7846_debounce;
+               m->complete = ads7846_rx_val;
                m->context = ts;
        }
 
@@ -820,31 +1015,24 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                        spi->dev.driver->name, ts)) {
                dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
                err = -EBUSY;
-               goto err_free_mem;
+               goto err_cleanup_filter;
        }
 
+       err = ads784x_hwmon_register(spi, ts);
+       if (err)
+               goto err_free_irq;
+
        dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
 
-       /* take a first sample, leaving nPENIRQ active; avoid
+       /* take a first sample, leaving nPENIRQ active and vREF off; avoid
         * the touchscreen, in case it's not connected.
         */
        (void) ads7846_read12_ser(&spi->dev,
                          READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
 
-       switch (ts->model) {
-       case 7846:
-               ts->attr_group = &ads7846_attr_group;
-               break;
-       case 7845:
-               ts->attr_group = &ads7845_attr_group;
-               break;
-       default:
-               ts->attr_group = &ads7843_attr_group;
-               break;
-       }
-       err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+       err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
        if (err)
-               goto err_free_irq;
+               goto err_remove_hwmon;
 
        err = input_register_device(input_dev);
        if (err)
@@ -853,9 +1041,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        return 0;
 
  err_remove_attr_group:
-       sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+       sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ err_remove_hwmon:
+       ads784x_hwmon_unregister(spi, ts);
  err_free_irq:
        free_irq(spi->irq, ts);
+ err_cleanup_filter:
+       if (ts->filter_cleanup)
+               ts->filter_cleanup(ts->filter_data);
  err_free_mem:
        input_free_device(input_dev);
        kfree(ts);
@@ -866,16 +1059,20 @@ static int __devexit ads7846_remove(struct spi_device *spi)
 {
        struct ads7846          *ts = dev_get_drvdata(&spi->dev);
 
+       ads784x_hwmon_unregister(spi, ts);
        input_unregister_device(ts->input);
 
        ads7846_suspend(spi, PMSG_SUSPEND);
 
-       sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+       sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
 
        free_irq(ts->spi->irq, ts);
        /* suspend left the IRQ disabled */
        enable_irq(ts->spi->irq);
 
+       if (ts->filter_cleanup)
+               ts->filter_cleanup(ts->filter_data);
+
        kfree(ts);
 
        dev_dbg(&spi->dev, "unregistered touchscreen\n");
index a730c461227f78608d8c461195f33b80f11210fb..0300dca8591d9cdb076f0413eee62a6b56823fc8 100644 (file)
@@ -151,6 +151,10 @@ static int tsdev_open(struct inode *inode, struct file *file)
        int i = iminor(inode) - TSDEV_MINOR_BASE;
        struct tsdev_list *list;
 
+       printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
+               "for removal.\nSee Documentation/feature-removal-schedule.txt "
+               "for details.\n");
+
        if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
                return -ENODEV;
 
index 5d145058a5cb33cf40a14873b0e363f4b5e23b00..bc7f8e6f8c97a12066b6ec7cf2294de0490ec442 100644 (file)
@@ -57,6 +57,7 @@ static struct hid_ff_initializer inits[] = {
        { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
        { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
        { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
+       { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
 #endif
 #ifdef CONFIG_PANTHERLORD_FF
        { 0x810, 0x0001, hid_plff_init },
index 4f4fc3be192e9116f40128b03b12384dbd06e124..4df0968f852e6d7686a6f731b94cef775cd41fb0 100644 (file)
@@ -52,6 +52,7 @@ static const struct dev_type devices[] = {
        { 0x046d, 0xc211, ff_rumble },
        { 0x046d, 0xc219, ff_rumble },
        { 0x046d, 0xc283, ff_joystick },
+       { 0x046d, 0xca03, ff_joystick },
        { 0x0000, 0x0000, ff_joystick }
 };
 
diff --git a/include/asm-arm/hardware/gpio_keys.h b/include/asm-arm/hardware/gpio_keys.h
new file mode 100644 (file)
index 0000000..2b217c7
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _GPIO_KEYS_H
+#define _GPIO_KEYS_H
+
+struct gpio_keys_button {
+       /* Configuration parameters */
+       int keycode;
+       int gpio;
+       int active_low;
+       char *desc;
+};
+
+struct gpio_keys_platform_data {
+       struct gpio_keys_button *buttons;
+       int nbuttons;
+};
+
+#endif
index adb3dafd33e96a6d12c122fc62101b6c7a5c0947..3387e44dfd13bdef5014e050aff8e85637387048 100644 (file)
@@ -5,9 +5,17 @@
  *
  * It's OK if the min/max values are zero.
  */
+enum ads7846_filter {
+       ADS7846_FILTER_OK,
+       ADS7846_FILTER_REPEAT,
+       ADS7846_FILTER_IGNORE,
+};
+
 struct ads7846_platform_data {
        u16     model;                  /* 7843, 7845, 7846. */
        u16     vref_delay_usecs;       /* 0 for external vref; etc */
+       int     keep_vref_on:1;         /* set to keep vref on for differential
+                                        * measurements as well */
        u16     x_plate_ohms;
        u16     y_plate_ohms;
 
@@ -21,5 +29,9 @@ struct ads7846_platform_data {
        u16     debounce_rep;           /* additional consecutive good readings
                                         * required after the first two */
        int     (*get_pendown_state)(void);
+       int     (*filter_init)  (struct ads7846_platform_data *pdata,
+                                void **filter_data);
+       int     (*filter)       (void *filter_data, int data_idx, int *val);
+       void    (*filter_cleanup)(void *filter_data);
 };