Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Sep 2009 22:39:36 +0000 (15:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Sep 2009 22:39:36 +0000 (15:39 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: add driver for Atmel AT42QT2160 Sensor Chip
  Input: max7359 - use threaded IRQs
  Input: add driver for Maxim MAX7359 key switch controller
  Input: add driver for ADP5588 QWERTY I2C Keypad
  Input: add touchscreen driver for MELFAS MCS-5000 controller
  Input: add driver for OpenCores Keyboard Controller
  Input: dm355evm_keys - remove dm355evm_keys_hardirq
  Input: synaptics_i2c - switch to using __cancel_delayed_work()
  Input: ad7879 - add support for AD7889
  Input: atkbd - rely on input core to restore state on resume
  Input: add generic suspend and resume for input devices
  Input: libps2 - additional locking for i8042 ports

24 files changed:
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5588-keys.c [new file with mode: 0644]
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/max7359_keypad.c [new file with mode: 0644]
drivers/input/keyboard/opencores-kbd.c [new file with mode: 0644]
drivers/input/keyboard/qt2160.c [new file with mode: 0644]
drivers/input/misc/dm355evm_keys.c
drivers/input/mouse/sentelic.c
drivers/input/mouse/synaptics_i2c.c
drivers/input/serio/i8042.c
drivers/input/serio/libps2.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/mcs5000_ts.c [new file with mode: 0644]
drivers/leds/leds-clevo-mail.c
drivers/platform/x86/acer-wmi.c
include/linux/i2c/adp5588.h [new file with mode: 0644]
include/linux/i2c/mcs5000_ts.h [new file with mode: 0644]
include/linux/i8042.h
include/linux/input.h
include/linux/libps2.h

index 556539d617a43295a8e4db43a3df6230da19aac5..e828aab7daceada9eb8858fb19fa3fc755baa7ea 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/types.h>
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/random.h>
@@ -514,7 +515,7 @@ static void input_disconnect_device(struct input_dev *dev)
         * that there are no threads in the middle of input_open_device()
         */
        mutex_lock(&dev->mutex);
-       dev->going_away = 1;
+       dev->going_away = true;
        mutex_unlock(&dev->mutex);
 
        spin_lock_irq(&dev->event_lock);
@@ -1259,10 +1260,71 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
        return 0;
 }
 
+#define INPUT_DO_TOGGLE(dev, type, bits, on)                   \
+       do {                                                    \
+               int i;                                          \
+               if (!test_bit(EV_##type, dev->evbit))           \
+                       break;                                  \
+               for (i = 0; i < type##_MAX; i++) {              \
+                       if (!test_bit(i, dev->bits##bit) ||     \
+                           !test_bit(i, dev->bits))            \
+                               continue;                       \
+                       dev->event(dev, EV_##type, i, on);      \
+               }                                               \
+       } while (0)
+
+static void input_dev_reset(struct input_dev *dev, bool activate)
+{
+       if (!dev->event)
+               return;
+
+       INPUT_DO_TOGGLE(dev, LED, led, activate);
+       INPUT_DO_TOGGLE(dev, SND, snd, activate);
+
+       if (activate && test_bit(EV_REP, dev->evbit)) {
+               dev->event(dev, EV_REP, REP_PERIOD, dev->rep[REP_PERIOD]);
+               dev->event(dev, EV_REP, REP_DELAY, dev->rep[REP_DELAY]);
+       }
+}
+
+#ifdef CONFIG_PM
+static int input_dev_suspend(struct device *dev)
+{
+       struct input_dev *input_dev = to_input_dev(dev);
+
+       mutex_lock(&input_dev->mutex);
+       input_dev_reset(input_dev, false);
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static int input_dev_resume(struct device *dev)
+{
+       struct input_dev *input_dev = to_input_dev(dev);
+
+       mutex_lock(&input_dev->mutex);
+       input_dev_reset(input_dev, true);
+       mutex_unlock(&input_dev->mutex);
+
+       return 0;
+}
+
+static const struct dev_pm_ops input_dev_pm_ops = {
+       .suspend        = input_dev_suspend,
+       .resume         = input_dev_resume,
+       .poweroff       = input_dev_suspend,
+       .restore        = input_dev_resume,
+};
+#endif /* CONFIG_PM */
+
 static struct device_type input_dev_type = {
        .groups         = input_dev_attr_groups,
        .release        = input_dev_release,
        .uevent         = input_dev_uevent,
+#ifdef CONFIG_PM
+       .pm             = &input_dev_pm_ops,
+#endif
 };
 
 static char *input_devnode(struct device *dev, mode_t *mode)
index 3525c19be4286e14f71568656142ff7215fc8dbc..ee98b1bc5d890c28de0f50aea1db487535fedee8 100644 (file)
@@ -24,6 +24,16 @@ config KEYBOARD_AAED2000
          To compile this driver as a module, choose M here: the
          module will be called aaed2000_kbd.
 
+config KEYBOARD_ADP5588
+       tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
+       depends on I2C
+       help
+         Say Y here if you want to use a ADP5588 attached to your
+         system I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adp5588-keys.
+
 config KEYBOARD_AMIGA
        tristate "Amiga keyboard"
        depends on AMIGA
@@ -104,6 +114,16 @@ config KEYBOARD_ATKBD_RDI_KEYCODES
          right-hand column will be interpreted as the key shown in the
          left-hand column.
 
+config QT2160
+       tristate "Atmel AT42QT2160 Touch Sensor Chip"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for Atmel AT42QT2160 Touch
+         Sensor chip as a keyboard input.
+
+         This driver can also be built as a module. If so, the module
+         will be called qt2160.
+
 config KEYBOARD_BFIN
        tristate "Blackfin BF54x keypad support"
        depends on (BF54x && !BF544)
@@ -251,6 +271,17 @@ config KEYBOARD_MAPLE
          To compile this driver as a module, choose M here: the
          module will be called maple_keyb.
 
+config KEYBOARD_MAX7359
+       tristate "Maxim MAX7359 Key Switch Controller"
+       depends on I2C
+       help
+         If you say yes here you get support for the Maxim MAX7359 Key
+         Switch Controller chip. This providers microprocessors with
+         management of up to 64 key switches
+
+         To compile this driver as a module, choose M here: the
+         module will be called max7359_keypad.
+
 config KEYBOARD_NEWTON
        tristate "Newton keyboard"
        select SERIO
@@ -260,6 +291,15 @@ config KEYBOARD_NEWTON
          To compile this driver as a module, choose M here: the
          module will be called newtonkbd.
 
+config KEYBOARD_OPENCORES
+       tristate "OpenCores Keyboard Controller"
+       help
+         Say Y here if you want to use the OpenCores Keyboard Controller
+         http://www.opencores.org/project,keyboardcontroller
+
+         To compile this driver as a module, choose M here; the
+         module will be called opencores-kbd.
+
 config KEYBOARD_PXA27x
        tristate "PXA27x/PXA3xx keypad support"
        depends on PXA27x || PXA3xx
index 8a7a22b302666618c4472aa11b8d91b395e39bd6..babad5e58b77d323f357618da87accd4f97dcce9 100644 (file)
@@ -5,6 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_ADP5588)         += adp5588-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)           += amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)           += atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)           += atkbd.o
@@ -21,10 +22,13 @@ obj-$(CONFIG_KEYBOARD_LM8323)               += lm8323.o
 obj-$(CONFIG_KEYBOARD_LOCOMO)          += locomokbd.o
 obj-$(CONFIG_KEYBOARD_MAPLE)           += maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)          += matrix_keypad.o
+obj-$(CONFIG_KEYBOARD_MAX7359)         += max7359_keypad.o
 obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_OPENCORES)       += opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)   += pxa930_rotary.o
+obj-$(CONFIG_KEYBOARD_QT2160)          += qt2160.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)                += sh_keysc.o
 obj-$(CONFIG_KEYBOARD_SPITZ)           += spitzkbd.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
new file mode 100644 (file)
index 0000000..d48c808
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * File: drivers/input/keyboard/adp5588_keys.c
+ * Description:  keypad driver for ADP5588 I2C QWERTY Keypad and IO Expander
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+
+#include <linux/i2c/adp5588.h>
+
+ /* Configuration Register1 */
+#define AUTO_INC       (1 << 7)
+#define GPIEM_CFG      (1 << 6)
+#define OVR_FLOW_M     (1 << 5)
+#define INT_CFG                (1 << 4)
+#define OVR_FLOW_IEN   (1 << 3)
+#define K_LCK_IM       (1 << 2)
+#define GPI_IEN                (1 << 1)
+#define KE_IEN         (1 << 0)
+
+/* Interrupt Status Register */
+#define CMP2_INT       (1 << 5)
+#define CMP1_INT       (1 << 4)
+#define OVR_FLOW_INT   (1 << 3)
+#define K_LCK_INT      (1 << 2)
+#define GPI_INT                (1 << 1)
+#define KE_INT         (1 << 0)
+
+/* Key Lock and Event Counter Register */
+#define K_LCK_EN       (1 << 6)
+#define LCK21          0x30
+#define KEC            0xF
+
+/* Key Event Register xy */
+#define KEY_EV_PRESSED         (1 << 7)
+#define KEY_EV_MASK            (0x7F)
+
+#define KP_SEL(x)              (0xFFFF >> (16 - x))    /* 2^x-1 */
+
+#define KEYP_MAX_EVENT         10
+
+/*
+ * Early pre 4.0 Silicon required to delay readout by at least 25ms,
+ * since the Event Counter Register updated 25ms after the interrupt
+ * asserted.
+ */
+#define WA_DELAYED_READOUT_REVID(rev)          ((rev) < 4)
+
+struct adp5588_kpad {
+       struct i2c_client *client;
+       struct input_dev *input;
+       struct delayed_work work;
+       unsigned long delay;
+       unsigned short keycode[ADP5588_KEYMAPSIZE];
+};
+
+static int adp5588_read(struct i2c_client *client, u8 reg)
+{
+       int ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               dev_err(&client->dev, "Read Error\n");
+
+       return ret;
+}
+
+static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static void adp5588_work(struct work_struct *work)
+{
+       struct adp5588_kpad *kpad = container_of(work,
+                                               struct adp5588_kpad, work.work);
+       struct i2c_client *client = kpad->client;
+       int i, key, status, ev_cnt;
+
+       status = adp5588_read(client, INT_STAT);
+
+       if (status & OVR_FLOW_INT)      /* Unlikely and should never happen */
+               dev_err(&client->dev, "Event Overflow Error\n");
+
+       if (status & KE_INT) {
+               ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
+               if (ev_cnt) {
+                       for (i = 0; i < ev_cnt; i++) {
+                               key = adp5588_read(client, Key_EVENTA + i);
+                               input_report_key(kpad->input,
+                                       kpad->keycode[(key & KEY_EV_MASK) - 1],
+                                       key & KEY_EV_PRESSED);
+                       }
+                       input_sync(kpad->input);
+               }
+       }
+       adp5588_write(client, INT_STAT, status); /* Status is W1C */
+}
+
+static irqreturn_t adp5588_irq(int irq, void *handle)
+{
+       struct adp5588_kpad *kpad = handle;
+
+       /*
+        * use keventd context to read the event fifo registers
+        * Schedule readout at least 25ms after notification for
+        * REVID < 4
+        */
+
+       schedule_delayed_work(&kpad->work, kpad->delay);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit adp5588_setup(struct i2c_client *client)
+{
+       struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+       int i, ret;
+
+       ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
+       ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
+       ret |= adp5588_write(client, KP_GPIO3, KP_SEL(pdata->cols) >> 8);
+
+       if (pdata->en_keylock) {
+               ret |= adp5588_write(client, UNLOCK1, pdata->unlock_key1);
+               ret |= adp5588_write(client, UNLOCK2, pdata->unlock_key2);
+               ret |= adp5588_write(client, KEY_LCK_EC_STAT, K_LCK_EN);
+       }
+
+       for (i = 0; i < KEYP_MAX_EVENT; i++)
+               ret |= adp5588_read(client, Key_EVENTA);
+
+       ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
+                                       OVR_FLOW_INT | K_LCK_INT |
+                                       GPI_INT | KE_INT); /* Status is W1C */
+
+       ret |= adp5588_write(client, CFG, INT_CFG | OVR_FLOW_IEN | KE_IEN);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "Write Error\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devinit adp5588_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct adp5588_kpad *kpad;
+       struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+       struct input_dev *input;
+       unsigned int revid;
+       int ret, i;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+               return -EIO;
+       }
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+               dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
+               return -EINVAL;
+       }
+
+       if (pdata->keymapsize != ADP5588_KEYMAPSIZE) {
+               dev_err(&client->dev, "invalid keymapsize\n");
+               return -EINVAL;
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "no IRQ?\n");
+               return -EINVAL;
+       }
+
+       kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!kpad || !input) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       kpad->client = client;
+       kpad->input = input;
+       INIT_DELAYED_WORK(&kpad->work, adp5588_work);
+
+       ret = adp5588_read(client, DEV_ID);
+       if (ret < 0) {
+               error = ret;
+               goto err_free_mem;
+       }
+
+       revid = (u8) ret & ADP5588_DEVICE_ID_MASK;
+       if (WA_DELAYED_READOUT_REVID(revid))
+               kpad->delay = msecs_to_jiffies(30);
+
+       input->name = client->name;
+       input->phys = "adp5588-keys/input0";
+       input->dev.parent = &client->dev;
+
+       input_set_drvdata(input, kpad);
+
+       input->id.bustype = BUS_I2C;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = revid;
+
+       input->keycodesize = sizeof(kpad->keycode[0]);
+       input->keycodemax = pdata->keymapsize;
+       input->keycode = kpad->keycode;
+
+       memcpy(kpad->keycode, pdata->keymap,
+               pdata->keymapsize * input->keycodesize);
+
+       /* setup input device */
+       __set_bit(EV_KEY, input->evbit);
+
+       if (pdata->repeat)
+               __set_bit(EV_REP, input->evbit);
+
+       for (i = 0; i < input->keycodemax; i++)
+               __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
+       __clear_bit(KEY_RESERVED, input->keybit);
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&client->dev, "unable to register input device\n");
+               goto err_free_mem;
+       }
+
+       error = request_irq(client->irq, adp5588_irq,
+                           IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+                           client->dev.driver->name, kpad);
+       if (error) {
+               dev_err(&client->dev, "irq %d busy?\n", client->irq);
+               goto err_unreg_dev;
+       }
+
+       error = adp5588_setup(client);
+       if (error)
+               goto err_free_irq;
+
+       device_init_wakeup(&client->dev, 1);
+       i2c_set_clientdata(client, kpad);
+
+       dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
+       return 0;
+
+ err_free_irq:
+       free_irq(client->irq, kpad);
+ err_unreg_dev:
+       input_unregister_device(input);
+       input = NULL;
+ err_free_mem:
+       input_free_device(input);
+       kfree(kpad);
+
+       return error;
+}
+
+static int __devexit adp5588_remove(struct i2c_client *client)
+{
+       struct adp5588_kpad *kpad = i2c_get_clientdata(client);
+
+       adp5588_write(client, CFG, 0);
+       free_irq(client->irq, kpad);
+       cancel_delayed_work_sync(&kpad->work);
+       input_unregister_device(kpad->input);
+       i2c_set_clientdata(client, NULL);
+       kfree(kpad);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int adp5588_suspend(struct device *dev)
+{
+       struct adp5588_kpad *kpad = dev_get_drvdata(dev);
+       struct i2c_client *client = kpad->client;
+
+       disable_irq(client->irq);
+       cancel_delayed_work_sync(&kpad->work);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int adp5588_resume(struct device *dev)
+{
+       struct adp5588_kpad *kpad = dev_get_drvdata(dev);
+       struct i2c_client *client = kpad->client;
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+
+       enable_irq(client->irq);
+
+       return 0;
+}
+
+static struct dev_pm_ops adp5588_dev_pm_ops = {
+       .suspend = adp5588_suspend,
+       .resume  = adp5588_resume,
+};
+#endif
+
+static const struct i2c_device_id adp5588_id[] = {
+       { KBUILD_MODNAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adp5588_id);
+
+static struct i2c_driver adp5588_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+#ifdef CONFIG_PM
+               .pm   = &adp5588_dev_pm_ops,
+#endif
+       },
+       .probe    = adp5588_probe,
+       .remove   = __devexit_p(adp5588_remove),
+       .id_table = adp5588_id,
+};
+
+static int __init adp5588_init(void)
+{
+       return i2c_add_driver(&adp5588_driver);
+}
+module_init(adp5588_init);
+
+static void __exit adp5588_exit(void)
+{
+       i2c_del_driver(&adp5588_driver);
+}
+module_exit(adp5588_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP5588 Keypad driver");
+MODULE_ALIAS("platform:adp5588-keys");
index adb09e2ba3944d8b0649186a14a8221673811429..4709e15af6070522dcf03516acb058bd024b07d7 100644 (file)
@@ -773,23 +773,6 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
 static int atkbd_activate(struct atkbd *atkbd)
 {
        struct ps2dev *ps2dev = &atkbd->ps2dev;
-       unsigned char param[1];
-
-/*
- * Set the LEDs to a defined state.
- */
-
-       param[0] = 0;
-       if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
-               return -1;
-
-/*
- * Set autorepeat to fastest possible.
- */
-
-       param[0] = 0;
-       if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
-               return -1;
 
 /*
  * Enable the keyboard to receive keystrokes.
@@ -1158,14 +1141,6 @@ static int atkbd_reconnect(struct serio *serio)
                        return -1;
 
                atkbd_activate(atkbd);
-
-/*
- * Restore repeat rate and LEDs (that were reset by atkbd_activate)
- * to pre-resume state
- */
-               if (!atkbd->softrepeat)
-                       atkbd_set_repeat_rate(atkbd);
-               atkbd_set_leds(atkbd);
        }
 
        atkbd_enable(atkbd);
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c
new file mode 100644 (file)
index 0000000..3b5b948
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * max7359_keypad.c - MAX7359 Key Switch Controller Driver
+ *
+ * Copyright (C) 2009 Samsung Electronics
+ * Kim Kyuwon <q1.kim@samsung.com>
+ *
+ * Based on pxa27x_keypad.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.
+ *
+ * Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/5456
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+
+#define MAX7359_MAX_KEY_ROWS   8
+#define MAX7359_MAX_KEY_COLS   8
+#define MAX7359_MAX_KEY_NUM    (MAX7359_MAX_KEY_ROWS * MAX7359_MAX_KEY_COLS)
+#define MAX7359_ROW_SHIFT      3
+
+/*
+ * MAX7359 registers
+ */
+#define MAX7359_REG_KEYFIFO    0x00
+#define MAX7359_REG_CONFIG     0x01
+#define MAX7359_REG_DEBOUNCE   0x02
+#define MAX7359_REG_INTERRUPT  0x03
+#define MAX7359_REG_PORTS      0x04
+#define MAX7359_REG_KEYREP     0x05
+#define MAX7359_REG_SLEEP      0x06
+
+/*
+ * Configuration register bits
+ */
+#define MAX7359_CFG_SLEEP      (1 << 7)
+#define MAX7359_CFG_INTERRUPT  (1 << 5)
+#define MAX7359_CFG_KEY_RELEASE        (1 << 3)
+#define MAX7359_CFG_WAKEUP     (1 << 1)
+#define MAX7359_CFG_TIMEOUT    (1 << 0)
+
+/*
+ * Autosleep register values (ms)
+ */
+#define MAX7359_AUTOSLEEP_8192 0x01
+#define MAX7359_AUTOSLEEP_4096 0x02
+#define MAX7359_AUTOSLEEP_2048 0x03
+#define MAX7359_AUTOSLEEP_1024 0x04
+#define MAX7359_AUTOSLEEP_512  0x05
+#define MAX7359_AUTOSLEEP_256  0x06
+
+struct max7359_keypad {
+       /* matrix key code map */
+       unsigned short keycodes[MAX7359_MAX_KEY_NUM];
+
+       struct input_dev *input_dev;
+       struct i2c_client *client;
+};
+
+static int max7359_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+       int ret = i2c_smbus_write_byte_data(client, reg, val);
+
+       if (ret < 0)
+               dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
+                       __func__, reg, val, ret);
+       return ret;
+}
+
+static int max7359_read_reg(struct i2c_client *client, int reg)
+{
+       int ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               dev_err(&client->dev, "%s: reg 0x%x, err %d\n",
+                       __func__, reg, ret);
+       return ret;
+}
+
+static void max7359_build_keycode(struct max7359_keypad *keypad,
+                               const struct matrix_keymap_data *keymap_data)
+{
+       struct input_dev *input_dev = keypad->input_dev;
+       int i;
+
+       for (i = 0; i < keymap_data->keymap_size; i++) {
+               unsigned int key = keymap_data->keymap[i];
+               unsigned int row = KEY_ROW(key);
+               unsigned int col = KEY_COL(key);
+               unsigned int scancode = MATRIX_SCAN_CODE(row, col,
+                                               MAX7359_ROW_SHIFT);
+               unsigned short keycode = KEY_VAL(key);
+
+               keypad->keycodes[scancode] = keycode;
+               __set_bit(keycode, input_dev->keybit);
+       }
+       __clear_bit(KEY_RESERVED, input_dev->keybit);
+}
+
+/* runs in an IRQ thread -- can (and will!) sleep */
+static irqreturn_t max7359_interrupt(int irq, void *dev_id)
+{
+       struct max7359_keypad *keypad = dev_id;
+       struct input_dev *input_dev = keypad->input_dev;
+       int val, row, col, release, code;
+
+       val = max7359_read_reg(keypad->client, MAX7359_REG_KEYFIFO);
+       row = val & 0x7;
+       col = (val >> 3) & 0x7;
+       release = val & 0x40;
+
+       code = MATRIX_SCAN_CODE(row, col, MAX7359_ROW_SHIFT);
+
+       dev_dbg(&keypad->client->dev,
+               "key[%d:%d] %s\n", row, col, release ? "release" : "press");
+
+       input_event(input_dev, EV_MSC, MSC_SCAN, code);
+       input_report_key(input_dev, keypad->keycodes[code], !release);
+       input_sync(input_dev);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Let MAX7359 fall into a deep sleep:
+ * If no keys are pressed, enter sleep mode for 8192 ms. And if any
+ * key is pressed, the MAX7359 returns to normal operating mode.
+ */
+static inline void max7359_fall_deepsleep(struct i2c_client *client)
+{
+       max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_8192);
+}
+
+/*
+ * Let MAX7359 take a catnap:
+ * Autosleep just for 256 ms.
+ */
+static inline void max7359_take_catnap(struct i2c_client *client)
+{
+       max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_256);
+}
+
+static int max7359_open(struct input_dev *dev)
+{
+       struct max7359_keypad *keypad = input_get_drvdata(dev);
+
+       max7359_take_catnap(keypad->client);
+
+       return 0;
+}
+
+static void max7359_close(struct input_dev *dev)
+{
+       struct max7359_keypad *keypad = input_get_drvdata(dev);
+
+       max7359_fall_deepsleep(keypad->client);
+}
+
+static void max7359_initialize(struct i2c_client *client)
+{
+       max7359_write_reg(client, MAX7359_REG_CONFIG,
+               MAX7359_CFG_INTERRUPT | /* Irq clears after host read */
+               MAX7359_CFG_KEY_RELEASE | /* Key release enable */
+               MAX7359_CFG_WAKEUP); /* Key press wakeup enable */
+
+       /* Full key-scan functionality */
+       max7359_write_reg(client, MAX7359_REG_DEBOUNCE, 0x1F);
+
+       /* nINT asserts every debounce cycles */
+       max7359_write_reg(client, MAX7359_REG_INTERRUPT, 0x01);
+
+       max7359_fall_deepsleep(client);
+}
+
+static int __devinit max7359_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       const struct matrix_keymap_data *keymap_data = client->dev.platform_data;
+       struct max7359_keypad *keypad;
+       struct input_dev *input_dev;
+       int ret;
+       int error;
+
+       if (!client->irq) {
+               dev_err(&client->dev, "The irq number should not be zero\n");
+               return -EINVAL;
+       }
+
+       /* Detect MAX7359: The initial Keys FIFO value is '0x3F' */
+       ret = max7359_read_reg(client, MAX7359_REG_KEYFIFO);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed to detect device\n");
+               return -ENODEV;
+       }
+
+       dev_dbg(&client->dev, "keys FIFO is 0x%02x\n", ret);
+
+       keypad = kzalloc(sizeof(struct max7359_keypad), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!keypad || !input_dev) {
+               dev_err(&client->dev, "failed to allocate memory\n");
+               error = -ENOMEM;
+               goto failed_free_mem;
+       }
+
+       keypad->client = client;
+       keypad->input_dev = input_dev;
+
+       input_dev->name = client->name;
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->open = max7359_open;
+       input_dev->close = max7359_close;
+       input_dev->dev.parent = &client->dev;
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+       input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+       input_dev->keycode = keypad->keycodes;
+
+       input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+       input_set_drvdata(input_dev, keypad);
+
+       max7359_build_keycode(keypad, keymap_data);
+
+       error = request_threaded_irq(client->irq, NULL, max7359_interrupt,
+                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                    client->name, keypad);
+       if (error) {
+               dev_err(&client->dev, "failed to register interrupt\n");
+               goto failed_free_mem;
+       }
+
+       /* Register the input device */
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&client->dev, "failed to register input device\n");
+               goto failed_free_irq;
+       }
+
+       /* Initialize MAX7359 */
+       max7359_initialize(client);
+
+       i2c_set_clientdata(client, keypad);
+       device_init_wakeup(&client->dev, 1);
+
+       return 0;
+
+failed_free_irq:
+       free_irq(client->irq, keypad);
+failed_free_mem:
+       input_free_device(input_dev);
+       kfree(keypad);
+       return error;
+}
+
+static int __devexit max7359_remove(struct i2c_client *client)
+{
+       struct max7359_keypad *keypad = i2c_get_clientdata(client);
+
+       free_irq(client->irq, keypad);
+       input_unregister_device(keypad->input_dev);
+       i2c_set_clientdata(client, NULL);
+       kfree(keypad);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int max7359_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       max7359_fall_deepsleep(client);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int max7359_resume(struct i2c_client *client)
+{
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+
+       /* Restore the default setting */
+       max7359_take_catnap(client);
+
+       return 0;
+}
+#else
+#define max7359_suspend        NULL
+#define max7359_resume NULL
+#endif
+
+static const struct i2c_device_id max7359_ids[] = {
+       { "max7359", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max7359_ids);
+
+static struct i2c_driver max7359_i2c_driver = {
+       .driver = {
+               .name = "max7359",
+       },
+       .probe          = max7359_probe,
+       .remove         = __devexit_p(max7359_remove),
+       .suspend        = max7359_suspend,
+       .resume         = max7359_resume,
+       .id_table       = max7359_ids,
+};
+
+static int __init max7359_init(void)
+{
+       return i2c_add_driver(&max7359_i2c_driver);
+}
+module_init(max7359_init);
+
+static void __exit max7359_exit(void)
+{
+       i2c_del_driver(&max7359_i2c_driver);
+}
+module_exit(max7359_exit);
+
+MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
+MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c
new file mode 100644 (file)
index 0000000..78cccdd
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * OpenCores Keyboard Controller Driver
+ * http://www.opencores.org/project,keyboardcontroller
+ *
+ * Copyright 2007-2009 HV Sistemas S.L.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct opencores_kbd {
+       struct input_dev *input;
+       struct resource *addr_res;
+       void __iomem *addr;
+       int irq;
+       unsigned short keycodes[128];
+};
+
+static irqreturn_t opencores_kbd_isr(int irq, void *dev_id)
+{
+       struct opencores_kbd *opencores_kbd = dev_id;
+       struct input_dev *input = opencores_kbd->input;
+       unsigned char c;
+
+       c = readb(opencores_kbd->addr);
+       input_report_key(input, c & 0x7f, c & 0x80 ? 0 : 1);
+       input_sync(input);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit opencores_kbd_probe(struct platform_device *pdev)
+{
+       struct input_dev *input;
+       struct opencores_kbd *opencores_kbd;
+       struct resource *res;
+       int irq, i, error;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "missing board memory resource\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "missing board IRQ resource\n");
+               return -EINVAL;
+       }
+
+       opencores_kbd = kzalloc(sizeof(*opencores_kbd), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!opencores_kbd || !input) {
+               dev_err(&pdev->dev, "failed to allocate device structures\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       opencores_kbd->addr_res = res;
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to request I/O memory\n");
+               error = -EBUSY;
+               goto err_free_mem;
+       }
+
+       opencores_kbd->addr = ioremap(res->start, resource_size(res));
+       if (!opencores_kbd->addr) {
+               dev_err(&pdev->dev, "failed to remap I/O memory\n");
+               error = -ENXIO;
+               goto err_rel_mem;
+       }
+
+       opencores_kbd->input = input;
+       opencores_kbd->irq = irq;
+
+       input->name = pdev->name;
+       input->phys = "opencores-kbd/input0";
+       input->dev.parent = &pdev->dev;
+
+       input_set_drvdata(input, opencores_kbd);
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       input->keycode = opencores_kbd->keycodes;
+       input->keycodesize = sizeof(opencores_kbd->keycodes[0]);
+       input->keycodemax = ARRAY_SIZE(opencores_kbd->keycodes);
+
+       __set_bit(EV_KEY, input->evbit);
+
+       for (i = 0; i < ARRAY_SIZE(opencores_kbd->keycodes); i++) {
+               /*
+                * OpenCores controller happens to have scancodes match
+                * our KEY_* definitions.
+                */
+               opencores_kbd->keycodes[i] = i;
+               __set_bit(opencores_kbd->keycodes[i], input->keybit);
+       }
+       __clear_bit(KEY_RESERVED, input->keybit);
+
+       error = request_irq(irq, &opencores_kbd_isr,
+                           IRQF_TRIGGER_RISING, pdev->name, opencores_kbd);
+       if (error) {
+               dev_err(&pdev->dev, "unable to claim irq %d\n", irq);
+               goto err_unmap_mem;
+       }
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&pdev->dev, "unable to register input device\n");
+               goto err_free_irq;
+       }
+
+       platform_set_drvdata(pdev, opencores_kbd);
+
+       return 0;
+
+ err_free_irq:
+       free_irq(irq, opencores_kbd);
+ err_unmap_mem:
+       iounmap(opencores_kbd->addr);
+ err_rel_mem:
+       release_mem_region(res->start, resource_size(res));
+ err_free_mem:
+       input_free_device(input);
+       kfree(opencores_kbd);
+
+       return error;
+}
+
+static int __devexit opencores_kbd_remove(struct platform_device *pdev)
+{
+       struct opencores_kbd *opencores_kbd = platform_get_drvdata(pdev);
+
+       free_irq(opencores_kbd->irq, opencores_kbd);
+
+       iounmap(opencores_kbd->addr);
+       release_mem_region(opencores_kbd->addr_res->start,
+               resource_size(opencores_kbd->addr_res));
+       input_unregister_device(opencores_kbd->input);
+       kfree(opencores_kbd);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver opencores_kbd_device_driver = {
+       .probe    = opencores_kbd_probe,
+       .remove   = __devexit_p(opencores_kbd_remove),
+       .driver   = {
+               .name = "opencores-kbd",
+       },
+};
+
+static int __init opencores_kbd_init(void)
+{
+       return platform_driver_register(&opencores_kbd_device_driver);
+}
+module_init(opencores_kbd_init);
+
+static void __exit opencores_kbd_exit(void)
+{
+       platform_driver_unregister(&opencores_kbd_device_driver);
+}
+module_exit(opencores_kbd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Javier Herrero <jherrero@hvsistemas.es>");
+MODULE_DESCRIPTION("Keyboard driver for OpenCores Keyboard Controller");
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
new file mode 100644 (file)
index 0000000..191cc51
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ *  qt2160.c - Atmel AT42QT2160 Touch Sense Controller
+ *
+ *  Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com>
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+
+#define QT2160_VALID_CHIPID  0x11
+
+#define QT2160_CMD_CHIPID     0
+#define QT2160_CMD_CODEVER    1
+#define QT2160_CMD_GSTAT      2
+#define QT2160_CMD_KEYS3      3
+#define QT2160_CMD_KEYS4      4
+#define QT2160_CMD_SLIDE      5
+#define QT2160_CMD_GPIOS      6
+#define QT2160_CMD_SUBVER     7
+#define QT2160_CMD_CALIBRATE  10
+
+#define QT2160_CYCLE_INTERVAL  (2*HZ)
+
+static unsigned char qt2160_key2code[] = {
+       KEY_0, KEY_1, KEY_2, KEY_3,
+       KEY_4, KEY_5, KEY_6, KEY_7,
+       KEY_8, KEY_9, KEY_A, KEY_B,
+       KEY_C, KEY_D, KEY_E, KEY_F,
+};
+
+struct qt2160_data {
+       struct i2c_client *client;
+       struct input_dev *input;
+       struct delayed_work dwork;
+       spinlock_t lock;        /* Protects canceling/rescheduling of dwork */
+       unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
+       u16 key_matrix;
+};
+
+static int qt2160_read_block(struct i2c_client *client,
+                            u8 inireg, u8 *buffer, unsigned int count)
+{
+       int error, idx = 0;
+
+       /*
+        * Can't use SMBus block data read. Check for I2C functionality to speed
+        * things up whenever possible. Otherwise we will be forced to read
+        * sequentially.
+        */
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))     {
+
+               error = i2c_smbus_write_byte(client, inireg + idx);
+               if (error) {
+                       dev_err(&client->dev,
+                               "couldn't send request. Returned %d\n", error);
+                       return error;
+               }
+
+               error = i2c_master_recv(client, buffer, count);
+               if (error != count) {
+                       dev_err(&client->dev,
+                               "couldn't read registers. Returned %d bytes\n", error);
+                       return error;
+               }
+       } else {
+
+               while (count--) {
+                       int data;
+
+                       error = i2c_smbus_write_byte(client, inireg + idx);
+                       if (error) {
+                               dev_err(&client->dev,
+                                       "couldn't send request. Returned %d\n", error);
+                               return error;
+                       }
+
+                       data = i2c_smbus_read_byte(client);
+                       if (data < 0) {
+                               dev_err(&client->dev,
+                                       "couldn't read register. Returned %d\n", data);
+                               return data;
+                       }
+
+                       buffer[idx++] = data;
+               }
+       }
+
+       return 0;
+}
+
+static int qt2160_get_key_matrix(struct qt2160_data *qt2160)
+{
+       struct i2c_client *client = qt2160->client;
+       struct input_dev *input = qt2160->input;
+       u8 regs[6];
+       u16 old_matrix, new_matrix;
+       int ret, i, mask;
+
+       dev_dbg(&client->dev, "requesting keys...\n");
+
+       /*
+        * Read all registers from General Status Register
+        * to GPIOs register
+        */
+       ret = qt2160_read_block(client, QT2160_CMD_GSTAT, regs, 6);
+       if (ret) {
+               dev_err(&client->dev,
+                       "could not perform chip read.\n");
+               return ret;
+       }
+
+       old_matrix = qt2160->key_matrix;
+       qt2160->key_matrix = new_matrix = (regs[2] << 8) | regs[1];
+
+       mask = 0x01;
+       for (i = 0; i < 16; ++i, mask <<= 1) {
+               int keyval = new_matrix & mask;
+
+               if ((old_matrix & mask) != keyval) {
+                       input_report_key(input, qt2160->keycodes[i], keyval);
+                       dev_dbg(&client->dev, "key %d %s\n",
+                               i, keyval ? "pressed" : "released");
+               }
+       }
+
+       input_sync(input);
+
+       return 0;
+}
+
+static irqreturn_t qt2160_irq(int irq, void *_qt2160)
+{
+       struct qt2160_data *qt2160 = _qt2160;
+       unsigned long flags;
+
+       spin_lock_irqsave(&qt2160->lock, flags);
+
+       __cancel_delayed_work(&qt2160->dwork);
+       schedule_delayed_work(&qt2160->dwork, 0);
+
+       spin_unlock_irqrestore(&qt2160->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static void qt2160_schedule_read(struct qt2160_data *qt2160)
+{
+       spin_lock_irq(&qt2160->lock);
+       schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL);
+       spin_unlock_irq(&qt2160->lock);
+}
+
+static void qt2160_worker(struct work_struct *work)
+{
+       struct qt2160_data *qt2160 =
+               container_of(work, struct qt2160_data, dwork.work);
+
+       dev_dbg(&qt2160->client->dev, "worker\n");
+
+       qt2160_get_key_matrix(qt2160);
+
+       /* Avoid device lock up by checking every so often */
+       qt2160_schedule_read(qt2160);
+}
+
+static int __devinit qt2160_read(struct i2c_client *client, u8 reg)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte(client, reg);
+       if (ret) {
+               dev_err(&client->dev,
+                       "couldn't send request. Returned %d\n", ret);
+               return ret;
+       }
+
+       ret = i2c_smbus_read_byte(client);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "couldn't read register. Returned %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data)
+{
+       int error;
+
+       error = i2c_smbus_write_byte(client, reg);
+       if (error) {
+               dev_err(&client->dev,
+                       "couldn't send request. Returned %d\n", error);
+               return error;
+       }
+
+       error = i2c_smbus_write_byte(client, data);
+       if (error) {
+               dev_err(&client->dev,
+                       "couldn't write data. Returned %d\n", error);
+               return error;
+       }
+
+       return error;
+}
+
+
+static bool __devinit qt2160_identify(struct i2c_client *client)
+{
+       int id, ver, rev;
+
+       /* Read Chid ID to check if chip is valid */
+       id = qt2160_read(client, QT2160_CMD_CHIPID);
+       if (id != QT2160_VALID_CHIPID) {
+               dev_err(&client->dev, "ID %d not supported\n", id);
+               return false;
+       }
+
+       /* Read chip firmware version */
+       ver = qt2160_read(client, QT2160_CMD_CODEVER);
+       if (ver < 0) {
+               dev_err(&client->dev, "could not get firmware version\n");
+               return false;
+       }
+
+       /* Read chip firmware revision */
+       rev = qt2160_read(client, QT2160_CMD_SUBVER);
+       if (rev < 0) {
+               dev_err(&client->dev, "could not get firmware revision\n");
+               return false;
+       }
+
+       dev_info(&client->dev, "AT42QT2160 firmware version %d.%d.%d\n",
+                       ver >> 4, ver & 0xf, rev);
+
+       return true;
+}
+
+static int __devinit qt2160_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct qt2160_data *qt2160;
+       struct input_dev *input;
+       int i;
+       int error;
+
+       /* Check functionality */
+       error = i2c_check_functionality(client->adapter,
+                       I2C_FUNC_SMBUS_BYTE);
+       if (!error) {
+               dev_err(&client->dev, "%s adapter not supported\n",
+                               dev_driver_string(&client->adapter->dev));
+               return -ENODEV;
+       }
+
+       if (!qt2160_identify(client))
+               return -ENODEV;
+
+       /* Chip is valid and active. Allocate structure */
+       qt2160 = kzalloc(sizeof(struct qt2160_data), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!qt2160 || !input) {
+               dev_err(&client->dev, "insufficient memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       qt2160->client = client;
+       qt2160->input = input;
+       INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker);
+       spin_lock_init(&qt2160->lock);
+
+       input->name = "AT42QT2160 Touch Sense Keyboard";
+       input->id.bustype = BUS_I2C;
+
+       input->keycode = qt2160->keycodes;
+       input->keycodesize = sizeof(qt2160->keycodes[0]);
+       input->keycodemax = ARRAY_SIZE(qt2160_key2code);
+
+       __set_bit(EV_KEY, input->evbit);
+       __clear_bit(EV_REP, input->evbit);
+       for (i = 0; i < ARRAY_SIZE(qt2160_key2code); i++) {
+               qt2160->keycodes[i] = qt2160_key2code[i];
+               __set_bit(qt2160_key2code[i], input->keybit);
+       }
+       __clear_bit(KEY_RESERVED, input->keybit);
+
+       /* Calibrate device */
+       error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1);
+       if (error) {
+               dev_err(&client->dev, "failed to calibrate device\n");
+               goto err_free_mem;
+       }
+
+       if (client->irq) {
+               error = request_irq(client->irq, qt2160_irq,
+                                   IRQF_TRIGGER_FALLING, "qt2160", qt2160);
+               if (error) {
+                       dev_err(&client->dev,
+                               "failed to allocate irq %d\n", client->irq);
+                       goto err_free_mem;
+               }
+       }
+
+       error = input_register_device(qt2160->input);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to register input device\n");
+               goto err_free_irq;
+       }
+
+       i2c_set_clientdata(client, qt2160);
+       qt2160_schedule_read(qt2160);
+
+       return 0;
+
+err_free_irq:
+       if (client->irq)
+               free_irq(client->irq, qt2160);
+err_free_mem:
+       input_free_device(input);
+       kfree(qt2160);
+       return error;
+}
+
+static int __devexit qt2160_remove(struct i2c_client *client)
+{
+       struct qt2160_data *qt2160 = i2c_get_clientdata(client);
+
+       /* Release IRQ so no queue will be scheduled */
+       if (client->irq)
+               free_irq(client->irq, qt2160);
+
+       cancel_delayed_work_sync(&qt2160->dwork);
+
+       input_unregister_device(qt2160->input);
+       kfree(qt2160);
+
+       i2c_set_clientdata(client, NULL);
+       return 0;
+}
+
+static struct i2c_device_id qt2160_idtable[] = {
+       { "qt2160", 0, },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, qt2160_idtable);
+
+static struct i2c_driver qt2160_driver = {
+       .driver = {
+               .name   = "qt2160",
+               .owner  = THIS_MODULE,
+       },
+
+       .id_table       = qt2160_idtable,
+       .probe          = qt2160_probe,
+       .remove         = __devexit_p(qt2160_remove),
+};
+
+static int __init qt2160_init(void)
+{
+       return i2c_add_driver(&qt2160_driver);
+}
+module_init(qt2160_init);
+
+static void __exit qt2160_cleanup(void)
+{
+       i2c_del_driver(&qt2160_driver);
+}
+module_exit(qt2160_cleanup);
+
+MODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>");
+MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
+MODULE_LICENSE("GPL");
index 0918acae584ac9844d2dd64c500f235b56f22b72..f2b67dc81d80b92ef186d698737190ff1b4f3fb1 100644 (file)
@@ -96,7 +96,13 @@ static struct {
        { 0x3169, KEY_PAUSE, },
 };
 
-/* runs in an IRQ thread -- can (and will!) sleep */
+/*
+ * Because we communicate with the MSP430 using I2C, and all I2C calls
+ * in Linux sleep, we use a threaded IRQ handler.  The IRQ itself is
+ * active low, but we go through the GPIO controller so we can trigger
+ * on falling edges and not worry about enabling/disabling the IRQ in
+ * the keypress handling path.
+ */
 static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
 {
        struct dm355evm_keys    *keys = _keys;
@@ -171,18 +177,6 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
        return IRQ_HANDLED;
 }
 
-/*
- * Because we communicate with the MSP430 using I2C, and all I2C calls
- * in Linux sleep, we use a threaded IRQ handler.  The IRQ itself is
- * active low, but we go through the GPIO controller so we can trigger
- * on falling edges and not worry about enabling/disabling the IRQ in
- * the keypress handling path.
- */
-static irqreturn_t dm355evm_keys_hardirq(int irq, void *_keys)
-{
-       return IRQ_WAKE_THREAD;
-}
-
 static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode)
 {
        u16             old_keycode;
@@ -257,10 +251,8 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
 
        /* REVISIT:  flush the event queue? */
 
-       status = request_threaded_irq(keys->irq,
-                       dm355evm_keys_hardirq, dm355evm_keys_irq,
-                       IRQF_TRIGGER_FALLING,
-                       dev_name(&pdev->dev), keys);
+       status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,
+                       IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);
        if (status < 0)
                goto fail1;
 
index 84e2fc04d11bbda7f68d93cf7f3f64c98da2e0c6..f84cbd97c8842ff12a406b61d543bfd7c036a75d 100644 (file)
@@ -92,7 +92,8 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
         */
        ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
-       mutex_lock(&ps2dev->cmd_mutex);
+
+       ps2_begin_command(ps2dev);
 
        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
                goto out;
@@ -126,7 +127,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
        rc = 0;
 
  out:
-       mutex_unlock(&ps2dev->cmd_mutex);
+       ps2_end_command(ps2dev);
        ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
        psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
        dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
@@ -140,7 +141,7 @@ static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
        unsigned char v;
        int rc = -1;
 
-       mutex_lock(&ps2dev->cmd_mutex);
+       ps2_begin_command(ps2dev);
 
        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
                goto out;
@@ -179,7 +180,7 @@ static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
        rc = 0;
 
  out:
-       mutex_unlock(&ps2dev->cmd_mutex);
+       ps2_end_command(ps2dev);
        dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n",
                reg_addr, reg_val, rc);
        return rc;
@@ -214,7 +215,8 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
 
        ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
-       mutex_lock(&ps2dev->cmd_mutex);
+
+       ps2_begin_command(ps2dev);
 
        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
                goto out;
@@ -236,7 +238,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
        rc = 0;
 
  out:
-       mutex_unlock(&ps2dev->cmd_mutex);
+       ps2_end_command(ps2dev);
        ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
        psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
        dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
@@ -250,7 +252,7 @@ static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
        unsigned char v;
        int rc = -1;
 
-       mutex_lock(&ps2dev->cmd_mutex);
+       ps2_begin_command(ps2dev);
 
        if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0)
                goto out;
@@ -275,7 +277,7 @@ static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
        rc = 0;
 
  out:
-       mutex_unlock(&ps2dev->cmd_mutex);
+       ps2_end_command(ps2dev);
        dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n",
                reg_val, rc);
        return rc;
index eac9fdde7ee9c13db9f5dc0c64aed2fcb82ee24b..7283c78044af3cd9a6a701bdb9f94684daf80e5f 100644 (file)
@@ -203,7 +203,7 @@ MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)");
  * and the irq configuration should be set to Falling Edge Trigger
  */
 /* Control IRQ / Polling option */
-static int polling_req;
+static bool polling_req;
 module_param(polling_req, bool, 0444);
 MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)");
 
@@ -217,6 +217,7 @@ struct synaptics_i2c {
        struct i2c_client       *client;
        struct input_dev        *input;
        struct delayed_work     dwork;
+       spinlock_t              lock;
        int                     no_data_count;
        int                     no_decel_param;
        int                     reduce_report_param;
@@ -366,17 +367,28 @@ static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
        return xy_delta || gesture;
 }
 
-static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
+static void synaptics_i2c_reschedule_work(struct synaptics_i2c *touch,
+                                         unsigned long delay)
 {
-       struct synaptics_i2c *touch = dev_id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&touch->lock, flags);
 
        /*
-        * We want to have the work run immediately but it might have
-        * already been scheduled with a delay, that's why we have to
-        * cancel it first.
+        * If work is already scheduled then subsequent schedules will not
+        * change the scheduled time that's why we have to cancel it first.
         */
-       cancel_delayed_work(&touch->dwork);
-       schedule_delayed_work(&touch->dwork, 0);
+       __cancel_delayed_work(&touch->dwork);
+       schedule_delayed_work(&touch->dwork, delay);
+
+       spin_unlock_irqrestore(&touch->lock, flags);
+}
+
+static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
+{
+       struct synaptics_i2c *touch = dev_id;
+
+       synaptics_i2c_reschedule_work(touch, 0);
 
        return IRQ_HANDLED;
 }
@@ -452,7 +464,7 @@ static void synaptics_i2c_work_handler(struct work_struct *work)
         * We poll the device once in THREAD_IRQ_SLEEP_SECS and
         * if error is detected, we try to reset and reconfigure the touchpad.
         */
-       schedule_delayed_work(&touch->dwork, delay);
+       synaptics_i2c_reschedule_work(touch, delay);
 }
 
 static int synaptics_i2c_open(struct input_dev *input)
@@ -465,8 +477,8 @@ static int synaptics_i2c_open(struct input_dev *input)
                return ret;
 
        if (polling_req)
-               schedule_delayed_work(&touch->dwork,
-                                      msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
+               synaptics_i2c_reschedule_work(touch,
+                               msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
 
        return 0;
 }
@@ -521,6 +533,7 @@ struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client)
        touch->scan_rate_param = scan_rate;
        set_scan_rate(touch, scan_rate);
        INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler);
+       spin_lock_init(&touch->lock);
 
        return touch;
 }
@@ -535,14 +548,12 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
        if (!touch)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, touch);
-
        ret = synaptics_i2c_reset_config(client);
        if (ret)
                goto err_mem_free;
 
        if (client->irq < 1)
-               polling_req = 1;
+               polling_req = true;
 
        touch->input = input_allocate_device();
        if (!touch->input) {
@@ -563,7 +574,7 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
                        dev_warn(&touch->client->dev,
                                  "IRQ request failed: %d, "
                                  "falling back to polling\n", ret);
-                       polling_req = 1;
+                       polling_req = true;
                        synaptics_i2c_reg_set(touch->client,
                                              INTERRUPT_EN_REG, 0);
                }
@@ -580,12 +591,14 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
                         "Input device register failed: %d\n", ret);
                goto err_input_free;
        }
+
+       i2c_set_clientdata(client, touch);
+
        return 0;
 
 err_input_free:
        input_free_device(touch->input);
 err_mem_free:
-       i2c_set_clientdata(client, NULL);
        kfree(touch);
 
        return ret;
@@ -596,7 +609,7 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
        struct synaptics_i2c *touch = i2c_get_clientdata(client);
 
        if (!polling_req)
-               free_irq(touch->client->irq, touch);
+               free_irq(client->irq, touch);
 
        input_unregister_device(touch->input);
        i2c_set_clientdata(client, NULL);
@@ -627,8 +640,8 @@ static int synaptics_i2c_resume(struct i2c_client *client)
        if (ret)
                return ret;
 
-       schedule_delayed_work(&touch->dwork,
-                              msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
+       synaptics_i2c_reschedule_work(touch,
+                               msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
 
        return 0;
 }
index eb3ff94af58c4cd6e87a41600c9a06cf886011a8..bc56e52b945f68c8e0fa604a7d88659dfa77fc23 100644 (file)
@@ -87,8 +87,22 @@ static bool i8042_bypass_aux_irq_test;
 
 #include "i8042.h"
 
+/*
+ * i8042_lock protects serialization between i8042_command and
+ * the interrupt handler.
+ */
 static DEFINE_SPINLOCK(i8042_lock);
 
+/*
+ * Writers to AUX and KBD ports as well as users issuing i8042_command
+ * directly should acquire i8042_mutex (by means of calling
+ * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
+ * they do not disturb each other (unfortunately in many i8042
+ * implementations write to one of the ports will immediately abort
+ * command that is being processed by another port).
+ */
+static DEFINE_MUTEX(i8042_mutex);
+
 struct i8042_port {
        struct serio *serio;
        int irq;
@@ -113,6 +127,18 @@ static struct platform_device *i8042_platform_device;
 
 static irqreturn_t i8042_interrupt(int irq, void *dev_id);
 
+void i8042_lock_chip(void)
+{
+       mutex_lock(&i8042_mutex);
+}
+EXPORT_SYMBOL(i8042_lock_chip);
+
+void i8042_unlock_chip(void)
+{
+       mutex_unlock(&i8042_mutex);
+}
+EXPORT_SYMBOL(i8042_unlock_chip);
+
 /*
  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
  * be ready for reading values from it / writing values to it.
@@ -1161,6 +1187,21 @@ static void __devexit i8042_unregister_ports(void)
        }
 }
 
+/*
+ * Checks whether port belongs to i8042 controller.
+ */
+bool i8042_check_port_owner(const struct serio *port)
+{
+       int i;
+
+       for (i = 0; i < I8042_NUM_PORTS; i++)
+               if (i8042_ports[i].serio == port)
+                       return true;
+
+       return false;
+}
+EXPORT_SYMBOL(i8042_check_port_owner);
+
 static void i8042_free_irqs(void)
 {
        if (i8042_aux_irq_registered)
index 3a95b508bf27b93b014503f06687a7e9ff92b86b..769ba65a585a562a2f298df5f3e62403e316c721 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/serio.h>
+#include <linux/i8042.h>
 #include <linux/init.h>
 #include <linux/libps2.h>
 
@@ -54,6 +55,24 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
 }
 EXPORT_SYMBOL(ps2_sendbyte);
 
+void ps2_begin_command(struct ps2dev *ps2dev)
+{
+       mutex_lock(&ps2dev->cmd_mutex);
+
+       if (i8042_check_port_owner(ps2dev->serio))
+               i8042_lock_chip();
+}
+EXPORT_SYMBOL(ps2_begin_command);
+
+void ps2_end_command(struct ps2dev *ps2dev)
+{
+       if (i8042_check_port_owner(ps2dev->serio))
+               i8042_unlock_chip();
+
+       mutex_unlock(&ps2dev->cmd_mutex);
+}
+EXPORT_SYMBOL(ps2_end_command);
+
 /*
  * ps2_drain() waits for device to transmit requested number of bytes
  * and discards them.
@@ -66,7 +85,7 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
                maxbytes = sizeof(ps2dev->cmdbuf);
        }
 
-       mutex_lock(&ps2dev->cmd_mutex);
+       ps2_begin_command(ps2dev);
 
        serio_pause_rx(ps2dev->serio);
        ps2dev->flags = PS2_FLAG_CMD;
@@ -76,7 +95,8 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
        wait_event_timeout(ps2dev->wait,
                           !(ps2dev->flags & PS2_FLAG_CMD),
                           msecs_to_jiffies(timeout));
-       mutex_unlock(&ps2dev->cmd_mutex);
+
+       ps2_end_command(ps2dev);
 }
 EXPORT_SYMBOL(ps2_drain);
 
@@ -237,9 +257,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 {
        int rc;
 
-       mutex_lock(&ps2dev->cmd_mutex);
+       ps2_begin_command(ps2dev);
        rc = __ps2_command(ps2dev, param, command);
-       mutex_unlock(&ps2dev->cmd_mutex);
+       ps2_end_command(ps2dev);
 
        return rc;
 }
index ab02d72afbf3b0f5df3b2eb7bbec895b202bad5e..8cc453c85ea704d42ee8411d232c31193e8212e1 100644 (file)
@@ -48,8 +48,8 @@ config TOUCHSCREEN_AD7879_I2C
        select TOUCHSCREEN_AD7879
        help
          Say Y here if you have a touchscreen interface using the
-         AD7879-1 controller, and your board-specific initialization
-         code includes that in its table of I2C devices.
+         AD7879-1/AD7889-1 controller, and your board-specific
+         initialization code includes that in its table of I2C devices.
 
          If unsure, say N (but it's safe to say "Y").
 
@@ -62,7 +62,7 @@ config TOUCHSCREEN_AD7879_SPI
        select TOUCHSCREEN_AD7879
        help
          Say Y here if you have a touchscreen interface using the
-         AD7879 controller, and your board-specific initialization
+         AD7879/AD7889 controller, and your board-specific initialization
          code includes that in its table of SPI devices.
 
          If unsure, say N (but it's safe to say "Y").
@@ -169,6 +169,17 @@ config TOUCHSCREEN_WACOM_W8001
          To compile this driver as a module, choose M here: the
          module will be called wacom_w8001.
 
+config TOUCHSCREEN_MCS5000
+       tristate "MELFAS MCS-5000 touchscreen"
+       depends on I2C
+       help
+         Say Y here if you have the MELFAS MCS-5000 touchscreen controller
+         chip in your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mcs5000_ts.
 
 config TOUCHSCREEN_MTOUCH
        tristate "MicroTouch serial touchscreens"
index 4599bf7ad8193ec0ce5f8b909a687d86e1887600..15fa62cffc77f576b8cb364e7712ea7e76b402c0 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI)                += eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)          += elo.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)      += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)       += inexio.o
+obj-$(CONFIG_TOUCHSCREEN_MCS5000)      += mcs5000_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MIGOR)                += migor_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MTOUCH)       += mtouch.o
 obj-$(CONFIG_TOUCHSCREEN_MK712)                += mk712.o
index 19b4db7e974d75c42eb3f7e9e21e8c19ac8d782e..f06332c9e21ba069bb177ff915897db2b9492e52 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Copyright (C) 2008 Michael Hennerich, Analog Devices Inc.
+ * Copyright (C) 2008-2009 Michael Hennerich, Analog Devices Inc.
  *
- * Description:        AD7879 based touchscreen, and GPIO driver (I2C/SPI Interface)
+ * Description:        AD7879/AD7889 based touchscreen, and GPIO driver
+ *             (I2C/SPI Interface)
  *
  * Bugs:        Enter bugs at http://blackfin.uclinux.org/
  *
@@ -747,6 +748,7 @@ static int __devexit ad7879_remove(struct i2c_client *client)
 
 static const struct i2c_device_id ad7879_id[] = {
        { "ad7879", 0 },
+       { "ad7889", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ad7879_id);
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
new file mode 100644 (file)
index 0000000..4c28b89
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * Based on wm97xx-core.c
+ *
+ *  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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/mcs5000_ts.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+
+/* Registers */
+#define MCS5000_TS_STATUS              0x00
+#define STATUS_OFFSET                  0
+#define STATUS_NO                      (0 << STATUS_OFFSET)
+#define STATUS_INIT                    (1 << STATUS_OFFSET)
+#define STATUS_SENSING                 (2 << STATUS_OFFSET)
+#define STATUS_COORD                   (3 << STATUS_OFFSET)
+#define STATUS_GESTURE                 (4 << STATUS_OFFSET)
+#define ERROR_OFFSET                   4
+#define ERROR_NO                       (0 << ERROR_OFFSET)
+#define ERROR_POWER_ON_RESET           (1 << ERROR_OFFSET)
+#define ERROR_INT_RESET                        (2 << ERROR_OFFSET)
+#define ERROR_EXT_RESET                        (3 << ERROR_OFFSET)
+#define ERROR_INVALID_REG_ADDRESS      (8 << ERROR_OFFSET)
+#define ERROR_INVALID_REG_VALUE                (9 << ERROR_OFFSET)
+
+#define MCS5000_TS_OP_MODE             0x01
+#define RESET_OFFSET                   0
+#define RESET_NO                       (0 << RESET_OFFSET)
+#define RESET_EXT_SOFT                 (1 << RESET_OFFSET)
+#define OP_MODE_OFFSET                 1
+#define OP_MODE_SLEEP                  (0 << OP_MODE_OFFSET)
+#define OP_MODE_ACTIVE                 (1 << OP_MODE_OFFSET)
+#define GESTURE_OFFSET                 4
+#define GESTURE_DISABLE                        (0 << GESTURE_OFFSET)
+#define GESTURE_ENABLE                 (1 << GESTURE_OFFSET)
+#define PROXIMITY_OFFSET               5
+#define PROXIMITY_DISABLE              (0 << PROXIMITY_OFFSET)
+#define PROXIMITY_ENABLE               (1 << PROXIMITY_OFFSET)
+#define SCAN_MODE_OFFSET               6
+#define SCAN_MODE_INTERRUPT            (0 << SCAN_MODE_OFFSET)
+#define SCAN_MODE_POLLING              (1 << SCAN_MODE_OFFSET)
+#define REPORT_RATE_OFFSET             7
+#define REPORT_RATE_40                 (0 << REPORT_RATE_OFFSET)
+#define REPORT_RATE_80                 (1 << REPORT_RATE_OFFSET)
+
+#define MCS5000_TS_SENS_CTL            0x02
+#define MCS5000_TS_FILTER_CTL          0x03
+#define PRI_FILTER_OFFSET              0
+#define SEC_FILTER_OFFSET              4
+
+#define MCS5000_TS_X_SIZE_UPPER                0x08
+#define MCS5000_TS_X_SIZE_LOWER                0x09
+#define MCS5000_TS_Y_SIZE_UPPER                0x0A
+#define MCS5000_TS_Y_SIZE_LOWER                0x0B
+
+#define MCS5000_TS_INPUT_INFO          0x10
+#define INPUT_TYPE_OFFSET              0
+#define INPUT_TYPE_NONTOUCH            (0 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_SINGLE              (1 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_DUAL                        (2 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_PALM                        (3 << INPUT_TYPE_OFFSET)
+#define INPUT_TYPE_PROXIMITY           (7 << INPUT_TYPE_OFFSET)
+#define GESTURE_CODE_OFFSET            3
+#define GESTURE_CODE_NO                        (0 << GESTURE_CODE_OFFSET)
+
+#define MCS5000_TS_X_POS_UPPER         0x11
+#define MCS5000_TS_X_POS_LOWER         0x12
+#define MCS5000_TS_Y_POS_UPPER         0x13
+#define MCS5000_TS_Y_POS_LOWER         0x14
+#define MCS5000_TS_Z_POS               0x15
+#define MCS5000_TS_WIDTH               0x16
+#define MCS5000_TS_GESTURE_VAL         0x17
+#define MCS5000_TS_MODULE_REV          0x20
+#define MCS5000_TS_FIRMWARE_VER                0x21
+
+/* Touchscreen absolute values */
+#define MCS5000_MAX_XC                 0x3ff
+#define MCS5000_MAX_YC                 0x3ff
+
+enum mcs5000_ts_read_offset {
+       READ_INPUT_INFO,
+       READ_X_POS_UPPER,
+       READ_X_POS_LOWER,
+       READ_Y_POS_UPPER,
+       READ_Y_POS_LOWER,
+       READ_BLOCK_SIZE,
+};
+
+/* Each client has this additional data */
+struct mcs5000_ts_data {
+       struct i2c_client *client;
+       struct input_dev *input_dev;
+       const struct mcs5000_ts_platform_data *platform_data;
+};
+
+static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
+{
+       struct mcs5000_ts_data *data = dev_id;
+       struct i2c_client *client = data->client;
+       u8 buffer[READ_BLOCK_SIZE];
+       int err;
+       int x;
+       int y;
+
+       err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
+                       READ_BLOCK_SIZE, buffer);
+       if (err < 0) {
+               dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
+               goto out;
+       }
+
+       switch (buffer[READ_INPUT_INFO]) {
+       case INPUT_TYPE_NONTOUCH:
+               input_report_key(data->input_dev, BTN_TOUCH, 0);
+               input_sync(data->input_dev);
+               break;
+
+       case INPUT_TYPE_SINGLE:
+               x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
+               y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
+
+               input_report_key(data->input_dev, BTN_TOUCH, 1);
+               input_report_abs(data->input_dev, ABS_X, x);
+               input_report_abs(data->input_dev, ABS_Y, y);
+               input_sync(data->input_dev);
+               break;
+
+       case INPUT_TYPE_DUAL:
+               /* TODO */
+               break;
+
+       case INPUT_TYPE_PALM:
+               /* TODO */
+               break;
+
+       case INPUT_TYPE_PROXIMITY:
+               /* TODO */
+               break;
+
+       default:
+               dev_err(&client->dev, "Unknown ts input type %d\n",
+                               buffer[READ_INPUT_INFO]);
+               break;
+       }
+
+ out:
+       return IRQ_HANDLED;
+}
+
+static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
+{
+       const struct mcs5000_ts_platform_data *platform_data =
+               data->platform_data;
+       struct i2c_client *client = data->client;
+
+       /* Touch reset & sleep mode */
+       i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
+                       RESET_EXT_SOFT | OP_MODE_SLEEP);
+
+       /* Touch size */
+       i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
+                       platform_data->x_size >> 8);
+       i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
+                       platform_data->x_size & 0xff);
+       i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
+                       platform_data->y_size >> 8);
+       i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
+                       platform_data->y_size & 0xff);
+
+       /* Touch active mode & 80 report rate */
+       i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
+                       OP_MODE_ACTIVE | REPORT_RATE_80);
+}
+
+static int __devinit mcs5000_ts_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct mcs5000_ts_data *data;
+       struct input_dev *input_dev;
+       int ret;
+
+       if (!client->dev.platform_data)
+               return -EINVAL;
+
+       data = kzalloc(sizeof(struct mcs5000_ts_data), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!data || !input_dev) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               ret = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       data->client = client;
+       data->input_dev = input_dev;
+       data->platform_data = client->dev.platform_data;
+
+       input_dev->name = "MELPAS MCS-5000 Touchscreen";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+       input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
+
+       input_set_drvdata(input_dev, data);
+
+       if (data->platform_data->cfg_pin)
+               data->platform_data->cfg_pin();
+
+       ret = request_threaded_irq(client->irq, NULL, mcs5000_ts_interrupt,
+                       IRQF_TRIGGER_LOW | IRQF_ONESHOT, "mcs5000_ts", data);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       ret = input_register_device(data->input_dev);
+       if (ret < 0)
+               goto err_free_irq;
+
+       mcs5000_ts_phys_init(data);
+       i2c_set_clientdata(client, data);
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(data);
+       return ret;
+}
+
+static int __devexit mcs5000_ts_remove(struct i2c_client *client)
+{
+       struct mcs5000_ts_data *data = i2c_get_clientdata(client);
+
+       free_irq(client->irq, data);
+       input_unregister_device(data->input_dev);
+       kfree(data);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       /* 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)
+{
+       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
+#endif
+
+static const struct i2c_device_id mcs5000_ts_id[] = {
+       { "mcs5000_ts", 0 },
+       { }
+};
+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",
+       },
+       .id_table       = mcs5000_ts_id,
+};
+
+static int __init mcs5000_ts_init(void)
+{
+       return i2c_add_driver(&mcs5000_ts_driver);
+}
+
+static void __exit mcs5000_ts_exit(void)
+{
+       i2c_del_driver(&mcs5000_ts_driver);
+}
+
+module_init(mcs5000_ts_init);
+module_exit(mcs5000_ts_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MELFAS MCS-5000 controller");
+MODULE_LICENSE("GPL");
index 1813c84ea5fccb10293e499a3721dacf94c54290..f2242db5401624d9c7091ea6ac04f330fe7f94fa 100644 (file)
@@ -93,6 +93,8 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
 static void clevo_mail_led_set(struct led_classdev *led_cdev,
                                enum led_brightness value)
 {
+       i8042_lock_chip();
+
        if (value == LED_OFF)
                i8042_command(NULL, CLEVO_MAIL_LED_OFF);
        else if (value <= LED_HALF)
@@ -100,6 +102,8 @@ static void clevo_mail_led_set(struct led_classdev *led_cdev,
        else
                i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
 
+       i8042_unlock_chip();
+
 }
 
 static int clevo_mail_led_blink(struct led_classdev *led_cdev,
@@ -108,6 +112,8 @@ static int clevo_mail_led_blink(struct led_classdev *led_cdev,
 {
        int status = -EINVAL;
 
+       i8042_lock_chip();
+
        if (*delay_on == 0 /* ms */ && *delay_off == 0 /* ms */) {
                /* Special case: the leds subsystem requested us to
                 * chose one user friendly blinking of the LED, and
@@ -135,6 +141,8 @@ static int clevo_mail_led_blink(struct led_classdev *led_cdev,
                       *delay_on, *delay_off);
        }
 
+       i8042_unlock_chip();
+
        return status;
 }
 
index fb45f5ee8df12a79c49e68ca88736f31920e5d80..454970d2d701b807317f06415a8baccaf7af50fe 100644 (file)
@@ -746,7 +746,9 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
                        return AE_BAD_PARAMETER;
                if (quirks->mailled == 1) {
                        param = value ? 0x92 : 0x93;
+                       i8042_lock_chip();
                        i8042_command(&param, 0x1059);
+                       i8042_unlock_chip();
                        return 0;
                }
                break;
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
new file mode 100644 (file)
index 0000000..fc5db82
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller
+ *
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADP5588_H
+#define _ADP5588_H
+
+#define DEV_ID 0x00            /* Device ID */
+#define CFG 0x01               /* Configuration Register1 */
+#define INT_STAT 0x02          /* Interrupt Status Register */
+#define KEY_LCK_EC_STAT 0x03   /* Key Lock and Event Counter Register */
+#define Key_EVENTA 0x04                /* Key Event Register A */
+#define Key_EVENTB 0x05                /* Key Event Register B */
+#define Key_EVENTC 0x06                /* Key Event Register C */
+#define Key_EVENTD 0x07                /* Key Event Register D */
+#define Key_EVENTE 0x08                /* Key Event Register E */
+#define Key_EVENTF 0x09                /* Key Event Register F */
+#define Key_EVENTG 0x0A                /* Key Event Register G */
+#define Key_EVENTH 0x0B                /* Key Event Register H */
+#define Key_EVENTI 0x0C                /* Key Event Register I */
+#define Key_EVENTJ 0x0D                /* Key Event Register J */
+#define KP_LCK_TMR 0x0E                /* Keypad Lock1 to Lock2 Timer */
+#define UNLOCK1 0x0F           /* Unlock Key1 */
+#define UNLOCK2 0x10           /* Unlock Key2 */
+#define GPIO_INT_STAT1 0x11    /* GPIO Interrupt Status */
+#define GPIO_INT_STAT2 0x12    /* GPIO Interrupt Status */
+#define GPIO_INT_STAT3 0x13    /* GPIO Interrupt Status */
+#define GPIO_DAT_STAT1 0x14    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT2 0x15    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT3 0x16    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_OUT1 0x17     /* GPIO DATA OUT */
+#define GPIO_DAT_OUT2 0x18     /* GPIO DATA OUT */
+#define GPIO_DAT_OUT3 0x19     /* GPIO DATA OUT */
+#define GPIO_INT_EN1 0x1A      /* GPIO Interrupt Enable */
+#define GPIO_INT_EN2 0x1B      /* GPIO Interrupt Enable */
+#define GPIO_INT_EN3 0x1C      /* GPIO Interrupt Enable */
+#define KP_GPIO1 0x1D          /* Keypad or GPIO Selection */
+#define KP_GPIO2 0x1E          /* Keypad or GPIO Selection */
+#define KP_GPIO3 0x1F          /* Keypad or GPIO Selection */
+#define GPI_EM1 0x20           /* GPI Event Mode 1 */
+#define GPI_EM2 0x21           /* GPI Event Mode 2 */
+#define GPI_EM3 0x22           /* GPI Event Mode 3 */
+#define GPIO_DIR1 0x23         /* GPIO Data Direction */
+#define GPIO_DIR2 0x24         /* GPIO Data Direction */
+#define GPIO_DIR3 0x25         /* GPIO Data Direction */
+#define GPIO_INT_LVL1 0x26     /* GPIO Edge/Level Detect */
+#define GPIO_INT_LVL2 0x27     /* GPIO Edge/Level Detect */
+#define GPIO_INT_LVL3 0x28     /* GPIO Edge/Level Detect */
+#define Debounce_DIS1 0x29     /* Debounce Disable */
+#define Debounce_DIS2 0x2A     /* Debounce Disable */
+#define Debounce_DIS3 0x2B     /* Debounce Disable */
+#define GPIO_PULL1 0x2C                /* GPIO Pull Disable */
+#define GPIO_PULL2 0x2D                /* GPIO Pull Disable */
+#define GPIO_PULL3 0x2E                /* GPIO Pull Disable */
+#define CMP_CFG_STAT 0x30      /* Comparator Configuration and Status Register */
+#define CMP_CONFG_SENS1 0x31   /* Sensor1 Comparator Configuration Register */
+#define CMP_CONFG_SENS2 0x32   /* L2 Light Sensor Reference Level, Output Falling for Sensor 1 */
+#define CMP1_LVL2_TRIP 0x33    /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 1 */
+#define CMP1_LVL2_HYS 0x34     /* L3 Light Sensor Reference Level, Output Falling For Sensor 1 */
+#define CMP1_LVL3_TRIP 0x35    /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 1 */
+#define CMP1_LVL3_HYS 0x36     /* Sensor 2 Comparator Configuration Register */
+#define CMP2_LVL2_TRIP 0x37    /* L2 Light Sensor Reference Level, Output Falling for Sensor 2 */
+#define CMP2_LVL2_HYS 0x38     /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 2 */
+#define CMP2_LVL3_TRIP 0x39    /* L3 Light Sensor Reference Level, Output Falling For Sensor 2 */
+#define CMP2_LVL3_HYS 0x3A     /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 2 */
+#define CMP1_ADC_DAT_R1 0x3B   /* Comparator 1 ADC data Register1 */
+#define CMP1_ADC_DAT_R2 0x3C   /* Comparator 1 ADC data Register2 */
+#define CMP2_ADC_DAT_R1 0x3D   /* Comparator 2 ADC data Register1 */
+#define CMP2_ADC_DAT_R2 0x3E   /* Comparator 2 ADC data Register2 */
+
+#define ADP5588_DEVICE_ID_MASK 0xF
+
+/* Put one of these structures in i2c_board_info platform_data */
+
+#define ADP5588_KEYMAPSIZE     80
+
+struct adp5588_kpad_platform_data {
+       int rows;                       /* Number of rows */
+       int cols;                       /* Number of columns */
+       const unsigned short *keymap;   /* Pointer to keymap */
+       unsigned short keymapsize;      /* Keymap size */
+       unsigned repeat:1;              /* Enable key repeat */
+       unsigned en_keylock:1;          /* Enable Key Lock feature */
+       unsigned short unlock_key1;     /* Unlock Key 1 */
+       unsigned short unlock_key2;     /* Unlock Key 2 */
+};
+
+#endif
diff --git a/include/linux/i2c/mcs5000_ts.h b/include/linux/i2c/mcs5000_ts.h
new file mode 100644 (file)
index 0000000..5a117b5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * mcs5000_ts.h
+ *
+ * Copyright (C) 2009 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ *  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.
+ *
+ */
+
+#ifndef __LINUX_MCS5000_TS_H
+#define __LINUX_MCS5000_TS_H
+
+/* platform data for the MELFAS MCS-5000 touchscreen driver */
+struct mcs5000_ts_platform_data {
+       void (*cfg_pin)(void);
+       int x_size;
+       int y_size;
+};
+
+#endif /* __LINUX_MCS5000_TS_H */
index 7907a72403eeddbfa8612ac492598bf811bcf9d4..60c3360ef6adf633416b51773d828623851afca0 100644 (file)
@@ -7,6 +7,7 @@
  * the Free Software Foundation.
  */
 
+#include <linux/types.h>
 
 /*
  * Standard commands.
 #define I8042_CMD_MUX_PFX      0x0090
 #define I8042_CMD_MUX_SEND     0x1090
 
+struct serio;
+
+#if defined(CONFIG_SERIO_I8042) || defined(CONFIG_SERIO_I8042_MODULE)
+
+void i8042_lock_chip(void);
+void i8042_unlock_chip(void);
 int i8042_command(unsigned char *param, int command);
+bool i8042_check_port_owner(const struct serio *);
+
+#else
+
+void i8042_lock_chip(void)
+{
+}
+
+void i8042_unlock_chip(void)
+{
+}
+
+int i8042_command(unsigned char *param, int command)
+{
+       return -ENOSYS;
+}
+
+bool i8042_check_port_owner(const struct serio *serio)
+{
+       return false;
+}
+
+#endif
 
 #endif
index 8b3bc3e0d1463a21a9bb8b71908d3c15dfd4dfb3..0ccfc30cd40f7696e0b9e863272f82fb8e42e0f0 100644 (file)
@@ -1123,7 +1123,7 @@ struct input_dev {
        struct mutex mutex;
 
        unsigned int users;
-       int going_away;
+       bool going_away;
 
        struct device dev;
 
index fcf5fbe6a50c3596be52388d74e210d6b4c38231..79603a6c356fb5dd28f2bddf27bceafbf263c7d2 100644 (file)
@@ -44,6 +44,8 @@ struct ps2dev {
 void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
 int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
 void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
+void ps2_begin_command(struct ps2dev *ps2dev);
+void ps2_end_command(struct ps2dev *ps2dev);
 int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
 int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);