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
This commit is contained in:
commit
d68798374b
21 changed files with 887 additions and 415 deletions
|
@ -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>
|
||||
|
||||
---------------------------
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
147
drivers/input/keyboard/gpio_keys.c
Normal file
147
drivers/input/keyboard/gpio_keys.c
Normal file
|
@ -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");
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
170
drivers/input/misc/atlas_btns.c
Normal file
170
drivers/input/misc/atlas_btns.c
Normal file
|
@ -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");
|
||||
|
|
@ -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, }
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
/* FIXME boards with ads7846 might use external vref instead ... */
|
||||
use_internal = (ts->model == 7846);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/* 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;
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
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,
|
||||
static struct attribute *ads784x_attributes[] = {
|
||||
&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,
|
||||
&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;
|
||||
}
|
||||
struct input_dev *input = ts->input;
|
||||
|
||||
if (sync) {
|
||||
input_report_abs(input_dev, ABS_PRESSURE, Rt);
|
||||
input_sync(input_dev);
|
||||
}
|
||||
|
||||
#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);
|
||||
input_sync(input);
|
||||
#ifdef VERBOSE
|
||||
dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
|
||||
#endif
|
||||
}
|
||||
|
||||
ts->pendown = (Rt != 0);
|
||||
mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
|
||||
|
||||
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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
17
include/asm-arm/hardware/gpio_keys.h
Normal file
17
include/asm-arm/hardware/gpio_keys.h
Normal file
|
@ -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
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue