提交 01c728a2 编写于 作者: D Dmitry Torokhov

Merge branch 'next' into for-linus

......@@ -49,7 +49,9 @@ This information is subject to change.
#include <linux/input.h>
#include <sys/ioctl.h>
unsigned long features[1 + FF_MAX/sizeof(unsigned long)];
#define BITS_TO_LONGS(x) \
(((x) + 8 * sizeof (unsigned long) - 1) / (8 * sizeof (unsigned long)))
unsigned long features[BITS_TO_LONGS(FF_CNT)];
int ioctl(int file_descriptor, int request, unsigned long *features);
"request" must be EVIOCGBIT(EV_FF, size of features array in bytes )
......
......@@ -884,6 +884,7 @@ and is between 256 and 4096 characters. It is defined in the file
controller
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
controllers
i8042.notimeout [HW] Ignore timeout condition signalled by conroller
i8042.reset [HW] Reset the controller during init and cleanup
i8042.unlock [HW] Unlock (ignore) the keylock
......
......@@ -255,6 +255,16 @@ config JOYSTICK_AMIGA
To compile this driver as a module, choose M here: the
module will be called amijoy.
config JOYSTICK_AS5011
tristate "Austria Microsystem AS5011 joystick"
depends on I2C
help
Say Y here if you have an AS5011 digital joystick connected to your
system.
To compile this driver as a module, choose M here: the
module will be called as5011.
config JOYSTICK_JOYDUMP
tristate "Gameport data dumper"
select GAMEPORT
......
......@@ -7,6 +7,7 @@
obj-$(CONFIG_JOYSTICK_A3D) += a3d.o
obj-$(CONFIG_JOYSTICK_ADI) += adi.o
obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o
obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o
obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o
obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o
obj-$(CONFIG_JOYSTICK_DB9) += db9.o
......
/*
* Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com>
* Sponsored by ARMadeus Systems
*
* 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
*
* Driver for Austria Microsystems joysticks AS5011
*
* TODO:
* - Power on the chip when open() and power down when close()
* - Manage power mode
*/
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/input/as5011.h>
#include <linux/slab.h>
#define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick"
#define MODULE_DEVICE_ALIAS "as5011"
MODULE_AUTHOR("Fabien Marteau <fabien.marteau@armadeus.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/* registers */
#define AS5011_CTRL1 0x76
#define AS5011_CTRL2 0x75
#define AS5011_XP 0x43
#define AS5011_XN 0x44
#define AS5011_YP 0x53
#define AS5011_YN 0x54
#define AS5011_X_REG 0x41
#define AS5011_Y_REG 0x42
#define AS5011_X_RES_INT 0x51
#define AS5011_Y_RES_INT 0x52
/* CTRL1 bits */
#define AS5011_CTRL1_LP_PULSED 0x80
#define AS5011_CTRL1_LP_ACTIVE 0x40
#define AS5011_CTRL1_LP_CONTINUE 0x20
#define AS5011_CTRL1_INT_WUP_EN 0x10
#define AS5011_CTRL1_INT_ACT_EN 0x08
#define AS5011_CTRL1_EXT_CLK_EN 0x04
#define AS5011_CTRL1_SOFT_RST 0x02
#define AS5011_CTRL1_DATA_VALID 0x01
/* CTRL2 bits */
#define AS5011_CTRL2_EXT_SAMPLE_EN 0x08
#define AS5011_CTRL2_RC_BIAS_ON 0x04
#define AS5011_CTRL2_INV_SPINNING 0x02
#define AS5011_MAX_AXIS 80
#define AS5011_MIN_AXIS (-80)
#define AS5011_FUZZ 8
#define AS5011_FLAT 40
struct as5011_device {
struct input_dev *input_dev;
struct i2c_client *i2c_client;
unsigned int button_gpio;
unsigned int button_irq;
unsigned int axis_irq;
};
static int as5011_i2c_write(struct i2c_client *client,
uint8_t aregaddr,
uint8_t avalue)
{
uint8_t data[2] = { aregaddr, avalue };
struct i2c_msg msg = {
client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data
};
int error;
error = i2c_transfer(client->adapter, &msg, 1);
return error < 0 ? error : 0;
}
static int as5011_i2c_read(struct i2c_client *client,
uint8_t aregaddr, signed char *value)
{
uint8_t data[2] = { aregaddr };
struct i2c_msg msg_set[2] = {
{ client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data },
{ client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data }
};
int error;
error = i2c_transfer(client->adapter, msg_set, 2);
if (error < 0)
return error;
*value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0];
return 0;
}
static irqreturn_t as5011_button_interrupt(int irq, void *dev_id)
{
struct as5011_device *as5011 = dev_id;
int val = gpio_get_value_cansleep(as5011->button_gpio);
input_report_key(as5011->input_dev, BTN_JOYSTICK, !val);
input_sync(as5011->input_dev);
return IRQ_HANDLED;
}
static irqreturn_t as5011_axis_interrupt(int irq, void *dev_id)
{
struct as5011_device *as5011 = dev_id;
int error;
signed char x, y;
error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x);
if (error < 0)
goto out;
error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y);
if (error < 0)
goto out;
input_report_abs(as5011->input_dev, ABS_X, x);
input_report_abs(as5011->input_dev, ABS_Y, y);
input_sync(as5011->input_dev);
out:
return IRQ_HANDLED;
}
static int __devinit as5011_configure_chip(struct as5011_device *as5011,
const struct as5011_platform_data *plat_dat)
{
struct i2c_client *client = as5011->i2c_client;
int error;
signed char value;
/* chip soft reset */
error = as5011_i2c_write(client, AS5011_CTRL1,
AS5011_CTRL1_SOFT_RST);
if (error < 0) {
dev_err(&client->dev, "Soft reset failed\n");
return error;
}
mdelay(10);
error = as5011_i2c_write(client, AS5011_CTRL1,
AS5011_CTRL1_LP_PULSED |
AS5011_CTRL1_LP_ACTIVE |
AS5011_CTRL1_INT_ACT_EN);
if (error < 0) {
dev_err(&client->dev, "Power config failed\n");
return error;
}
error = as5011_i2c_write(client, AS5011_CTRL2,
AS5011_CTRL2_INV_SPINNING);
if (error < 0) {
dev_err(&client->dev, "Can't invert spinning\n");
return error;
}
/* write threshold */
error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp);
if (error < 0) {
dev_err(&client->dev, "Can't write threshold\n");
return error;
}
error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn);
if (error < 0) {
dev_err(&client->dev, "Can't write threshold\n");
return error;
}
error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp);
if (error < 0) {
dev_err(&client->dev, "Can't write threshold\n");
return error;
}
error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn);
if (error < 0) {
dev_err(&client->dev, "Can't write threshold\n");
return error;
}
/* to free irq gpio in chip */
error = as5011_i2c_read(client, AS5011_X_RES_INT, &value);
if (error < 0) {
dev_err(&client->dev, "Can't read i2c X resolution value\n");
return error;
}
return 0;
}
static int __devinit as5011_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct as5011_platform_data *plat_data;
struct as5011_device *as5011;
struct input_dev *input_dev;
int irq;
int error;
plat_data = client->dev.platform_data;
if (!plat_data)
return -EINVAL;
if (!plat_data->axis_irq) {
dev_err(&client->dev, "No axis IRQ?\n");
return -EINVAL;
}
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_PROTOCOL_MANGLING)) {
dev_err(&client->dev,
"need i2c bus that supports protocol mangling\n");
return -ENODEV;
}
as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL);
input_dev = input_allocate_device();
if (!as5011 || !input_dev) {
dev_err(&client->dev,
"Can't allocate memory for device structure\n");
error = -ENOMEM;
goto err_free_mem;
}
as5011->i2c_client = client;
as5011->input_dev = input_dev;
as5011->button_gpio = plat_data->button_gpio;
as5011->axis_irq = plat_data->axis_irq;
input_dev->name = "Austria Microsystem as5011 joystick";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(BTN_JOYSTICK, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X,
AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
input_set_abs_params(as5011->input_dev, ABS_Y,
AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
error = gpio_request(as5011->button_gpio, "AS5011 button");
if (error < 0) {
dev_err(&client->dev, "Failed to request button gpio\n");
goto err_free_mem;
}
irq = gpio_to_irq(as5011->button_gpio);
if (irq < 0) {
dev_err(&client->dev,
"Failed to get irq number for button gpio\n");
goto err_free_button_gpio;
}
as5011->button_irq = irq;
error = request_threaded_irq(as5011->button_irq,
NULL, as5011_button_interrupt,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"as5011_button", as5011);
if (error < 0) {
dev_err(&client->dev,
"Can't allocate button irq %d\n", as5011->button_irq);
goto err_free_button_gpio;
}
error = as5011_configure_chip(as5011, plat_data);
if (error)
goto err_free_button_irq;
error = request_threaded_irq(as5011->axis_irq, NULL,
as5011_axis_interrupt,
plat_data->axis_irqflags,
"as5011_joystick", as5011);
if (error) {
dev_err(&client->dev,
"Can't allocate axis irq %d\n", plat_data->axis_irq);
goto err_free_button_irq;
}
error = input_register_device(as5011->input_dev);
if (error) {
dev_err(&client->dev, "Failed to register input device\n");
goto err_free_axis_irq;
}
i2c_set_clientdata(client, as5011);
return 0;
err_free_axis_irq:
free_irq(as5011->axis_irq, as5011);
err_free_button_irq:
free_irq(as5011->button_irq, as5011);
err_free_button_gpio:
gpio_free(as5011->button_gpio);
err_free_mem:
input_free_device(input_dev);
kfree(as5011);
return error;
}
static int __devexit as5011_remove(struct i2c_client *client)
{
struct as5011_device *as5011 = i2c_get_clientdata(client);
free_irq(as5011->axis_irq, as5011);
free_irq(as5011->button_irq, as5011);
gpio_free(as5011->button_gpio);
input_unregister_device(as5011->input_dev);
kfree(as5011);
return 0;
}
static const struct i2c_device_id as5011_id[] = {
{ MODULE_DEVICE_ALIAS, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, as5011_id);
static struct i2c_driver as5011_driver = {
.driver = {
.name = "as5011",
},
.probe = as5011_probe,
.remove = __devexit_p(as5011_remove),
.id_table = as5011_id,
};
static int __init as5011_init(void)
{
return i2c_add_driver(&as5011_driver);
}
module_init(as5011_init);
static void __exit as5011_exit(void)
{
i2c_del_driver(&as5011_driver);
}
module_exit(as5011_exit);
......@@ -12,18 +12,6 @@ menuconfig INPUT_KEYBOARD
if INPUT_KEYBOARD
config KEYBOARD_AAED2000
tristate "AAED-2000 keyboard"
depends on MACH_AAED2000
select INPUT_POLLDEV
default y
help
Say Y here to enable the keyboard on the Agilent AAED-2000
development board.
To compile this driver as a module, choose M here: the
module will be called aaed2000_kbd.
config KEYBOARD_ADP5520
tristate "Keypad Support for ADP5520 PMIC"
depends on PMIC_ADP5520
......
......@@ -4,7 +4,6 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
......
/*
* Keyboard driver for the AAED-2000 dev board
*
* Copyright (c) 2006 Nicolas Bellido Y Ortega
*
* Based on corgikbd.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/input-polldev.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <mach/hardware.h>
#include <mach/aaed2000.h>
#define KB_ROWS 12
#define KB_COLS 8
#define KB_ROWMASK(r) (1 << (r))
#define SCANCODE(r,c) (((c) * KB_ROWS) + (r))
#define NR_SCANCODES (KB_COLS * KB_ROWS)
#define SCAN_INTERVAL (50) /* ms */
#define KB_ACTIVATE_DELAY (20) /* us */
static unsigned char aaedkbd_keycode[NR_SCANCODES] = {
KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, 0, KEY_SPACE, KEY_KP6, 0, KEY_KPDOT, 0, 0,
KEY_K, KEY_M, KEY_O, KEY_DOT, KEY_SLASH, 0, KEY_F, 0, 0, 0, KEY_LEFTSHIFT, 0,
KEY_I, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, 0, 0, 0, 0, KEY_RIGHTSHIFT, 0,
KEY_8, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0,
KEY_J, KEY_H, KEY_B, KEY_KP8, KEY_KP4, 0, KEY_C, KEY_D, KEY_S, KEY_A, 0, KEY_CAPSLOCK,
KEY_Y, KEY_U, KEY_N, KEY_T, 0, 0, KEY_R, KEY_E, KEY_W, KEY_Q, 0, KEY_TAB,
KEY_7, KEY_6, KEY_G, 0, KEY_5, 0, KEY_4, KEY_3, KEY_2, KEY_1, 0, KEY_GRAVE,
0, 0, KEY_COMMA, 0, KEY_KP2, 0, KEY_V, KEY_LEFTALT, KEY_X, KEY_Z, 0, KEY_LEFTCTRL
};
struct aaedkbd {
unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)];
struct input_polled_dev *poll_dev;
int kbdscan_state[KB_COLS];
int kbdscan_count[KB_COLS];
};
#define KBDSCAN_STABLE_COUNT 2
static void aaedkbd_report_col(struct aaedkbd *aaedkbd,
unsigned int col, unsigned int rowd)
{
unsigned int scancode, pressed;
unsigned int row;
for (row = 0; row < KB_ROWS; row++) {
scancode = SCANCODE(row, col);
pressed = rowd & KB_ROWMASK(row);
input_report_key(aaedkbd->poll_dev->input,
aaedkbd->keycode[scancode], pressed);
}
}
/* Scan the hardware keyboard and push any changes up through the input layer */
static void aaedkbd_poll(struct input_polled_dev *dev)
{
struct aaedkbd *aaedkbd = dev->private;
unsigned int col, rowd;
col = 0;
do {
AAEC_GPIO_KSCAN = col + 8;
udelay(KB_ACTIVATE_DELAY);
rowd = AAED_EXT_GPIO & AAED_EGPIO_KBD_SCAN;
if (rowd != aaedkbd->kbdscan_state[col]) {
aaedkbd->kbdscan_count[col] = 0;
aaedkbd->kbdscan_state[col] = rowd;
} else if (++aaedkbd->kbdscan_count[col] >= KBDSCAN_STABLE_COUNT) {
aaedkbd_report_col(aaedkbd, col, rowd);
col++;
}
} while (col < KB_COLS);
AAEC_GPIO_KSCAN = 0x07;
input_sync(dev->input);
}
static int __devinit aaedkbd_probe(struct platform_device *pdev)
{
struct aaedkbd *aaedkbd;
struct input_polled_dev *poll_dev;
struct input_dev *input_dev;
int i;
int error;
aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL);
poll_dev = input_allocate_polled_device();
if (!aaedkbd || !poll_dev) {
error = -ENOMEM;
goto fail;
}
platform_set_drvdata(pdev, aaedkbd);
aaedkbd->poll_dev = poll_dev;
memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode));
poll_dev->private = aaedkbd;
poll_dev->poll = aaedkbd_poll;
poll_dev->poll_interval = SCAN_INTERVAL;
input_dev = poll_dev->input;
input_dev->name = "AAED-2000 Keyboard";
input_dev->phys = "aaedkbd/input0";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_dev->keycode = aaedkbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(aaedkbd_keycode);
for (i = 0; i < ARRAY_SIZE(aaedkbd_keycode); i++)
set_bit(aaedkbd->keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
error = input_register_polled_device(aaedkbd->poll_dev);
if (error)
goto fail;
return 0;
fail: kfree(aaedkbd);
input_free_polled_device(poll_dev);
return error;
}
static int __devexit aaedkbd_remove(struct platform_device *pdev)
{
struct aaedkbd *aaedkbd = platform_get_drvdata(pdev);
input_unregister_polled_device(aaedkbd->poll_dev);
input_free_polled_device(aaedkbd->poll_dev);
kfree(aaedkbd);
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:aaed2000-keyboard");
static struct platform_driver aaedkbd_driver = {
.probe = aaedkbd_probe,
.remove = __devexit_p(aaedkbd_remove),
.driver = {
.name = "aaed2000-keyboard",
.owner = THIS_MODULE,
},
};
static int __init aaedkbd_init(void)
{
return platform_driver_register(&aaedkbd_driver);
}
static void __exit aaedkbd_exit(void)
{
platform_driver_unregister(&aaedkbd_driver);
}
module_init(aaedkbd_init);
module_exit(aaedkbd_exit);
MODULE_AUTHOR("Nicolas Bellido Y Ortega");
MODULE_DESCRIPTION("AAED-2000 Keyboard Driver");
MODULE_LICENSE("GPL v2");
......@@ -424,6 +424,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
},
},
{
/* Dell Vostro V13 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
},
},
{ }
};
......@@ -545,6 +552,17 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
};
#endif
static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
{
/* Dell Vostro V13 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
},
},
{ }
};
/*
* Some Wistron based laptops need us to explicitly enable the 'Dritek
* keyboard extension' to make their extra keys start generating scancodes.
......@@ -896,6 +914,9 @@ static int __init i8042_platform_init(void)
if (dmi_check_system(i8042_dmi_nomux_table))
i8042_nomux = true;
if (dmi_check_system(i8042_dmi_notimeout_table))
i8042_notimeout = true;
if (dmi_check_system(i8042_dmi_dritek_table))
i8042_dritek = true;
#endif /* CONFIG_X86 */
......
......@@ -63,6 +63,10 @@ static bool i8042_noloop;
module_param_named(noloop, i8042_noloop, bool, 0);
MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port");
static bool i8042_notimeout;
module_param_named(notimeout, i8042_notimeout, bool, 0);
MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
#ifdef CONFIG_X86
static bool i8042_dritek;
module_param_named(dritek, i8042_dritek, bool, 0);
......@@ -504,7 +508,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
} else {
dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
port_no = (str & I8042_STR_AUXDATA) ?
I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
......
......@@ -10,14 +10,16 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pm.h>
#include "ad7879.h"
#define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */
#ifdef CONFIG_PM
static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
static int ad7879_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_suspend(ts);
......@@ -25,17 +27,17 @@ static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
return 0;
}
static int ad7879_i2c_resume(struct i2c_client *client)
static int ad7879_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ad7879 *ts = i2c_get_clientdata(client);
ad7879_resume(ts);
return 0;
}
#else
# define ad7879_i2c_suspend NULL
# define ad7879_i2c_resume NULL
static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume);
#endif
/* All registers are word-sized.
......@@ -117,11 +119,12 @@ static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &ad7879_i2c_pm,
#endif
},
.probe = ad7879_i2c_probe,
.remove = __devexit_p(ad7879_i2c_remove),
.suspend = ad7879_i2c_suspend,
.resume = ad7879_i2c_resume,
.id_table = ad7879_id,
};
......
......@@ -280,8 +280,9 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
}
#ifdef CONFIG_PM
static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
static int cy8ctmg110_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
......@@ -293,8 +294,9 @@ static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
static int cy8ctmg110_resume(struct i2c_client *client)
static int cy8ctmg110_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
......@@ -305,6 +307,8 @@ static int cy8ctmg110_resume(struct i2c_client *client)
}
return 0;
}
static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
#endif
static int __devexit cy8ctmg110_remove(struct i2c_client *client)
......@@ -335,14 +339,13 @@ static struct i2c_driver cy8ctmg110_driver = {
.driver = {
.owner = THIS_MODULE,
.name = CY8CTMG110_DRIVER_NAME,
#ifdef CONFIG_PM
.pm = &cy8ctmg110_pm,
#endif
},
.id_table = cy8ctmg110_idtable,
.probe = cy8ctmg110_probe,
.remove = __devexit_p(cy8ctmg110_remove),
#ifdef CONFIG_PM
.suspend = cy8ctmg110_suspend,
.resume = cy8ctmg110_resume,
#endif
};
static int __init cy8ctmg110_init(void)
......
......@@ -261,8 +261,9 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
static int eeti_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
......@@ -279,8 +280,9 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
static int eeti_ts_resume(struct i2c_client *client)
static int eeti_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
struct input_dev *input_dev = priv->input;
......@@ -296,9 +298,8 @@ static int eeti_ts_resume(struct i2c_client *client)
return 0;
}
#else
#define eeti_ts_suspend NULL
#define eeti_ts_resume NULL
static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
#endif
static const struct i2c_device_id eeti_ts_id[] = {
......@@ -310,11 +311,12 @@ MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
static struct i2c_driver eeti_ts_driver = {
.driver = {
.name = "eeti_ts",
#ifdef CONFIG_PM
.pm = &eeti_ts_pm,
#endif
},
.probe = eeti_ts_probe,
.remove = __devexit_p(eeti_ts_remove),
.suspend = eeti_ts_suspend,
.resume = eeti_ts_resume,
.id_table = eeti_ts_id,
};
......
......@@ -261,25 +261,27 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg)
static int mcs5000_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
/* Touch sleep mode */
i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
return 0;
}
static int mcs5000_ts_resume(struct i2c_client *client)
static int mcs5000_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcs5000_ts_data *data = i2c_get_clientdata(client);
mcs5000_ts_phys_init(data);
return 0;
}
#else
#define mcs5000_ts_suspend NULL
#define mcs5000_ts_resume NULL
static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
#endif
static const struct i2c_device_id mcs5000_ts_id[] = {
......@@ -291,10 +293,11 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
static struct i2c_driver mcs5000_ts_driver = {
.probe = mcs5000_ts_probe,
.remove = __devexit_p(mcs5000_ts_remove),
.suspend = mcs5000_ts_suspend,
.resume = mcs5000_ts_resume,
.driver = {
.name = "mcs5000_ts",
#ifdef CONFIG_PM
.pm = &mcs5000_ts_pm,
#endif
},
.id_table = mcs5000_ts_id,
};
......
......@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/i2c.h>
......@@ -226,8 +227,9 @@ static int migor_ts_remove(struct i2c_client *client)
return 0;
}
static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg)
static int migor_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
if (device_may_wakeup(&client->dev))
......@@ -236,8 +238,9 @@ static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
static int migor_ts_resume(struct i2c_client *client)
static int migor_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = dev_get_drvdata(&client->dev);
if (device_may_wakeup(&client->dev))
......@@ -246,6 +249,8 @@ static int migor_ts_resume(struct i2c_client *client)
return 0;
}
static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
static const struct i2c_device_id migor_ts_id[] = {
{ "migor_ts", 0 },
{ }
......@@ -255,11 +260,10 @@ MODULE_DEVICE_TABLE(i2c, migor_ts);
static struct i2c_driver migor_ts_driver = {
.driver = {
.name = "migor_ts",
.pm = &migor_ts_pm,
},
.probe = migor_ts_probe,
.remove = migor_ts_remove,
.suspend = migor_ts_suspend,
.resume = migor_ts_resume,
.id_table = migor_ts_id,
};
......
......@@ -3,6 +3,7 @@
*
* Copyright (c) 2008 Jaya Kumar
* Copyright (c) 2010 Red Hat, Inc.
* Copyright (c) 2010 - 2011 Ping Cheng, Wacom. <pingc@wacom.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
......@@ -64,11 +65,11 @@ struct w8001_coord {
/* touch query reply packet */
struct w8001_touch_query {
u16 x;
u16 y;
u8 panel_res;
u8 capacity_res;
u8 sensor_id;
u16 x;
u16 y;
};
/*
......@@ -87,9 +88,14 @@ struct w8001 {
char phys[32];
int type;
unsigned int pktlen;
u16 max_touch_x;
u16 max_touch_y;
u16 max_pen_x;
u16 max_pen_y;
char name[64];
};
static void parse_data(u8 *data, struct w8001_coord *coord)
static void parse_pen_data(u8 *data, struct w8001_coord *coord)
{
memset(coord, 0, sizeof(*coord));
......@@ -113,11 +119,30 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
coord->tilt_y = data[8] & 0x7F;
}
static void parse_touch(struct w8001 *w8001)
static void parse_single_touch(u8 *data, struct w8001_coord *coord)
{
coord->x = (data[1] << 7) | data[2];
coord->y = (data[3] << 7) | data[4];
coord->tsw = data[0] & 0x01;
}
static void scale_touch_coordinates(struct w8001 *w8001,
unsigned int *x, unsigned int *y)
{
if (w8001->max_pen_x && w8001->max_touch_x)
*x = *x * w8001->max_pen_x / w8001->max_touch_x;
if (w8001->max_pen_y && w8001->max_touch_y)
*y = *y * w8001->max_pen_y / w8001->max_touch_y;
}
static void parse_multi_touch(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
unsigned char *data = w8001->data;
unsigned int x, y;
int i;
int count = 0;
for (i = 0; i < 2; i++) {
bool touch = data[0] & (1 << i);
......@@ -125,15 +150,29 @@ static void parse_touch(struct w8001 *w8001)
input_mt_slot(dev, i);
input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
if (touch) {
int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
x = (data[6 * i + 1] << 7) | data[6 * i + 2];
y = (data[6 * i + 3] << 7) | data[6 * i + 4];
/* data[5,6] and [11,12] is finger capacity */
/* scale to pen maximum */
scale_touch_coordinates(w8001, &x, &y);
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y);
count++;
}
}
/* emulate single touch events when stylus is out of proximity.
* This is to make single touch backward support consistent
* across all Wacom single touch devices.
*/
if (w8001->type != BTN_TOOL_PEN &&
w8001->type != BTN_TOOL_RUBBER) {
w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED;
input_mt_report_pointer_emulation(dev, true);
}
input_sync(dev);
}
......@@ -152,6 +191,15 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
query->y = data[5] << 9;
query->y |= data[6] << 2;
query->y |= (data[2] >> 3) & 0x3;
/* Early days' single-finger touch models need the following defaults */
if (!query->x && !query->y) {
query->x = 1024;
query->y = 1024;
if (query->panel_res)
query->x = query->y = (1 << query->panel_res);
query->panel_res = 10;
}
}
static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
......@@ -161,16 +209,15 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
/*
* We have 1 bit for proximity (rdy) and 3 bits for tip, side,
* side2/eraser. If rdy && f2 are set, this can be either pen + side2,
* or eraser. assume
* or eraser. Assume:
* - if dev is already in proximity and f2 is toggled → pen + side2
* - if dev comes into proximity with f2 set → eraser
* If f2 disappears after assuming eraser, fake proximity out for
* eraser and in for pen.
*/
if (!w8001->type) {
w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
} else if (w8001->type == BTN_TOOL_RUBBER) {
switch (w8001->type) {
case BTN_TOOL_RUBBER:
if (!coord->f2) {
input_report_abs(dev, ABS_PRESSURE, 0);
input_report_key(dev, BTN_TOUCH, 0);
......@@ -180,8 +227,21 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
input_sync(dev);
w8001->type = BTN_TOOL_PEN;
}
} else {
break;
case BTN_TOOL_FINGER:
input_report_key(dev, BTN_TOUCH, 0);
input_report_key(dev, BTN_TOOL_FINGER, 0);
input_sync(dev);
/* fall through */
case KEY_RESERVED:
w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
break;
default:
input_report_key(dev, BTN_STYLUS2, coord->f2);
break;
}
input_report_abs(dev, ABS_X, coord->x);
......@@ -193,7 +253,26 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
input_sync(dev);
if (!coord->rdy)
w8001->type = 0;
w8001->type = KEY_RESERVED;
}
static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
{
struct input_dev *dev = w8001->dev;
unsigned int x = coord->x;
unsigned int y = coord->y;
/* scale to pen maximum */
scale_touch_coordinates(w8001, &x, &y);
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_report_key(dev, BTN_TOUCH, coord->tsw);
input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
input_sync(dev);
w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED;
}
static irqreturn_t w8001_interrupt(struct serio *serio,
......@@ -214,9 +293,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
case W8001_PKTLEN_TOUCH93 - 1:
case W8001_PKTLEN_TOUCH9A - 1:
/* ignore one-finger touch packet. */
if (w8001->pktlen == w8001->idx)
tmp = w8001->data[0] & W8001_TOUCH_BYTE;
if (tmp != W8001_TOUCH_BYTE)
break;
if (w8001->pktlen == w8001->idx) {
w8001->idx = 0;
if (w8001->type != BTN_TOOL_PEN &&
w8001->type != BTN_TOOL_RUBBER) {
parse_single_touch(w8001->data, &coord);
report_single_touch(w8001, &coord);
}
}
break;
/* Pen coordinates packet */
......@@ -225,18 +313,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
if (unlikely(tmp == W8001_TAB_BYTE))
break;
tmp = (w8001->data[0] & W8001_TOUCH_BYTE);
tmp = w8001->data[0] & W8001_TOUCH_BYTE;
if (tmp == W8001_TOUCH_BYTE)
break;
w8001->idx = 0;
parse_data(w8001->data, &coord);
parse_pen_data(w8001->data, &coord);
report_pen_events(w8001, &coord);
break;
/* control packet */
case W8001_PKTLEN_TPCCTL - 1:
tmp = (w8001->data[0] & W8001_TOUCH_MASK);
tmp = w8001->data[0] & W8001_TOUCH_MASK;
if (tmp == W8001_TOUCH_BYTE)
break;
......@@ -249,7 +337,7 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
/* 2 finger touch packet */
case W8001_PKTLEN_TOUCH2FG - 1:
w8001->idx = 0;
parse_touch(w8001);
parse_multi_touch(w8001);
break;
}
......@@ -279,6 +367,7 @@ static int w8001_setup(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
struct w8001_coord coord;
struct w8001_touch_query touch;
int error;
error = w8001_command(w8001, W8001_CMD_STOP, false);
......@@ -287,14 +376,21 @@ static int w8001_setup(struct w8001 *w8001)
msleep(250); /* wait 250ms before querying the device */
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
/* penabled? */
error = w8001_command(w8001, W8001_CMD_QUERY, true);
if (!error) {
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_PEN, dev->keybit);
__set_bit(BTN_TOOL_RUBBER, dev->keybit);
__set_bit(BTN_STYLUS, dev->keybit);
__set_bit(BTN_STYLUS2, dev->keybit);
parse_data(w8001->response, &coord);
parse_pen_data(w8001->response, &coord);
w8001->max_pen_x = coord.x;
w8001->max_pen_y = coord.y;
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
......@@ -303,6 +399,8 @@ static int w8001_setup(struct w8001 *w8001)
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
}
w8001->id = 0x90;
strlcat(w8001->name, " Penabled", sizeof(w8001->name));
}
/* Touch enabled? */
......@@ -313,24 +411,38 @@ static int w8001_setup(struct w8001 *w8001)
* second byte is empty, which indicates touch is not supported.
*/
if (!error && w8001->response[1]) {
struct w8001_touch_query touch;
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_FINGER, dev->keybit);
parse_touchquery(w8001->response, &touch);
w8001->max_touch_x = touch.x;
w8001->max_touch_y = touch.y;
/* scale to pen maximum */
if (w8001->max_pen_x && w8001->max_pen_y) {
touch.x = w8001->max_pen_x;
touch.y = w8001->max_pen_y;
}
input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
__set_bit(BTN_TOOL_FINGER, dev->keybit);
switch (touch.sensor_id) {
case 0:
case 2:
w8001->pktlen = W8001_PKTLEN_TOUCH93;
w8001->id = 0x93;
strlcat(w8001->name, " 1FG", sizeof(w8001->name));
break;
case 1:
case 3:
case 4:
w8001->pktlen = W8001_PKTLEN_TOUCH9A;
strlcat(w8001->name, " 1FG", sizeof(w8001->name));
w8001->id = 0x9a;
break;
case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
......@@ -341,10 +453,18 @@ static int w8001_setup(struct w8001 *w8001)
0, touch.y, 0, 0);
input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
strlcat(w8001->name, " 2FG", sizeof(w8001->name));
if (w8001->max_pen_x && w8001->max_pen_y)
w8001->id = 0xE3;
else
w8001->id = 0xE2;
break;
}
}
strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
return w8001_command(w8001, W8001_CMD_START, false);
}
......@@ -384,22 +504,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
}
w8001->serio = serio;
w8001->id = serio->id.id;
w8001->dev = input_dev;
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
input_dev->name = "Wacom W8001 Penabled Serial TouchScreen";
input_dev->phys = w8001->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_W8001;
input_dev->id.product = w8001->id;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
__set_bit(BTN_TOUCH, input_dev->keybit);
serio_set_drvdata(serio, w8001);
err = serio_open(serio, drv);
if (err)
......@@ -409,6 +517,14 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
if (err)
goto fail3;
input_dev->name = w8001->name;
input_dev->phys = w8001->phys;
input_dev->id.product = w8001->id;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = 0x056a;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
err = input_register_device(w8001->dev);
if (err)
goto fail3;
......
......@@ -800,6 +800,7 @@ struct input_keymap_entry {
#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */
#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */
#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */
#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
#define SW_MAX 0x0f
#define SW_CNT (SW_MAX+1)
......
#ifndef _AS5011_H
#define _AS5011_H
/*
* Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
struct as5011_platform_data {
unsigned int button_gpio;
unsigned int axis_irq; /* irq number */
unsigned long axis_irqflags;
char xp, xn; /* threshold for x axis */
char yp, yn; /* threshold for y axis */
};
#endif /* _AS5011_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册