Merge commit 'v3.4-rc4' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Sun, 22 Apr 2012 06:28:35 +0000 (23:28 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Sun, 22 Apr 2012 06:28:35 +0000 (23:28 -0700)
63 files changed:
Documentation/ABI/testing/sysfs-driver-wacom
Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt [new file with mode: 0644]
drivers/input/joystick/a3d.c
drivers/input/joystick/adi.c
drivers/input/joystick/cobra.c
drivers/input/joystick/gf2k.c
drivers/input/joystick/grip.c
drivers/input/joystick/grip_mp.c
drivers/input/joystick/guillemot.c
drivers/input/joystick/interact.c
drivers/input/joystick/joydump.c
drivers/input/joystick/magellan.c
drivers/input/joystick/sidewinder.c
drivers/input/joystick/spaceball.c
drivers/input/joystick/spaceorb.c
drivers/input/joystick/stinger.c
drivers/input/joystick/tmdc.c
drivers/input/joystick/twidjoy.c
drivers/input/joystick/warrior.c
drivers/input/joystick/zhenhua.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/ep93xx_keypad.c
drivers/input/keyboard/hil_kbd.c
drivers/input/keyboard/lkkbd.c
drivers/input/keyboard/lm8333.c [new file with mode: 0644]
drivers/input/keyboard/matrix_keypad.c
drivers/input/keyboard/newtonkbd.c
drivers/input/keyboard/stowaway.c
drivers/input/keyboard/sunkbd.c
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/keyboard/xtkbd.c
drivers/input/misc/cma3000_d0x.c
drivers/input/mouse/sermouse.c
drivers/input/mouse/vsxxxaa.c
drivers/input/serio/ps2mult.c
drivers/input/serio/serio_raw.c
drivers/input/serio/xilinx_ps2.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/dynapro.c
drivers/input/touchscreen/elo.c
drivers/input/touchscreen/fujitsu_ts.c
drivers/input/touchscreen/gunze.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/input/touchscreen/hampshire.c
drivers/input/touchscreen/inexio.c
drivers/input/touchscreen/lpc32xx_ts.c
drivers/input/touchscreen/mtouch.c
drivers/input/touchscreen/penmount.c
drivers/input/touchscreen/st1232.c
drivers/input/touchscreen/touchit213.c
drivers/input/touchscreen/touchright.c
drivers/input/touchscreen/touchwin.c
drivers/input/touchscreen/tsc40.c
drivers/input/touchscreen/wacom_i2c.c [new file with mode: 0644]
drivers/input/touchscreen/wacom_w8001.c
include/linux/gameport.h
include/linux/input/lm8333.h [new file with mode: 0644]
include/linux/serio.h

index 0130d6683c14eecf01c3a9b6226aec0549487a81..5e9cbdc7486eb29402f53f087d2b7f3724b0cffb 100644 (file)
@@ -15,9 +15,10 @@ Contact:     linux-input@vger.kernel.org
 Description:
                Attribute group for control of the status LEDs and the OLEDs.
                This attribute group is only available for Intuos 4 M, L,
-               and XL (with LEDs and OLEDs) and Cintiq 21UX2 and Cintiq 24HD
-               (LEDs only). Therefore its presence implicitly signifies the
-               presence of said LEDs and OLEDs on the tablet device.
+               and XL (with LEDs and OLEDs), Intuos 5 (LEDs only), and Cintiq
+               21UX2 and Cintiq 24HD (LEDs only). Therefore its presence
+               implicitly signifies the presence of said LEDs and OLEDs on the
+               tablet device.
 
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status0_luminance
 Date:          August 2011
@@ -40,10 +41,10 @@ What:               /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led0
 Date:          August 2011
 Contact:       linux-input@vger.kernel.org
 Description:
-               Writing to this file sets which one of the four (for Intuos 4)
-               or of the right four (for Cintiq 21UX2 and Cintiq 24HD) status
-               LEDs is active (0..3). The other three LEDs on the same side are
-               always inactive.
+               Writing to this file sets which one of the four (for Intuos 4
+               and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq
+               24HD) status LEDs is active (0..3). The other three LEDs on the
+               same side are always inactive.
 
 What:          /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led1_select
 Date:          September 2011
diff --git a/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt
new file mode 100644 (file)
index 0000000..d0c68e3
--- /dev/null
@@ -0,0 +1,16 @@
+* NXP LPC32xx SoC Touchscreen Controller (TSC)
+
+Required properties:
+- compatible: must be "nxp,lpc32xx-tsc"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: The TSC/ADC interrupt
+
+Example:
+
+       tsc@40048000 {
+               compatible = "nxp,lpc32xx-tsc";
+               reg = <0x40048000 0x1000>;
+               interrupt-parent = <&mic>;
+               interrupts = <39 0>;
+       };
index 1639ab2b94b7326e46a87503d98bcd2e6f3a71cb..85bc8dc07cfc084a32a10397412b649f5c7abbac 100644 (file)
@@ -413,15 +413,4 @@ static struct gameport_driver a3d_drv = {
        .disconnect     = a3d_disconnect,
 };
 
-static int __init a3d_init(void)
-{
-       return gameport_register_driver(&a3d_drv);
-}
-
-static void __exit a3d_exit(void)
-{
-       gameport_unregister_driver(&a3d_drv);
-}
-
-module_init(a3d_init);
-module_exit(a3d_exit);
+module_gameport_driver(a3d_drv);
index b992fbf91f2fd6958405a5bb59735c914945e101..0cbfd2dfabf4502173b165ec66e0c6aaafdbf989 100644 (file)
@@ -557,10 +557,6 @@ static void adi_disconnect(struct gameport *gameport)
        kfree(port);
 }
 
-/*
- * The gameport device structure.
- */
-
 static struct gameport_driver adi_drv = {
        .driver         = {
                .name   = "adi",
@@ -570,15 +566,4 @@ static struct gameport_driver adi_drv = {
        .disconnect     = adi_disconnect,
 };
 
-static int __init adi_init(void)
-{
-       return gameport_register_driver(&adi_drv);
-}
-
-static void __exit adi_exit(void)
-{
-       gameport_unregister_driver(&adi_drv);
-}
-
-module_init(adi_init);
-module_exit(adi_exit);
+module_gameport_driver(adi_drv);
index 3497b87c3d0591c12446f16bc232337c3f367981..65367e44d715391b251f0123309345784278173c 100644 (file)
@@ -261,15 +261,4 @@ static struct gameport_driver cobra_drv = {
        .disconnect     = cobra_disconnect,
 };
 
-static int __init cobra_init(void)
-{
-       return gameport_register_driver(&cobra_drv);
-}
-
-static void __exit cobra_exit(void)
-{
-       gameport_unregister_driver(&cobra_drv);
-}
-
-module_init(cobra_init);
-module_exit(cobra_exit);
+module_gameport_driver(cobra_drv);
index 0536b1b2f018e5d6838579e0dfb97f5d4e219880..ab1cf288200403a744fcefbdbfcd9b684196fa4c 100644 (file)
@@ -373,15 +373,4 @@ static struct gameport_driver gf2k_drv = {
        .disconnect     = gf2k_disconnect,
 };
 
-static int __init gf2k_init(void)
-{
-       return gameport_register_driver(&gf2k_drv);
-}
-
-static void __exit gf2k_exit(void)
-{
-       gameport_unregister_driver(&gf2k_drv);
-}
-
-module_init(gf2k_init);
-module_exit(gf2k_exit);
+module_gameport_driver(gf2k_drv);
index fc55899ba6c50a8d5d4c8336d100ca51677d440f..9e1beff57c33a5094f796fa62a13e6f93cb40701 100644 (file)
@@ -424,15 +424,4 @@ static struct gameport_driver grip_drv = {
        .disconnect     = grip_disconnect,
 };
 
-static int __init grip_init(void)
-{
-       return gameport_register_driver(&grip_drv);
-}
-
-static void __exit grip_exit(void)
-{
-       gameport_unregister_driver(&grip_drv);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
+module_gameport_driver(grip_drv);
index 2d47baf47769843a98e23d9b47665560ef885e7f..c0f9c7b7eb4eb4a4d1c738f7fc4d81f295e81ed1 100644 (file)
@@ -687,15 +687,4 @@ static struct gameport_driver grip_drv = {
        .disconnect     = grip_disconnect,
 };
 
-static int __init grip_init(void)
-{
-       return gameport_register_driver(&grip_drv);
-}
-
-static void __exit grip_exit(void)
-{
-       gameport_unregister_driver(&grip_drv);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
+module_gameport_driver(grip_drv);
index 4058d4b272fe88fed73a2a3f0183b1d2cbeabd9b..55196f730af6b80dd01284be87df1761b9899370 100644 (file)
@@ -281,15 +281,4 @@ static struct gameport_driver guillemot_drv = {
        .disconnect     = guillemot_disconnect,
 };
 
-static int __init guillemot_init(void)
-{
-       return gameport_register_driver(&guillemot_drv);
-}
-
-static void __exit guillemot_exit(void)
-{
-       gameport_unregister_driver(&guillemot_drv);
-}
-
-module_init(guillemot_init);
-module_exit(guillemot_exit);
+module_gameport_driver(guillemot_drv);
index 16fb19d1ca25f95542e04f8796f97949d1781003..88c22623a2e8cc01ec461d70f216f09486a25904 100644 (file)
@@ -311,15 +311,4 @@ static struct gameport_driver interact_drv = {
        .disconnect     = interact_disconnect,
 };
 
-static int __init interact_init(void)
-{
-       return gameport_register_driver(&interact_drv);
-}
-
-static void __exit interact_exit(void)
-{
-       gameport_unregister_driver(&interact_drv);
-}
-
-module_init(interact_init);
-module_exit(interact_exit);
+module_gameport_driver(interact_drv);
index cd894a0564a2f06932954d7dcec2ff6c179a9d92..7eb878bab9683505b42d40c0c4b79c6c20e93bdf 100644 (file)
@@ -159,15 +159,4 @@ static struct gameport_driver joydump_drv = {
        .disconnect     = joydump_disconnect,
 };
 
-static int __init joydump_init(void)
-{
-       return gameport_register_driver(&joydump_drv);
-}
-
-static void __exit joydump_exit(void)
-{
-       gameport_unregister_driver(&joydump_drv);
-}
-
-module_init(joydump_init);
-module_exit(joydump_exit);
+module_gameport_driver(joydump_drv);
index 40e40780747d50d2536824045171370a61f667bb..9fb153eef2fc07b28661a7ec4661a952587319cc 100644 (file)
@@ -222,19 +222,4 @@ static struct serio_driver magellan_drv = {
        .disconnect     = magellan_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init magellan_init(void)
-{
-       return serio_register_driver(&magellan_drv);
-}
-
-static void __exit magellan_exit(void)
-{
-       serio_unregister_driver(&magellan_drv);
-}
-
-module_init(magellan_init);
-module_exit(magellan_exit);
+module_serio_driver(magellan_drv);
index b8d86115644bbb9e6b9a1c4585ad4fc2bcca7483..04c69af371482e6927fc0416174265c95928d02c 100644 (file)
@@ -820,15 +820,4 @@ static struct gameport_driver sw_drv = {
        .disconnect     = sw_disconnect,
 };
 
-static int __init sw_init(void)
-{
-       return gameport_register_driver(&sw_drv);
-}
-
-static void __exit sw_exit(void)
-{
-       gameport_unregister_driver(&sw_drv);
-}
-
-module_init(sw_init);
-module_exit(sw_exit);
+module_gameport_driver(sw_drv);
index 0cd9b29356a8a5f06bb31885ef0581fa5c57f2dc..80a7b27a457a046cb94efd10dbc8ff84bb0eab8b 100644 (file)
@@ -296,19 +296,4 @@ static struct serio_driver spaceball_drv = {
        .disconnect     = spaceball_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init spaceball_init(void)
-{
-       return serio_register_driver(&spaceball_drv);
-}
-
-static void __exit spaceball_exit(void)
-{
-       serio_unregister_driver(&spaceball_drv);
-}
-
-module_init(spaceball_init);
-module_exit(spaceball_exit);
+module_serio_driver(spaceball_drv);
index a694bf8e557bbca7ec84e2101a0e895a226f5d34..a41f291652e6ce55b028e21f4049f50ad226e3f9 100644 (file)
@@ -237,19 +237,4 @@ static struct serio_driver spaceorb_drv = {
        .disconnect     = spaceorb_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init spaceorb_init(void)
-{
-       return serio_register_driver(&spaceorb_drv);
-}
-
-static void __exit spaceorb_exit(void)
-{
-       serio_unregister_driver(&spaceorb_drv);
-}
-
-module_init(spaceorb_init);
-module_exit(spaceorb_exit);
+module_serio_driver(spaceorb_drv);
index e0db9f5e4b413962baa220b37ee4640927e51882..0f51a60e14a7f9903950c37b55c16d35fb83b98a 100644 (file)
@@ -208,19 +208,4 @@ static struct serio_driver stinger_drv = {
        .disconnect     = stinger_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init stinger_init(void)
-{
-       return serio_register_driver(&stinger_drv);
-}
-
-static void __exit stinger_exit(void)
-{
-       serio_unregister_driver(&stinger_drv);
-}
-
-module_init(stinger_init);
-module_exit(stinger_exit);
+module_serio_driver(stinger_drv);
index d6c6098071150e02a456d1688c71fbf44a78cd91..5ef9bcdb0345bff2ebacac80ea73ea318403dd03 100644 (file)
@@ -436,15 +436,4 @@ static struct gameport_driver tmdc_drv = {
        .disconnect     = tmdc_disconnect,
 };
 
-static int __init tmdc_init(void)
-{
-       return gameport_register_driver(&tmdc_drv);
-}
-
-static void __exit tmdc_exit(void)
-{
-       gameport_unregister_driver(&tmdc_drv);
-}
-
-module_init(tmdc_init);
-module_exit(tmdc_exit);
+module_gameport_driver(tmdc_drv);
index 3f4ec73c9553a2debeb52f2789b3e016a555b7cb..2556a819357978897db8889dda334180b621c045 100644 (file)
@@ -257,19 +257,4 @@ static struct serio_driver twidjoy_drv = {
        .disconnect     = twidjoy_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init twidjoy_init(void)
-{
-       return serio_register_driver(&twidjoy_drv);
-}
-
-static void __exit twidjoy_exit(void)
-{
-       serio_unregister_driver(&twidjoy_drv);
-}
-
-module_init(twidjoy_init);
-module_exit(twidjoy_exit);
+module_serio_driver(twidjoy_drv);
index f72c83e15e6020ddfa288558011ef8918efaa3d3..23b3071abb6e4b92ba8cf01b9e8bb8994c8e485e 100644 (file)
@@ -217,19 +217,4 @@ static struct serio_driver warrior_drv = {
        .disconnect     = warrior_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init warrior_init(void)
-{
-       return serio_register_driver(&warrior_drv);
-}
-
-static void __exit warrior_exit(void)
-{
-       serio_unregister_driver(&warrior_drv);
-}
-
-module_init(warrior_init);
-module_exit(warrior_exit);
+module_serio_driver(warrior_drv);
index b5853125c8987b72ecf766e123e1e66db727a6c5..c4de4388fd7f1f1b6efd1dbf3b2013e74b6e8881 100644 (file)
@@ -225,19 +225,4 @@ static struct serio_driver zhenhua_drv = {
        .disconnect     = zhenhua_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init zhenhua_init(void)
-{
-       return serio_register_driver(&zhenhua_drv);
-}
-
-static void __exit zhenhua_exit(void)
-{
-       serio_unregister_driver(&zhenhua_drv);
-}
-
-module_init(zhenhua_init);
-module_exit(zhenhua_exit);
+module_serio_driver(zhenhua_drv);
index f354813a13e8608868040355e3a1f4f19cf2b139..7eaf93fe51280a48b9a6e45b0a5644f794ff3db6 100644 (file)
@@ -309,6 +309,16 @@ config KEYBOARD_LM8323
          To compile this driver as a module, choose M here: the
          module will be called lm8323.
 
+config KEYBOARD_LM8333
+       tristate "LM8333 keypad chip"
+       depends on I2C
+       help
+         If you say yes here you get support for the National Semiconductor
+         LM8333 keypad controller.
+
+         To compile this driver as a module, choose M here: the
+         module will be called lm8333.
+
 config KEYBOARD_LOCOMO
        tristate "LoCoMo Keyboard Support"
        depends on SHARP_LOCOMO
index df7061f129184f4c5dfb6265229529fe1387dcf7..b03b02456a828d03570bb0b8d950f0ebbb2b7589 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_KEYBOARD_HP6XX)          += jornada680_kbd.o
 obj-$(CONFIG_KEYBOARD_HP7XX)           += jornada720_kbd.o
 obj-$(CONFIG_KEYBOARD_LKKBD)           += lkkbd.o
 obj-$(CONFIG_KEYBOARD_LM8323)          += lm8323.o
+obj-$(CONFIG_KEYBOARD_LM8333)          += lm8333.o
 obj-$(CONFIG_KEYBOARD_LOCOMO)          += locomokbd.o
 obj-$(CONFIG_KEYBOARD_MAPLE)           += maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)          += matrix_keypad.o
index 0ba69f3fcb52b8ca3d47ce3516be6b2f6bbbf167..df194bdaab509607c2c70a5033f913964c4bd53b 100644 (file)
@@ -182,16 +182,10 @@ static void ep93xx_keypad_close(struct input_dev *pdev)
 }
 
 
-#ifdef CONFIG_PM
-/*
- * NOTE: I don't know if this is correct, or will work on the ep93xx.
- *
- * None of the existing ep93xx drivers have power management support.
- * But, this is basically what the pxa27x_keypad driver does.
- */
-static int ep93xx_keypad_suspend(struct platform_device *pdev,
-                                pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int ep93xx_keypad_suspend(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
        struct input_dev *input_dev = keypad->input_dev;
 
@@ -210,8 +204,9 @@ static int ep93xx_keypad_suspend(struct platform_device *pdev,
        return 0;
 }
 
-static int ep93xx_keypad_resume(struct platform_device *pdev)
+static int ep93xx_keypad_resume(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
        struct input_dev *input_dev = keypad->input_dev;
 
@@ -232,10 +227,10 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
 
        return 0;
 }
-#else  /* !CONFIG_PM */
-#define ep93xx_keypad_suspend  NULL
-#define ep93xx_keypad_resume   NULL
-#endif /* !CONFIG_PM */
+#endif
+
+static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
+                        ep93xx_keypad_suspend, ep93xx_keypad_resume);
 
 static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
 {
@@ -384,11 +379,10 @@ static struct platform_driver ep93xx_keypad_driver = {
        .driver         = {
                .name   = "ep93xx-keypad",
                .owner  = THIS_MODULE,
+               .pm     = &ep93xx_keypad_pm_ops,
        },
        .probe          = ep93xx_keypad_probe,
        .remove         = __devexit_p(ep93xx_keypad_remove),
-       .suspend        = ep93xx_keypad_suspend,
-       .resume         = ep93xx_keypad_resume,
 };
 module_platform_driver(ep93xx_keypad_driver);
 
index fed31e0947a170f7a39468f97ec4ab10a3ab3181..589e3c258f3f1ecd48c0df846987e796b02ebdbc 100644 (file)
@@ -583,15 +583,4 @@ static struct serio_driver hil_serio_drv = {
        .interrupt      = hil_dev_interrupt
 };
 
-static int __init hil_dev_init(void)
-{
-       return serio_register_driver(&hil_serio_drv);
-}
-
-static void __exit hil_dev_exit(void)
-{
-       serio_unregister_driver(&hil_serio_drv);
-}
-
-module_init(hil_dev_init);
-module_exit(hil_dev_exit);
+module_serio_driver(hil_serio_drv);
index fa9bb6d235e20b88695f95e85c3164fae911d334..fc0a63c2f2785a8b529ad3e0afc43debc284d6c7 100644 (file)
@@ -731,19 +731,4 @@ static struct serio_driver lkkbd_drv = {
        .interrupt      = lkkbd_interrupt,
 };
 
-/*
- * The functions for insering/removing us as a module.
- */
-static int __init lkkbd_init(void)
-{
-       return serio_register_driver(&lkkbd_drv);
-}
-
-static void __exit lkkbd_exit(void)
-{
-       serio_unregister_driver(&lkkbd_drv);
-}
-
-module_init(lkkbd_init);
-module_exit(lkkbd_exit);
-
+module_serio_driver(lkkbd_drv);
diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
new file mode 100644 (file)
index 0000000..9a8c4a6
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * LM8333 keypad driver
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/input/lm8333.h>
+
+#define LM8333_FIFO_READ               0x20
+#define LM8333_DEBOUNCE                        0x22
+#define LM8333_READ_INT                        0xD0
+#define LM8333_ACTIVE                  0xE4
+#define LM8333_READ_ERROR              0xF0
+
+#define LM8333_KEYPAD_IRQ              (1 << 0)
+#define LM8333_ERROR_IRQ               (1 << 3)
+
+#define LM8333_ERROR_KEYOVR            0x04
+#define LM8333_ERROR_FIFOOVR           0x40
+
+#define LM8333_FIFO_TRANSFER_SIZE      16
+
+#define LM8333_ROW_SHIFT       4
+#define LM8333_NUM_ROWS                8
+
+
+struct lm8333 {
+       struct i2c_client *client;
+       struct input_dev *input;
+       unsigned short keycodes[LM8333_NUM_ROWS << LM8333_ROW_SHIFT];
+};
+
+/* The accessors try twice because the first access may be needed for wakeup */
+#define LM8333_READ_RETRIES 2
+
+int lm8333_read8(struct lm8333 *lm8333, u8 cmd)
+{
+       int retries = 0, ret;
+
+       do {
+               ret = i2c_smbus_read_byte_data(lm8333->client, cmd);
+       } while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+       return ret;
+}
+
+int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val)
+{
+       int retries = 0, ret;
+
+       do {
+               ret = i2c_smbus_write_byte_data(lm8333->client, cmd, val);
+       } while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+       return ret;
+}
+
+int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf)
+{
+       int retries = 0, ret;
+
+       do {
+               ret = i2c_smbus_read_i2c_block_data(lm8333->client,
+                                                   cmd, len, buf);
+       } while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+       return ret;
+}
+
+static void lm8333_key_handler(struct lm8333 *lm8333)
+{
+       struct input_dev *input = lm8333->input;
+       u8 keys[LM8333_FIFO_TRANSFER_SIZE];
+       u8 code, pressed;
+       int i, ret;
+
+       ret = lm8333_read_block(lm8333, LM8333_FIFO_READ,
+                               LM8333_FIFO_TRANSFER_SIZE, keys);
+       if (ret != LM8333_FIFO_TRANSFER_SIZE) {
+               dev_err(&lm8333->client->dev,
+                       "Error %d while reading FIFO\n", ret);
+               return;
+       }
+
+       for (i = 0; keys[i] && i < LM8333_FIFO_TRANSFER_SIZE; i++) {
+               pressed = keys[i] & 0x80;
+               code = keys[i] & 0x7f;
+
+               input_event(input, EV_MSC, MSC_SCAN, code);
+               input_report_key(input, lm8333->keycodes[code], pressed);
+       }
+
+       input_sync(input);
+}
+
+static irqreturn_t lm8333_irq_thread(int irq, void *data)
+{
+       struct lm8333 *lm8333 = data;
+       u8 status = lm8333_read8(lm8333, LM8333_READ_INT);
+
+       if (!status)
+               return IRQ_NONE;
+
+       if (status & LM8333_ERROR_IRQ) {
+               u8 err = lm8333_read8(lm8333, LM8333_READ_ERROR);
+
+               if (err & (LM8333_ERROR_KEYOVR | LM8333_ERROR_FIFOOVR)) {
+                       u8 dummy[LM8333_FIFO_TRANSFER_SIZE];
+
+                       lm8333_read_block(lm8333, LM8333_FIFO_READ,
+                                       LM8333_FIFO_TRANSFER_SIZE, dummy);
+               }
+               dev_err(&lm8333->client->dev, "Got error %02x\n", err);
+       }
+
+       if (status & LM8333_KEYPAD_IRQ)
+               lm8333_key_handler(lm8333);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit lm8333_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       const struct lm8333_platform_data *pdata = client->dev.platform_data;
+       struct lm8333 *lm8333;
+       struct input_dev *input;
+       int err, active_time;
+
+       if (!pdata)
+               return -EINVAL;
+
+       active_time = pdata->active_time ?: 500;
+       if (active_time / 3 <= pdata->debounce_time / 3) {
+               dev_err(&client->dev, "Active time not big enough!\n");
+               return -EINVAL;
+       }
+
+       lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!lm8333 || !input) {
+               err = -ENOMEM;
+               goto free_mem;
+       }
+
+       lm8333->client = client;
+       lm8333->input = input;
+
+       input->name = client->name;
+       input->dev.parent = &client->dev;
+       input->id.bustype = BUS_I2C;
+
+       input->keycode = lm8333->keycodes;
+       input->keycodesize = sizeof(lm8333->keycodes[0]);
+       input->keycodemax = ARRAY_SIZE(lm8333->keycodes);
+       input->evbit[0] = BIT_MASK(EV_KEY);
+       input_set_capability(input, EV_MSC, MSC_SCAN);
+
+       matrix_keypad_build_keymap(pdata->matrix_data, LM8333_ROW_SHIFT,
+                       input->keycode, input->keybit);
+
+       if (pdata->debounce_time) {
+               err = lm8333_write8(lm8333, LM8333_DEBOUNCE,
+                                   pdata->debounce_time / 3);
+               if (err)
+                       dev_warn(&client->dev, "Unable to set debounce time\n");
+       }
+
+       if (pdata->active_time) {
+               err = lm8333_write8(lm8333, LM8333_ACTIVE,
+                                   pdata->active_time / 3);
+               if (err)
+                       dev_warn(&client->dev, "Unable to set active time\n");
+       }
+
+       err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                  "lm8333", lm8333);
+       if (err)
+               goto free_mem;
+
+       err = input_register_device(input);
+       if (err)
+               goto free_irq;
+
+       i2c_set_clientdata(client, lm8333);
+       return 0;
+
+ free_irq:
+       free_irq(client->irq, lm8333);
+ free_mem:
+       input_free_device(input);
+       kfree(lm8333);
+       return err;
+}
+
+static int __devexit lm8333_remove(struct i2c_client *client)
+{
+       struct lm8333 *lm8333 = i2c_get_clientdata(client);
+
+       free_irq(client->irq, lm8333);
+       input_unregister_device(lm8333->input);
+       kfree(lm8333);
+
+       return 0;
+}
+
+static const struct i2c_device_id lm8333_id[] = {
+       { "lm8333", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lm8333_id);
+
+static struct i2c_driver lm8333_driver = {
+       .driver = {
+               .name           = "lm8333",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = lm8333_probe,
+       .remove         = __devexit_p(lm8333_remove),
+       .id_table       = lm8333_id,
+};
+module_i2c_driver(lm8333_driver);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("LM8333 keyboard driver");
+MODULE_LICENSE("GPL v2");
index 9b223d73de326a12f9a7279e15d7a85ad4cd8760..98ae281bedb0503cd0bc0942d818e6abba0047a3 100644 (file)
@@ -27,7 +27,6 @@
 struct matrix_keypad {
        const struct matrix_keypad_platform_data *pdata;
        struct input_dev *input_dev;
-       unsigned short *keycodes;
        unsigned int row_shift;
 
        DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
@@ -38,6 +37,8 @@ struct matrix_keypad {
        bool scan_pending;
        bool stopped;
        bool gpio_all_disabled;
+
+       unsigned short keycodes[];
 };
 
 /*
@@ -224,7 +225,7 @@ static void matrix_keypad_stop(struct input_dev *dev)
        disable_row_irqs(keypad);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
 {
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
@@ -293,16 +294,16 @@ static int matrix_keypad_resume(struct device *dev)
 
        return 0;
 }
-
-static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
-                               matrix_keypad_suspend, matrix_keypad_resume);
 #endif
 
-static int __devinit init_matrix_gpio(struct platform_device *pdev,
-                                       struct matrix_keypad *keypad)
+static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
+                        matrix_keypad_suspend, matrix_keypad_resume);
+
+static int __devinit matrix_keypad_init_gpio(struct platform_device *pdev,
+                                            struct matrix_keypad *keypad)
 {
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
-       int i, err = -EINVAL;
+       int i, err;
 
        /* initialized strobe lines as outputs, activated */
        for (i = 0; i < pdata->num_col_gpios; i++) {
@@ -348,8 +349,7 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
                                        "matrix-keypad", keypad);
                        if (err) {
                                dev_err(&pdev->dev,
-                                       "Unable to acquire interrupt "
-                                       "for GPIO line %i\n",
+                                       "Unable to acquire interrupt for GPIO line %i\n",
                                        pdata->row_gpios[i]);
                                goto err_free_irqs;
                        }
@@ -375,14 +375,33 @@ err_free_cols:
        return err;
 }
 
+static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
+{
+       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+       int i;
+
+       if (pdata->clustered_irq > 0) {
+               free_irq(pdata->clustered_irq, keypad);
+       } else {
+               for (i = 0; i < pdata->num_row_gpios; i++)
+                       free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
+       }
+
+       for (i = 0; i < pdata->num_row_gpios; i++)
+               gpio_free(pdata->row_gpios[i]);
+
+       for (i = 0; i < pdata->num_col_gpios; i++)
+               gpio_free(pdata->col_gpios[i]);
+}
+
 static int __devinit matrix_keypad_probe(struct platform_device *pdev)
 {
        const struct matrix_keypad_platform_data *pdata;
        const struct matrix_keymap_data *keymap_data;
        struct matrix_keypad *keypad;
        struct input_dev *input_dev;
-       unsigned short *keycodes;
        unsigned int row_shift;
+       size_t keymap_size;
        int err;
 
        pdata = pdev->dev.platform_data;
@@ -398,20 +417,18 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
        }
 
        row_shift = get_count_order(pdata->num_col_gpios);
-
-       keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
-       keycodes = kzalloc((pdata->num_row_gpios << row_shift) *
-                               sizeof(*keycodes),
-                          GFP_KERNEL);
+       keymap_size = (pdata->num_row_gpios << row_shift) *
+                       sizeof(keypad->keycodes[0]);
+       keypad = kzalloc(sizeof(struct matrix_keypad) + keymap_size,
+                        GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!keypad || !keycodes || !input_dev) {
+       if (!keypad || !input_dev) {
                err = -ENOMEM;
                goto err_free_mem;
        }
 
        keypad->input_dev = input_dev;
        keypad->pdata = pdata;
-       keypad->keycodes = keycodes;
        keypad->row_shift = row_shift;
        keypad->stopped = true;
        INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
@@ -426,8 +443,8 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
        input_dev->open         = matrix_keypad_start;
        input_dev->close        = matrix_keypad_stop;
 
-       input_dev->keycode      = keycodes;
-       input_dev->keycodesize  = sizeof(*keycodes);
+       input_dev->keycode      = keypad->keycodes;
+       input_dev->keycodesize  = sizeof(keypad->keycodes[0]);
        input_dev->keycodemax   = pdata->num_row_gpios << row_shift;
 
        matrix_keypad_build_keymap(keymap_data, row_shift,
@@ -436,22 +453,23 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
        input_set_drvdata(input_dev, keypad);
 
-       err = init_matrix_gpio(pdev, keypad);
+       err = matrix_keypad_init_gpio(pdev, keypad);
        if (err)
                goto err_free_mem;
 
        err = input_register_device(keypad->input_dev);
        if (err)
-               goto err_free_mem;
+               goto err_free_gpio;
 
        device_init_wakeup(&pdev->dev, pdata->wakeup);
        platform_set_drvdata(pdev, keypad);
 
        return 0;
 
+err_free_gpio:
+       matrix_keypad_free_gpio(keypad);
 err_free_mem:
        input_free_device(input_dev);
-       kfree(keycodes);
        kfree(keypad);
        return err;
 }
@@ -459,29 +477,15 @@ err_free_mem:
 static int __devexit matrix_keypad_remove(struct platform_device *pdev)
 {
        struct matrix_keypad *keypad = platform_get_drvdata(pdev);
-       const struct matrix_keypad_platform_data *pdata = keypad->pdata;
-       int i;
 
        device_init_wakeup(&pdev->dev, 0);
 
-       if (pdata->clustered_irq > 0) {
-               free_irq(pdata->clustered_irq, keypad);
-       } else {
-               for (i = 0; i < pdata->num_row_gpios; i++)
-                       free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
-       }
-
-       for (i = 0; i < pdata->num_row_gpios; i++)
-               gpio_free(pdata->row_gpios[i]);
-
-       for (i = 0; i < pdata->num_col_gpios; i++)
-               gpio_free(pdata->col_gpios[i]);
-
+       matrix_keypad_free_gpio(keypad);
        input_unregister_device(keypad->input_dev);
-       platform_set_drvdata(pdev, NULL);
-       kfree(keypad->keycodes);
        kfree(keypad);
 
+       platform_set_drvdata(pdev, NULL);
+
        return 0;
 }
 
@@ -491,9 +495,7 @@ static struct platform_driver matrix_keypad_driver = {
        .driver         = {
                .name   = "matrix-keypad",
                .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm     = &matrix_keypad_pm_ops,
-#endif
        },
 };
 module_platform_driver(matrix_keypad_driver);
index 48d1cab0aa1c7284dcc795391d1759303f39db7c..f971898ad59183f07aafd0811cd725f3aea903e2 100644 (file)
@@ -166,15 +166,4 @@ static struct serio_driver nkbd_drv = {
        .disconnect     = nkbd_disconnect,
 };
 
-static int __init nkbd_init(void)
-{
-       return serio_register_driver(&nkbd_drv);
-}
-
-static void __exit nkbd_exit(void)
-{
-       serio_unregister_driver(&nkbd_drv);
-}
-
-module_init(nkbd_init);
-module_exit(nkbd_exit);
+module_serio_driver(nkbd_drv);
index 7437219370b1a22e0695003d7318f596e60350d1..cc612c5d542782fdf898757bdfdd1434b7d19d86 100644 (file)
@@ -170,15 +170,4 @@ static struct serio_driver skbd_drv = {
        .disconnect     = skbd_disconnect,
 };
 
-static int __init skbd_init(void)
-{
-       return serio_register_driver(&skbd_drv);
-}
-
-static void __exit skbd_exit(void)
-{
-       serio_unregister_driver(&skbd_drv);
-}
-
-module_init(skbd_init);
-module_exit(skbd_exit);
+module_serio_driver(skbd_drv);
index a99a04b03ee49f3161d3f97ff6cecc8141b50ec9..5f836b1638c159fa4f2386e09c516092abe8dbd8 100644 (file)
@@ -369,19 +369,4 @@ static struct serio_driver sunkbd_drv = {
        .disconnect     = sunkbd_disconnect,
 };
 
-/*
- * The functions for insering/removing us as a module.
- */
-
-static int __init sunkbd_init(void)
-{
-       return serio_register_driver(&sunkbd_drv);
-}
-
-static void __exit sunkbd_exit(void)
-{
-       serio_unregister_driver(&sunkbd_drv);
-}
-
-module_init(sunkbd_init);
-module_exit(sunkbd_exit);
+module_serio_driver(sunkbd_drv);
index 2dee3e4e7c6f1a8f337ea4739fe69ab0cb7e7b55..f4da2a7a6970ef49fa430f4b5c2fe75f7673135f 100644 (file)
@@ -96,21 +96,15 @@ static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
 {
        int ret;
        struct tc3589x *tc3589x = keypad->tc3589x;
-       u8 settle_time = keypad->board->settle_time;
-       u8 dbounce_period = keypad->board->debounce_period;
-       u8 rows = keypad->board->krow & 0xf;    /* mask out the nibble */
-       u8 column = keypad->board->kcol & 0xf;  /* mask out the nibble */
-
-       /* validate platform configurations */
-       if (keypad->board->kcol > TC3589x_MAX_KPCOL ||
-           keypad->board->krow > TC3589x_MAX_KPROW ||
-           keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE ||
-           keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE)
+       const struct tc3589x_keypad_platform_data *board = keypad->board;
+
+       /* validate platform configuration */
+       if (board->kcol > TC3589x_MAX_KPCOL || board->krow > TC3589x_MAX_KPROW)
                return -EINVAL;
 
        /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
        ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE,
-                       (rows << KP_ROW_SHIFT) | column);
+                       (board->krow << KP_ROW_SHIFT) | board->kcol);
        if (ret < 0)
                return ret;
 
@@ -124,12 +118,14 @@ static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
                return ret;
 
        /* Configure settle time */
-       ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time);
+       ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG,
+                               board->settle_time);
        if (ret < 0)
                return ret;
 
        /* Configure debounce time */
-       ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period);
+       ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE,
+                               board->debounce_period);
        if (ret < 0)
                return ret;
 
index 37b01d777a4abc2ccf8652d91a15839bee41d334..d050d9d0011bfe42313e0617ea8674591c57f466 100644 (file)
@@ -169,15 +169,4 @@ static struct serio_driver xtkbd_drv = {
        .disconnect     = xtkbd_disconnect,
 };
 
-static int __init xtkbd_init(void)
-{
-       return serio_register_driver(&xtkbd_drv);
-}
-
-static void __exit xtkbd_exit(void)
-{
-       serio_unregister_driver(&xtkbd_drv);
-}
-
-module_init(xtkbd_init);
-module_exit(xtkbd_exit);
+module_serio_driver(xtkbd_drv);
index 06517e60e50c1e64742083eb1371fb7a328bd929..a3735a01e9fd430820037872e5050e8203661a20 100644 (file)
@@ -318,7 +318,7 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
        mutex_init(&data->mutex);
 
        data->mode = pdata->mode;
-       if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
+       if (data->mode > CMAMODE_POFF) {
                data->mode = CMAMODE_MOTDET;
                dev_warn(dev,
                         "Invalid mode specified, assuming Motion Detect\n");
index 17ff137b9bd5ee2b3fedd916f752270c415f0299..d5928fd0c914e8f28e30eee232ea990cfb47f484 100644 (file)
@@ -355,15 +355,4 @@ static struct serio_driver sermouse_drv = {
        .disconnect     = sermouse_disconnect,
 };
 
-static int __init sermouse_init(void)
-{
-       return serio_register_driver(&sermouse_drv);
-}
-
-static void __exit sermouse_exit(void)
-{
-       serio_unregister_driver(&sermouse_drv);
-}
-
-module_init(sermouse_init);
-module_exit(sermouse_exit);
+module_serio_driver(sermouse_drv);
index eb9a3cfbeefaacba0f646cd7bd225a535303a816..e900d465aaf624f73762f0a5fe9a3461d76da5b0 100644 (file)
@@ -548,16 +548,4 @@ static struct serio_driver vsxxxaa_drv = {
        .disconnect     = vsxxxaa_disconnect,
 };
 
-static int __init vsxxxaa_init(void)
-{
-       return serio_register_driver(&vsxxxaa_drv);
-}
-
-static void __exit vsxxxaa_exit(void)
-{
-       serio_unregister_driver(&vsxxxaa_drv);
-}
-
-module_init(vsxxxaa_init);
-module_exit(vsxxxaa_exit);
-
+module_serio_driver(vsxxxaa_drv);
index 15aa81c9f1fb0215d1552bd36d22c5adf10d62c4..a76fb64f03db8fe910b4cd67688e848453489c70 100644 (file)
@@ -304,15 +304,4 @@ static struct serio_driver ps2mult_drv = {
        .reconnect      = ps2mult_reconnect,
 };
 
-static int __init ps2mult_init(void)
-{
-       return serio_register_driver(&ps2mult_drv);
-}
-
-static void __exit ps2mult_exit(void)
-{
-       serio_unregister_driver(&ps2mult_drv);
-}
-
-module_init(ps2mult_init);
-module_exit(ps2mult_exit);
+module_serio_driver(ps2mult_drv);
index 4494233d331ac4689eef8ca58366c7138904627d..3e243621c0e30501eddd29916b289a368911a4d2 100644 (file)
@@ -165,31 +165,38 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer,
        struct serio_raw *serio_raw = client->serio_raw;
        char uninitialized_var(c);
        ssize_t read = 0;
-       int retval;
+       int error = 0;
 
-       if (serio_raw->dead)
-               return -ENODEV;
+       do {
+               if (serio_raw->dead)
+                       return -ENODEV;
 
-       if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
-               return -EAGAIN;
+               if (serio_raw->head == serio_raw->tail &&
+                   (file->f_flags & O_NONBLOCK))
+                       return -EAGAIN;
 
-       retval = wait_event_interruptible(serio_raw->wait,
-                       serio_raw->head != serio_raw->tail || serio_raw->dead);
-       if (retval)
-               return retval;
+               if (count == 0)
+                       break;
 
-       if (serio_raw->dead)
-               return -ENODEV;
+               while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
+                       if (put_user(c, buffer++)) {
+                               error = -EFAULT;
+                               goto out;
+                       }
+                       read++;
+               }
 
-       while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
-               if (put_user(c, buffer++)) {
-                       retval = -EFAULT;
+               if (read)
                        break;
-               }
-               read++;
-       }
 
-       return read ?: retval;
+               if (!(file->f_flags & O_NONBLOCK))
+                       error = wait_event_interruptible(serio_raw->wait,
+                                       serio_raw->head != serio_raw->tail ||
+                                       serio_raw->dead);
+       } while (!error);
+
+out:
+       return read ?: error;
 }
 
 static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
@@ -432,15 +439,4 @@ static struct serio_driver serio_raw_drv = {
        .manual_bind    = true,
 };
 
-static int __init serio_raw_init(void)
-{
-       return serio_register_driver(&serio_raw_drv);
-}
-
-static void __exit serio_raw_exit(void)
-{
-       serio_unregister_driver(&serio_raw_drv);
-}
-
-module_init(serio_raw_init);
-module_exit(serio_raw_exit);
+module_serio_driver(serio_raw_drv);
index d96d4c2a76a94793270c6e4ce6dda247b2e08ebe..1e983bec7d86c524243d55e57ff409e2d831571d 100644 (file)
@@ -73,7 +73,8 @@ struct xps2data {
        spinlock_t lock;
        void __iomem *base_address;     /* virt. address of control registers */
        unsigned int flags;
-       struct serio serio;             /* serio */
+       struct serio *serio;            /* serio */
+       struct device *dev;
 };
 
 /************************************/
@@ -119,7 +120,7 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
 
        /* Check which interrupt is active */
        if (intr_sr & XPS2_IPIXR_RX_OVF)
-               dev_warn(drvdata->serio.dev.parent, "receive overrun error\n");
+               dev_warn(drvdata->dev, "receive overrun error\n");
 
        if (intr_sr & XPS2_IPIXR_RX_ERR)
                drvdata->flags |= SERIO_PARITY;
@@ -132,10 +133,10 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
 
                /* Error, if a byte is not received */
                if (status) {
-                       dev_err(drvdata->serio.dev.parent,
+                       dev_err(drvdata->dev,
                                "wrong rcvd byte count (%d)\n", status);
                } else {
-                       serio_interrupt(&drvdata->serio, c, drvdata->flags);
+                       serio_interrupt(drvdata->serio, c, drvdata->flags);
                        drvdata->flags = 0;
                }
        }
@@ -193,7 +194,7 @@ static int sxps2_open(struct serio *pserio)
        error = request_irq(drvdata->irq, &xps2_interrupt, 0,
                                DRIVER_NAME, drvdata);
        if (error) {
-               dev_err(drvdata->serio.dev.parent,
+               dev_err(drvdata->dev,
                        "Couldn't allocate interrupt %d\n", drvdata->irq);
                return error;
        }
@@ -259,15 +260,16 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
        }
 
        drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
-       if (!drvdata) {
-               dev_err(dev, "Couldn't allocate device private record\n");
-               return -ENOMEM;
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+       if (!drvdata || !serio) {
+               error = -ENOMEM;
+               goto failed1;
        }
 
-       dev_set_drvdata(dev, drvdata);
-
        spin_lock_init(&drvdata->lock);
        drvdata->irq = r_irq.start;
+       drvdata->serio = serio;
+       drvdata->dev = dev;
 
        phys_addr = r_mem.start;
        remap_size = resource_size(&r_mem);
@@ -298,7 +300,6 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
                 (unsigned long long)phys_addr, drvdata->base_address,
                 drvdata->irq);
 
-       serio = &drvdata->serio;
        serio->id.type = SERIO_8042;
        serio->write = sxps2_write;
        serio->open = sxps2_open;
@@ -312,13 +313,14 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
 
        serio_register_port(serio);
 
+       platform_set_drvdata(ofdev, drvdata);
        return 0;               /* success */
 
 failed2:
        release_mem_region(phys_addr, remap_size);
 failed1:
+       kfree(serio);
        kfree(drvdata);
-       dev_set_drvdata(dev, NULL);
 
        return error;
 }
@@ -333,22 +335,21 @@ failed1:
  */
 static int __devexit xps2_of_remove(struct platform_device *of_dev)
 {
-       struct device *dev = &of_dev->dev;
-       struct xps2data *drvdata = dev_get_drvdata(dev);
+       struct xps2data *drvdata = platform_get_drvdata(of_dev);
        struct resource r_mem; /* IO mem resources */
 
-       serio_unregister_port(&drvdata->serio);
+       serio_unregister_port(drvdata->serio);
        iounmap(drvdata->base_address);
 
        /* Get iospace of the device */
        if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem))
-               dev_err(dev, "invalid address\n");
+               dev_err(drvdata->dev, "invalid address\n");
        else
                release_mem_region(r_mem.start, resource_size(&r_mem));
 
        kfree(drvdata);
 
-       dev_set_drvdata(dev, NULL);
+       platform_set_drvdata(of_dev, NULL);
 
        return 0;
 }
index 0d269212931e86be95d4c77c26b667ac781200c2..98e9dd692d680cb888a4ae3eae6777a77124851d 100644 (file)
@@ -233,6 +233,9 @@ static int wacom_parse_logical_collection(unsigned char *report,
  * 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
  * Collection. Instead they define a Logical Collection with a single
  * Logical Maximum for both X and Y.
+ *
+ * Intuos5 touch interface does not contain useful data. We deal with
+ * this after returning from this function.
  */
 static int wacom_parse_hid(struct usb_interface *intf,
                           struct hid_descriptor *hid_desc,
@@ -574,23 +577,39 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom)
 static int wacom_led_control(struct wacom *wacom)
 {
        unsigned char *buf;
-       int retval, led = 0;
+       int retval;
 
        buf = kzalloc(9, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
-           wacom->wacom_wac.features.type == WACOM_24HD)
-               led = (wacom->led.select[1] << 4) | 0x40;
-
-       led |=  wacom->led.select[0] | 0x4;
-
-       buf[0] = WAC_CMD_LED_CONTROL;
-       buf[1] = led;
-       buf[2] = wacom->led.llv;
-       buf[3] = wacom->led.hlv;
-       buf[4] = wacom->led.img_lum;
+       if (wacom->wacom_wac.features.type >= INTUOS5S &&
+           wacom->wacom_wac.features.type <= INTUOS5L) {
+               /*
+                * Touch Ring and crop mark LED luminance may take on
+                * one of four values:
+                *    0 = Low; 1 = Medium; 2 = High; 3 = Off
+                */
+               int ring_led = wacom->led.select[0] & 0x03;
+               int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
+               int crop_lum = 0;
+
+               buf[0] = WAC_CMD_LED_CONTROL;
+               buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
+       }
+       else {
+               int led = wacom->led.select[0] | 0x4;
+
+               if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
+                   wacom->wacom_wac.features.type == WACOM_24HD)
+                       led |= (wacom->led.select[1] << 4) | 0x40;
+
+               buf[0] = WAC_CMD_LED_CONTROL;
+               buf[1] = led;
+               buf[2] = wacom->led.llv;
+               buf[3] = wacom->led.hlv;
+               buf[4] = wacom->led.img_lum;
+       }
 
        retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
                                  buf, 9, WAC_CMD_RETRIES);
@@ -783,6 +802,17 @@ static struct attribute_group intuos4_led_attr_group = {
        .attrs = intuos4_led_attrs,
 };
 
+static struct attribute *intuos5_led_attrs[] = {
+       &dev_attr_status0_luminance.attr,
+       &dev_attr_status_led0_select.attr,
+       NULL
+};
+
+static struct attribute_group intuos5_led_attr_group = {
+       .name = "wacom_led",
+       .attrs = intuos5_led_attrs,
+};
+
 static int wacom_initialize_leds(struct wacom *wacom)
 {
        int error;
@@ -812,6 +842,19 @@ static int wacom_initialize_leds(struct wacom *wacom)
                                           &cintiq_led_attr_group);
                break;
 
+       case INTUOS5S:
+       case INTUOS5:
+       case INTUOS5L:
+               wacom->led.select[0] = 0;
+               wacom->led.select[1] = 0;
+               wacom->led.llv = 32;
+               wacom->led.hlv = 0;
+               wacom->led.img_lum = 0;
+
+               error = sysfs_create_group(&wacom->intf->dev.kobj,
+                                          &intuos5_led_attr_group);
+               break;
+
        default:
                return 0;
        }
@@ -840,6 +883,13 @@ static void wacom_destroy_leds(struct wacom *wacom)
                sysfs_remove_group(&wacom->intf->dev.kobj,
                                   &cintiq_led_attr_group);
                break;
+
+       case INTUOS5S:
+       case INTUOS5:
+       case INTUOS5L:
+               sysfs_remove_group(&wacom->intf->dev.kobj,
+                                  &intuos5_led_attr_group);
+               break;
        }
 }
 
@@ -1040,6 +1090,28 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        if (error)
                goto fail3;
 
+       /*
+        * Intuos5 has no useful data about its touch interface in its
+        * HID descriptor. If this is the touch interface (wMaxPacketSize
+        * of WACOM_PKGLEN_BBTOUCH3), override the table values.
+        */
+       if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
+               if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
+                       features->device_type = BTN_TOOL_FINGER;
+                       features->pktlen = WACOM_PKGLEN_BBTOUCH3;
+
+                       features->x_phy =
+                               (features->x_max * 100) / features->x_resolution;
+                       features->y_phy =
+                               (features->y_max * 100) / features->y_resolution;
+
+                       features->x_max = 4096;
+                       features->y_max = 4096;
+               } else {
+                       features->device_type = BTN_TOOL_PEN;
+               }
+       }
+
        wacom_setup_device_quirks(features);
 
        strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
index cecd35c8f0b3ce46cb82bd51514f7b468ab282cd..d96e186f71dc56d22765ad90b03348db1187656c 100644 (file)
@@ -321,6 +321,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 
        /* Enter report */
        if ((data[1] & 0xfc) == 0xc0) {
+               if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+                       wacom->shared->stylus_in_proximity = true;
+
                /* serial number of the tool */
                wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
                        (data[4] << 20) + (data[5] << 12) +
@@ -406,6 +409,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 
        /* Exit report */
        if ((data[1] & 0xfe) == 0x80) {
+               if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+                       wacom->shared->stylus_in_proximity = false;
+
                /*
                 * Reset all states otherwise we lose the initial states
                 * when in-prox next time
@@ -452,6 +458,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
        if ((data[1] & 0xb8) == 0xa0) {
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
                if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+                    (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
                    features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
                        t = (t << 1) | (data[1] & 1);
                }
@@ -483,7 +490,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        int idx = 0, result;
 
        if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD
-               && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) {
+               && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD
+               && data[0] != WACOM_REPORT_INTUOS5PAD) {
                dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
                 return 0;
        }
@@ -493,7 +501,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                idx = data[1] & 0x01;
 
        /* pad packets. Works as a second tool and is always in prox */
-       if (data[0] == WACOM_REPORT_INTUOSPAD) {
+       if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
                if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                        input_report_key(input, BTN_0, (data[2] & 0x01));
                        input_report_key(input, BTN_1, (data[3] & 0x01));
@@ -569,6 +577,34 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                input_report_key(input, wacom->tool[1], 0);
                                input_report_abs(input, ABS_MISC, 0);
                        }
+               } else if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
+                       int i;
+
+                       /* Touch ring mode switch has no capacitive sensor */
+                       input_report_key(input, BTN_0, (data[3] & 0x01));
+
+                       /*
+                        * ExpressKeys on Intuos5 have a capacitive sensor in
+                        * addition to the mechanical switch. Switch data is
+                        * stored in data[4], capacitive data in data[5].
+                        */
+                       for (i = 0; i < 8; i++)
+                               input_report_key(input, BTN_1 + i, data[4] & (1 << i));
+
+                       if (data[2] & 0x80) {
+                               input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
+                       } else {
+                               /* Out of proximity, clear wheel value. */
+                               input_report_abs(input, ABS_WHEEL, 0);
+                       }
+
+                       if (data[2] | (data[3] & 0x01) | data[4]) {
+                               input_report_key(input, wacom->tool[1], 1);
+                               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+                       } else {
+                               input_report_key(input, wacom->tool[1], 0);
+                               input_report_abs(input, ABS_MISC, 0);
+                       }
                } else {
                        if (features->type == WACOM_21UX2) {
                                input_report_key(input, BTN_0, (data[5] & 0x01));
@@ -632,7 +668,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
            (features->type == INTUOS3 ||
             features->type == INTUOS3S ||
             features->type == INTUOS4 ||
-            features->type == INTUOS4S)) {
+            features->type == INTUOS4S ||
+            features->type == INTUOS5 ||
+            features->type == INTUOS5S)) {
 
                return 0;
        }
@@ -685,7 +723,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
 
                } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
                        /* I4 mouse */
-                       if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+                       if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+                           (features->type >= INTUOS5S && features->type <= INTUOS5L)) {
                                input_report_key(input, BTN_LEFT,   data[6] & 0x01);
                                input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
                                input_report_key(input, BTN_RIGHT,  data[6] & 0x04);
@@ -712,7 +751,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
                                }
                        }
                } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
-                               features->type == INTUOS4L) &&
+                               features->type == INTUOS4L || features->type == INTUOS5L) &&
                           wacom->tool[idx] == BTN_TOOL_LENS) {
                        /* Lens cursor packets */
                        input_report_key(input, BTN_LEFT,   data[8] & 0x01);
@@ -1114,6 +1153,15 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
                sync = wacom_intuos_irq(wacom_wac);
                break;
 
+       case INTUOS5S:
+       case INTUOS5:
+       case INTUOS5L:
+               if (len == WACOM_PKGLEN_BBTOUCH3)
+                       sync = wacom_bpt3_touch(wacom_wac);
+               else
+                       sync = wacom_intuos_irq(wacom_wac);
+               break;
+
        case TABLETPC:
        case TABLETPC2FG:
                sync = wacom_tpc_irq(wacom_wac, len);
@@ -1188,7 +1236,8 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 
        /* these device have multiple inputs */
        if (features->type == TABLETPC || features->type == TABLETPC2FG ||
-           features->type == BAMBOO_PT || features->type == WIRELESS)
+           features->type == BAMBOO_PT || features->type == WIRELESS ||
+           (features->type >= INTUOS5S && features->type <= INTUOS5L))
                features->quirks |= WACOM_QUIRK_MULTI_INPUT;
 
        /* quirk for bamboo touch with 2 low res touches */
@@ -1355,6 +1404,50 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                wacom_setup_intuos(wacom_wac);
                break;
 
+       case INTUOS5:
+       case INTUOS5L:
+               if (features->device_type == BTN_TOOL_PEN) {
+                       __set_bit(BTN_7, input_dev->keybit);
+                       __set_bit(BTN_8, input_dev->keybit);
+               }
+               /* fall through */
+
+       case INTUOS5S:
+               __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+               if (features->device_type == BTN_TOOL_PEN) {
+                       for (i = 0; i < 7; i++)
+                               __set_bit(BTN_0 + i, input_dev->keybit);
+
+                       input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+                                             features->distance_max,
+                                             0, 0);
+
+                       input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+
+                       wacom_setup_intuos(wacom_wac);
+               } else if (features->device_type == BTN_TOOL_FINGER) {
+                       __clear_bit(ABS_MISC, input_dev->absbit);
+
+                       __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+                       __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+                       __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+                       __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
+
+                       input_mt_init_slots(input_dev, 16);
+
+                       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+                                            0, 255, 0, 0);
+
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+                                            0, features->x_max,
+                                            features->x_fuzz, 0);
+                       input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+                                            0, features->y_max,
+                                            features->y_fuzz, 0);
+               }
+               break;
+
        case INTUOS4:
        case INTUOS4L:
                __set_bit(BTN_7, input_dev->keybit);
@@ -1629,6 +1722,21 @@ static const struct wacom_features wacom_features_0xBB =
 static const struct wacom_features wacom_features_0xBC =
        { "Wacom Intuos4 WL",     WACOM_PKGLEN_INTUOS,    40840, 25400, 2047,
          63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x26 =
+       { "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
+         63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x27 =
+       { "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
+         63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x28 =
+       { "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047,
+         63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x29 =
+       { "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS,  31496, 19685, 2047,
+         63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x2A =
+       { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
+         63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 static const struct wacom_features wacom_features_0xF4 =
        { "Wacom Cintiq 24HD",    WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
          63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
@@ -1801,6 +1909,11 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xBA) },
        { USB_DEVICE_WACOM(0xBB) },
        { USB_DEVICE_WACOM(0xBC) },
+       { USB_DEVICE_WACOM(0x26) },
+       { USB_DEVICE_WACOM(0x27) },
+       { USB_DEVICE_WACOM(0x28) },
+       { USB_DEVICE_WACOM(0x29) },
+       { USB_DEVICE_WACOM(0x2A) },
        { USB_DEVICE_WACOM(0x3F) },
        { USB_DEVICE_WACOM(0xC5) },
        { USB_DEVICE_WACOM(0xC6) },
index ba5a334e54d6b525995965cad49acba64a41e89b..17ba1868f0cd4f732d1747239f818482bc7d9183 100644 (file)
@@ -38,6 +38,7 @@
 #define WACOM_REPORT_INTUOSREAD                5
 #define WACOM_REPORT_INTUOSWRITE       6
 #define WACOM_REPORT_INTUOSPAD         12
+#define WACOM_REPORT_INTUOS5PAD                3
 #define WACOM_REPORT_TPC1FG            6
 #define WACOM_REPORT_TPC2FG            13
 #define WACOM_REPORT_TPCHID            15
@@ -65,6 +66,9 @@ enum {
        INTUOS4S,
        INTUOS4,
        INTUOS4L,
+       INTUOS5S,
+       INTUOS5,
+       INTUOS5L,
        WACOM_24HD,
        WACOM_21UX2,
        CINTIQ,
index 2a2141915aa04939a4a1f9f9f96b0ef9a58072b6..ba7c56567ee7056c202e6c515bf6c5e831529959 100644 (file)
@@ -306,6 +306,18 @@ config TOUCHSCREEN_WACOM_W8001
          To compile this driver as a module, choose M here: the
          module will be called wacom_w8001.
 
+config TOUCHSCREEN_WACOM_I2C
+       tristate "Wacom Tablet support (I2C)"
+       depends on I2C
+       help
+         Say Y here if you want to use the I2C version of the Wacom
+         Pen Tablet.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the module
+         will be called wacom_i2c.
+
 config TOUCHSCREEN_LPC32XX
        tristate "LPC32XX touchscreen controller"
        depends on ARCH_LPC32XX
index 3d5cf8cbf89c48391e6c30d621366c255004a536..7cca7ddb464309ae25e5dfc75fc90189c5336d29 100644 (file)
@@ -59,6 +59,7 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2005)     += tsc2005.o
 obj-$(CONFIG_TOUCHSCREEN_TSC2007)      += tsc2007.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)  += wacom_w8001.o
+obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C)    += wacom_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_WM831X)       += wm831x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)       += wm97xx-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
index 455353908bdfefeca9620377fc1072d1eba5c91d..1809677a6513fd0a9221010d8ce0e2c3f6475060 100644 (file)
@@ -188,19 +188,4 @@ static struct serio_driver dynapro_drv = {
        .disconnect     = dynapro_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init dynapro_init(void)
-{
-       return serio_register_driver(&dynapro_drv);
-}
-
-static void __exit dynapro_exit(void)
-{
-       serio_unregister_driver(&dynapro_drv);
-}
-
-module_init(dynapro_init);
-module_exit(dynapro_exit);
+module_serio_driver(dynapro_drv);
index 486d31ba9c0952b28f95e73baa75a78b53316255..957423d1471db4d873c3312c1df1e427b643514f 100644 (file)
@@ -405,19 +405,4 @@ static struct serio_driver elo_drv = {
        .disconnect     = elo_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init elo_init(void)
-{
-       return serio_register_driver(&elo_drv);
-}
-
-static void __exit elo_exit(void)
-{
-       serio_unregister_driver(&elo_drv);
-}
-
-module_init(elo_init);
-module_exit(elo_exit);
+module_serio_driver(elo_drv);
index 80b21800355f10d255a8e8f06fdad8a3b37270fa..10794ddbdf588503495badb9b26937a913ab4db3 100644 (file)
@@ -175,15 +175,4 @@ static struct serio_driver fujitsu_drv = {
        .disconnect     = fujitsu_disconnect,
 };
 
-static int __init fujitsu_init(void)
-{
-       return serio_register_driver(&fujitsu_drv);
-}
-
-static void __exit fujitsu_exit(void)
-{
-       serio_unregister_driver(&fujitsu_drv);
-}
-
-module_init(fujitsu_init);
-module_exit(fujitsu_exit);
+module_serio_driver(fujitsu_drv);
index a54f90e02ab60b5f8ac2ab914872fcb270a9c914..41c71766bf18d85285c18004fbf494b8cac86112 100644 (file)
@@ -186,19 +186,4 @@ static struct serio_driver gunze_drv = {
        .disconnect     = gunze_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init gunze_init(void)
-{
-       return serio_register_driver(&gunze_drv);
-}
-
-static void __exit gunze_exit(void)
-{
-       serio_unregister_driver(&gunze_drv);
-}
-
-module_init(gunze_init);
-module_exit(gunze_exit);
+module_serio_driver(gunze_drv);
index 6107e563e68141545f356bbdd724ebbd70ebcd7e..b9e8686a6f1c036b7bd6a61f89d352e02122f014 100644 (file)
@@ -476,19 +476,4 @@ static struct serio_driver h3600ts_drv = {
        .disconnect     = h3600ts_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init h3600ts_init(void)
-{
-       return serio_register_driver(&h3600ts_drv);
-}
-
-static void __exit h3600ts_exit(void)
-{
-       serio_unregister_driver(&h3600ts_drv);
-}
-
-module_init(h3600ts_init);
-module_exit(h3600ts_exit);
+module_serio_driver(h3600ts_drv);
index 2da6cc31bb2187f0b62770bd09aa6c0923c36687..0cc47ea98acff584cf04bcf93d8305b638fe1714 100644 (file)
@@ -187,19 +187,4 @@ static struct serio_driver hampshire_drv = {
        .disconnect     = hampshire_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init hampshire_init(void)
-{
-       return serio_register_driver(&hampshire_drv);
-}
-
-static void __exit hampshire_exit(void)
-{
-       serio_unregister_driver(&hampshire_drv);
-}
-
-module_init(hampshire_init);
-module_exit(hampshire_exit);
+module_serio_driver(hampshire_drv);
index 192ade0a0fb9cf7424a79069a3def4f103b31e08..a29c99c32245eda591bdcf457d853c78566af3ca 100644 (file)
@@ -189,19 +189,4 @@ static struct serio_driver inexio_drv = {
        .disconnect     = inexio_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init inexio_init(void)
-{
-       return serio_register_driver(&inexio_drv);
-}
-
-static void __exit inexio_exit(void)
-{
-       serio_unregister_driver(&inexio_drv);
-}
-
-module_init(inexio_init);
-module_exit(inexio_exit);
+module_serio_driver(inexio_drv);
index afcd0691ec678a03de9a5f36578284574f05424a..e8fccbc452dbc66c0f5007ebc5bcdc7d2c37a726 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 /*
  * Touchscreen controller register offsets
@@ -383,6 +384,14 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
 #define LPC32XX_TS_PM_OPS NULL
 #endif
 
+#ifdef CONFIG_OF
+static struct of_device_id lpc32xx_tsc_of_match[] = {
+       { .compatible = "nxp,lpc32xx-tsc", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
+#endif
+
 static struct platform_driver lpc32xx_ts_driver = {
        .probe          = lpc32xx_ts_probe,
        .remove         = __devexit_p(lpc32xx_ts_remove),
@@ -390,6 +399,7 @@ static struct platform_driver lpc32xx_ts_driver = {
                .name   = MOD_NAME,
                .owner  = THIS_MODULE,
                .pm     = LPC32XX_TS_PM_OPS,
+               .of_match_table = of_match_ptr(lpc32xx_tsc_of_match),
        },
 };
 module_platform_driver(lpc32xx_ts_driver);
index 9077228418b7028242caa03cc99292ee8f2c62cd..eb66b7c37c2f9408e3a29b7fd7b5254bf7dcfb08 100644 (file)
@@ -202,19 +202,4 @@ static struct serio_driver mtouch_drv = {
        .disconnect     = mtouch_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init mtouch_init(void)
-{
-       return serio_register_driver(&mtouch_drv);
-}
-
-static void __exit mtouch_exit(void)
-{
-       serio_unregister_driver(&mtouch_drv);
-}
-
-module_init(mtouch_init);
-module_exit(mtouch_exit);
+module_serio_driver(mtouch_drv);
index 4c012fb2b01eb091f764abea0ef992e8052a53d3..4ccde45b9da2bfac620f81c62aa9c6b95d5f873c 100644 (file)
@@ -317,19 +317,4 @@ static struct serio_driver pm_drv = {
        .disconnect     = pm_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init pm_init(void)
-{
-       return serio_register_driver(&pm_drv);
-}
-
-static void __exit pm_exit(void)
-{
-       serio_unregister_driver(&pm_drv);
-}
-
-module_init(pm_init);
-module_exit(pm_exit);
+module_serio_driver(pm_drv);
index cbbf71b22696f671a1774d58f9da0a0997a4c127..6cb68a1981bf7412624d492cb431945fb5060755 100644 (file)
@@ -218,7 +218,7 @@ static int __devexit st1232_ts_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int st1232_ts_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -243,18 +243,25 @@ static int st1232_ts_resume(struct device *dev)
        return 0;
 }
 
-static const struct dev_pm_ops st1232_ts_pm_ops = {
-       .suspend        = st1232_ts_suspend,
-       .resume         = st1232_ts_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
+                        st1232_ts_suspend, st1232_ts_resume);
+
 static const struct i2c_device_id st1232_ts_id[] = {
        { ST1232_TS_NAME, 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = {
+       { .compatible = "sitronix,st1232", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
+#endif
+
 static struct i2c_driver st1232_ts_driver = {
        .probe          = st1232_ts_probe,
        .remove         = __devexit_p(st1232_ts_remove),
@@ -262,9 +269,8 @@ static struct i2c_driver st1232_ts_driver = {
        .driver = {
                .name   = ST1232_TS_NAME,
                .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
+               .of_match_table = of_match_ptr(st1232_ts_dt_ids),
                .pm     = &st1232_ts_pm_ops,
-#endif
        },
 };
 
index d1297ba19daf622e8fa791962d49088653ac0910..5f29e5b8e1c1995bbede2bb5df00f7cc609a59d1 100644 (file)
@@ -216,19 +216,4 @@ static struct serio_driver touchit213_drv = {
        .disconnect     = touchit213_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init touchit213_init(void)
-{
-       return serio_register_driver(&touchit213_drv);
-}
-
-static void __exit touchit213_exit(void)
-{
-       serio_unregister_driver(&touchit213_drv);
-}
-
-module_init(touchit213_init);
-module_exit(touchit213_exit);
+module_serio_driver(touchit213_drv);
index 3a5c142c2a78a6fd6b0e55cbf79c5c57bf236999..8a2887daf194ed26c204ff5cf216f4261ec05520 100644 (file)
@@ -176,19 +176,4 @@ static struct serio_driver tr_drv = {
        .disconnect     = tr_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init tr_init(void)
-{
-       return serio_register_driver(&tr_drv);
-}
-
-static void __exit tr_exit(void)
-{
-       serio_unregister_driver(&tr_drv);
-}
-
-module_init(tr_init);
-module_exit(tr_exit);
+module_serio_driver(tr_drv);
index 763a656a59f8270929f2366f710147ef2339e43e..588cdcb839ddef36541f5f685972a919417628c1 100644 (file)
@@ -183,19 +183,4 @@ static struct serio_driver tw_drv = {
        .disconnect     = tw_disconnect,
 };
 
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init tw_init(void)
-{
-       return serio_register_driver(&tw_drv);
-}
-
-static void __exit tw_exit(void)
-{
-       serio_unregister_driver(&tw_drv);
-}
-
-module_init(tw_init);
-module_exit(tw_exit);
+module_serio_driver(tw_drv);
index 29d5ed4dd31c8b3b975654cc4c39d97f2308a688..63209aaa55f01f1baf65a8a1632c8c2ce4056870 100644 (file)
@@ -167,17 +167,7 @@ static struct serio_driver tsc_drv = {
        .disconnect     = tsc_disconnect,
 };
 
-static int __init tsc_ser_init(void)
-{
-       return serio_register_driver(&tsc_drv);
-}
-module_init(tsc_ser_init);
-
-static void __exit tsc_exit(void)
-{
-       serio_unregister_driver(&tsc_drv);
-}
-module_exit(tsc_exit);
+module_serio_driver(tsc_drv);
 
 MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
new file mode 100644 (file)
index 0000000..3557257
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Wacom Penabled Driver for I2C
+ *
+ * Copyright (c) 2011 Tatsunosuke Tobita, Wacom.
+ * <tobita.tatsunosuke@wacom.co.jp>
+ *
+ * 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 of 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <asm/unaligned.h>
+
+#define WACOM_CMD_QUERY0       0x04
+#define WACOM_CMD_QUERY1       0x00
+#define WACOM_CMD_QUERY2       0x33
+#define WACOM_CMD_QUERY3       0x02
+#define WACOM_CMD_THROW0       0x05
+#define WACOM_CMD_THROW1       0x00
+#define WACOM_QUERY_SIZE       19
+#define WACOM_RETRY_CNT                100
+
+struct wacom_features {
+       int x_max;
+       int y_max;
+       int pressure_max;
+       char fw_version;
+};
+
+struct wacom_i2c {
+       struct i2c_client *client;
+       struct input_dev *input;
+       u8 data[WACOM_QUERY_SIZE];
+};
+
+static int wacom_query_device(struct i2c_client *client,
+                             struct wacom_features *features)
+{
+       int ret;
+       u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1,
+                       WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 };
+       u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 };
+       u8 data[WACOM_QUERY_SIZE];
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = sizeof(cmd1),
+                       .buf = cmd1,
+               },
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = sizeof(cmd2),
+                       .buf = cmd2,
+               },
+               {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = sizeof(data),
+                       .buf = data,
+               },
+       };
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret < 0)
+               return ret;
+       if (ret != ARRAY_SIZE(msgs))
+               return -EIO;
+
+       features->x_max = get_unaligned_le16(&data[3]);
+       features->y_max = get_unaligned_le16(&data[5]);
+       features->pressure_max = get_unaligned_le16(&data[11]);
+       features->fw_version = get_unaligned_le16(&data[13]);
+
+       dev_dbg(&client->dev,
+               "x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
+               features->x_max, features->y_max,
+               features->pressure_max, features->fw_version);
+
+       return 0;
+}
+
+static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
+{
+       struct wacom_i2c *wac_i2c = dev_id;
+       struct input_dev *input = wac_i2c->input;
+       u8 *data = wac_i2c->data;
+       unsigned int x, y, pressure;
+       unsigned char tsw, f1, f2, ers;
+       int error;
+
+       error = i2c_master_recv(wac_i2c->client,
+                               wac_i2c->data, sizeof(wac_i2c->data));
+       if (error < 0)
+               goto out;
+
+       tsw = data[3] & 0x01;
+       ers = data[3] & 0x04;
+       f1 = data[3] & 0x02;
+       f2 = data[3] & 0x10;
+       x = le16_to_cpup((__le16 *)&data[4]);
+       y = le16_to_cpup((__le16 *)&data[6]);
+       pressure = le16_to_cpup((__le16 *)&data[8]);
+
+       input_report_key(input, BTN_TOUCH, tsw || ers);
+       input_report_key(input, BTN_TOOL_PEN, tsw);
+       input_report_key(input, BTN_TOOL_RUBBER, ers);
+       input_report_key(input, BTN_STYLUS, f1);
+       input_report_key(input, BTN_STYLUS2, f2);
+       input_report_abs(input, ABS_X, x);
+       input_report_abs(input, ABS_Y, y);
+       input_report_abs(input, ABS_PRESSURE, pressure);
+       input_sync(input);
+
+out:
+       return IRQ_HANDLED;
+}
+
+static int wacom_i2c_open(struct input_dev *dev)
+{
+       struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
+       struct i2c_client *client = wac_i2c->client;
+
+       enable_irq(client->irq);
+
+       return 0;
+}
+
+static void wacom_i2c_close(struct input_dev *dev)
+{
+       struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
+       struct i2c_client *client = wac_i2c->client;
+
+       disable_irq(client->irq);
+}
+
+static int __devinit wacom_i2c_probe(struct i2c_client *client,
+                                    const struct i2c_device_id *id)
+{
+       struct wacom_i2c *wac_i2c;
+       struct input_dev *input;
+       struct wacom_features features;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "i2c_check_functionality error\n");
+               return -EIO;
+       }
+
+       error = wacom_query_device(client, &features);
+       if (error)
+               return error;
+
+       wac_i2c = kzalloc(sizeof(*wac_i2c), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!wac_i2c || !input) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       wac_i2c->client = client;
+       wac_i2c->input = input;
+
+       input->name = "Wacom I2C Digitizer";
+       input->id.bustype = BUS_I2C;
+       input->id.vendor = 0x56a;
+       input->id.version = features.fw_version;
+       input->dev.parent = &client->dev;
+       input->open = wacom_i2c_open;
+       input->close = wacom_i2c_close;
+
+       input->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+
+       __set_bit(BTN_TOOL_PEN, input->keybit);
+       __set_bit(BTN_TOOL_RUBBER, input->keybit);
+       __set_bit(BTN_STYLUS, input->keybit);
+       __set_bit(BTN_STYLUS2, input->keybit);
+       __set_bit(BTN_TOUCH, input->keybit);
+
+       input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0);
+       input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0);
+       input_set_abs_params(input, ABS_PRESSURE,
+                            0, features.pressure_max, 0, 0);
+
+       input_set_drvdata(input, wac_i2c);
+
+       error = request_threaded_irq(client->irq, NULL, wacom_i2c_irq,
+                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                    "wacom_i2c", wac_i2c);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to enable IRQ, error: %d\n", error);
+               goto err_free_mem;
+       }
+
+       /* Disable the IRQ, we'll enable it in wac_i2c_open() */
+       disable_irq(client->irq);
+
+       error = input_register_device(wac_i2c->input);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to register input device, error: %d\n", error);
+               goto err_free_irq;
+       }
+
+       i2c_set_clientdata(client, wac_i2c);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, wac_i2c);
+err_free_mem:
+       input_free_device(input);
+       kfree(wac_i2c);
+
+       return error;
+}
+
+static int __devexit wacom_i2c_remove(struct i2c_client *client)
+{
+       struct wacom_i2c *wac_i2c = i2c_get_clientdata(client);
+
+       free_irq(client->irq, wac_i2c);
+       input_unregister_device(wac_i2c->input);
+       kfree(wac_i2c);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wacom_i2c_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       disable_irq(client->irq);
+
+       return 0;
+}
+
+static int wacom_i2c_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       enable_irq(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
+
+static const struct i2c_device_id wacom_i2c_id[] = {
+       { "WAC_I2C_EMR", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
+
+static struct i2c_driver wacom_i2c_driver = {
+       .driver = {
+               .name   = "wacom_i2c",
+               .owner  = THIS_MODULE,
+               .pm     = &wacom_i2c_pm,
+       },
+
+       .probe          = wacom_i2c_probe,
+       .remove         = __devexit_p(wacom_i2c_remove),
+       .id_table       = wacom_i2c_id,
+};
+module_i2c_driver(wacom_i2c_driver);
+
+MODULE_AUTHOR("Tatsunosuke Tobita <tobita.tatsunosuke@wacom.co.jp>");
+MODULE_DESCRIPTION("WACOM EMR I2C Driver");
+MODULE_LICENSE("GPL");
index 1569a3934ab26dc56d2afc9ffad5d59fb1c7e28a..8f9ad2f893b825a0c2d3afc5a9777ec098003308 100644 (file)
@@ -594,15 +594,4 @@ static struct serio_driver w8001_drv = {
        .disconnect     = w8001_disconnect,
 };
 
-static int __init w8001_init(void)
-{
-       return serio_register_driver(&w8001_drv);
-}
-
-static void __exit w8001_exit(void)
-{
-       serio_unregister_driver(&w8001_drv);
-}
-
-module_init(w8001_init);
-module_exit(w8001_exit);
+module_serio_driver(w8001_drv);
index b456b08d70ed4bd68aa77ef511b8cc9b05851d97..b986be513406f51fb8abc66d9a26fbe324e30470 100644 (file)
@@ -153,6 +153,19 @@ int __must_check __gameport_register_driver(struct gameport_driver *drv,
 
 void gameport_unregister_driver(struct gameport_driver *drv);
 
+/**
+ * module_gameport_driver() - Helper macro for registering a gameport driver
+ * @__gameport_driver: gameport_driver struct
+ *
+ * Helper macro for gameport drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module may
+ * only use this macro once, and calling it replaces module_init() and
+ * module_exit().
+ */
+#define module_gameport_driver(__gameport_driver) \
+       module_driver(__gameport_driver, gameport_register_driver, \
+                      gameport_unregister_driver)
+
 #endif /* __KERNEL__ */
 
 #define GAMEPORT_MODE_DISABLED         0
diff --git a/include/linux/input/lm8333.h b/include/linux/input/lm8333.h
new file mode 100644 (file)
index 0000000..79f918c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * public include for LM8333 keypad driver - same license as driver
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
+ */
+
+#ifndef _LM8333_H
+#define _LM8333_H
+
+struct lm8333;
+
+struct lm8333_platform_data {
+       /* Keymap data */
+       const struct matrix_keymap_data *matrix_data;
+       /* Active timeout before enter HALT mode in microseconds */
+       unsigned active_time;
+       /* Debounce interval in microseconds */
+       unsigned debounce_time;
+};
+
+extern int lm8333_read8(struct lm8333 *lm8333, u8 cmd);
+extern int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val);
+extern int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf);
+
+#endif /* _LM8333_H */
index ca82861b0e461d6798e6a05a977352dca24335e5..6d6cfd3e94a348cb578f73c3b019b6121ee8aca1 100644 (file)
@@ -96,6 +96,19 @@ int __must_check __serio_register_driver(struct serio_driver *drv,
 
 void serio_unregister_driver(struct serio_driver *drv);
 
+/**
+ * module_serio_driver() - Helper macro for registering a serio driver
+ * @__serio_driver: serio_driver struct
+ *
+ * Helper macro for serio drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module
+ * may only use this macro once, and calling it replaces module_init()
+ * and module_exit().
+ */
+#define module_serio_driver(__serio_driver) \
+       module_driver(__serio_driver, serio_register_driver, \
+                      serio_unregister_driver)
+
 static inline int serio_write(struct serio *serio, unsigned char data)
 {
        if (serio->write)