Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jan 2011 17:58:14 +0000 (09:58 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jan 2011 17:58:14 +0000 (09:58 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: add SW_ROTATE_LOCK switch type
  Input: fix force feedback capability query example
  Input: wacom_w8001 - add single-touch support
  Input: add Austria Microsystem AS5011 joystick driver
  Input: remove aaed2000 keyboard driver
  Input: i8042 - introduce 'notimeout' blacklist for Dell Vostro V13
  Input: cy8ctmg110_ts - Convert to dev_pm_ops
  Input: migor_ts - convert to dev_pm_ops
  Input: mcs5000_ts - convert to dev_pm_ops
  Input: eeti_ts - convert to dev_pm_ops
  Input: ad7879 - convert I2C to dev_pm_ops

18 files changed:
Documentation/input/ff.txt
Documentation/kernel-parameters.txt
drivers/input/joystick/Kconfig
drivers/input/joystick/Makefile
drivers/input/joystick/as5011.c [new file with mode: 0644]
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/aaed2000_kbd.c [deleted file]
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/touchscreen/ad7879-i2c.c
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/eeti_ts.c
drivers/input/touchscreen/mcs5000_ts.c
drivers/input/touchscreen/migor_ts.c
drivers/input/touchscreen/wacom_w8001.c
include/linux/input.h
include/linux/input/as5011.h [new file with mode: 0644]

index ded4d5f..b3867bf 100644 (file)
@@ -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 )
index ed3708f..5e4d9a6 100644 (file)
@@ -888,6 +888,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
 
index 5b59616..56eb471 100644 (file)
@@ -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
index f3a8cbe..92dc0de 100644 (file)
@@ -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
diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c
new file mode 100644 (file)
index 0000000..f6732b5
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * 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);
index f829998..7b3c0b8 100644 (file)
@@ -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
index 8933e9c..4e5571b 100644 (file)
@@ -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
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
deleted file mode 100644 (file)
index 18222a6..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *  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");
index 5ae0fc4..bb9f5d3 100644 (file)
@@ -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 */
index c04ff00..ac4c936 100644 (file)
@@ -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;
index d82a38e..4e4e58c 100644 (file)
 #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,
 };
 
index d0c3a72..a93c5c2 100644 (file)
@@ -280,8 +280,9 @@ err_free_mem:
 }
 
 #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)
index 7a3a916..7f8f538 100644 (file)
@@ -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,
 };
 
index 6ee9940..2d84c80 100644 (file)
@@ -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,
 };
index defe5dd..5803bd0 100644 (file)
@@ -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,
 };
 
index 8ed53ad..5cb8449 100644 (file)
@@ -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;
index c4e9d91..e428382 100644 (file)
@@ -802,6 +802,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)
 
diff --git a/include/linux/input/as5011.h b/include/linux/input/as5011.h
new file mode 100644 (file)
index 0000000..1affd0d
--- /dev/null
@@ -0,0 +1,20 @@
+#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 */