diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 11:50:24 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 11:50:24 -0800 |
commit | d68798374bcf5cd4a19105b86d96121651b3c8cb (patch) | |
tree | 5e7432adf2b61f1497a4c3138c969e8664c54b6e | |
parent | 412ecd7751a2653ab17df39a1dc3565a548633fd (diff) | |
parent | 2a598df595d33be0f12e37ef5df75eff13511d07 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* '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
-rw-r--r-- | Documentation/feature-removal-schedule.txt | 15 | ||||
-rw-r--r-- | drivers/char/scan_keyb.c | 149 | ||||
-rw-r--r-- | drivers/char/scan_keyb.h | 15 | ||||
-rw-r--r-- | drivers/input/keyboard/Kconfig | 19 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 5 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 147 | ||||
-rw-r--r-- | drivers/input/keyboard/hilkbd.c | 114 | ||||
-rw-r--r-- | drivers/input/misc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/atlas_btns.c | 170 | ||||
-rw-r--r-- | drivers/input/misc/wistron_btns.c | 20 | ||||
-rw-r--r-- | drivers/input/mouse/inport.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/pc110pad.c | 2 | ||||
-rw-r--r-- | drivers/input/serio/i8042.c | 12 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 9 | ||||
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 581 | ||||
-rw-r--r-- | drivers/input/tsdev.c | 4 | ||||
-rw-r--r-- | drivers/usb/input/hid-ff.c | 1 | ||||
-rw-r--r-- | drivers/usb/input/hid-lgff.c | 1 | ||||
-rw-r--r-- | include/asm-arm/hardware/gpio_keys.h | 17 | ||||
-rw-r--r-- | include/linux/spi/ads7846.h | 12 |
21 files changed, 889 insertions, 417 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 8247a4b79d0..c585aa8d62b 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -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 index 2b5bb4f5754..00000000000 --- a/drivers/char/scan_keyb.c +++ /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 index b4b611290a0..00000000000 --- a/drivers/char/scan_keyb.h +++ /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 diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 049f2f544e7..1b81a72e19d 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -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 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 56879790734..586a0fe53be 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -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 index 00000000000..3a8f1b427a7 --- /dev/null +++ b/drivers/input/keyboard/gpio_keys.c @@ -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"); diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 35461eab2fa..255a6ec75a4 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -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); - diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ba0e88c64e1..41b42587f5e 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -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 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 415c4917898..e0a8d58c9e9 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -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 index 00000000000..0acc3a12360 --- /dev/null +++ b/drivers/input/misc/atlas_btns.c @@ -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"); + diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 7b9d1c1da41..e1183aeb8ed 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -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, } }; diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c index 13dd96785e3..701ebd5473c 100644 --- a/drivers/input/mouse/inport.c +++ b/drivers/input/mouse/inport.c @@ -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 diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index f155c1fea04..05d992e514f 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -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")) { diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index debe9445488..c3fdfc1f342 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -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(¶m, 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; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6b46c9bf1d2..971618059a6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -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 diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c6164b6f476..cd251efda41 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -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"); diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index a730c461227..0300dca8591 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -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; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 5d145058a5c..bc7f8e6f8c9 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -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 }, diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 4f4fc3be192..4df0968f852 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -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 index 00000000000..2b217c7b931 --- /dev/null +++ b/include/asm-arm/hardware/gpio_keys.h @@ -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 diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index adb3dafd33e..3387e44dfd1 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h @@ -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); }; |