Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Jan 2012 18:55:52 +0000 (10:55 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Jan 2012 18:55:52 +0000 (10:55 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (64 commits)
  Input: tc3589x-keypad - add missing kerneldoc
  Input: ucb1400-ts - switch to using dev_xxx() for diagnostic messages
  Input: ucb1400_ts - convert to threaded IRQ
  Input: ucb1400_ts - drop inline annotations
  Input: usb1400_ts - add __devinit/__devexit section annotations
  Input: ucb1400_ts - set driver owner
  Input: ucb1400_ts - convert to use dev_pm_ops
  Input: psmouse - make sure we do not use stale methods
  Input: evdev - do not block waiting for an event if fd is nonblock
  Input: evdev - if no events and non-block, return EAGAIN not 0
  Input: evdev - only allow reading events if a full packet is present
  Input: add driver for pixcir i2c touchscreens
  Input: samsung-keypad - implement runtime power management support
  Input: tegra-kbc - report wakeup key for some platforms
  Input: tegra-kbc - add device tree bindings
  Input: add driver for AUO In-Cell touchscreens using pixcir ICs
  Input: mpu3050 - configure the sampling method
  Input: mpu3050 - ensure we enable interrupts
  Input: mpu3050 - add of_match table for device-tree probing
  Input: sentelic - document the latest hardware
  ...

Fix up fairly trivial conflicts (device tree matching conflicting with
some independent cleanups) in drivers/input/keyboard/samsung-keypad.c

1  2 
drivers/input/keyboard/samsung-keypad.c
drivers/input/misc/ati_remote2.c
drivers/input/tablet/aiptek.c
drivers/input/tablet/wacom_sys.c
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/zylonite-wm97xx.c

  #include <linux/io.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
+ #include <linux/pm.h>
+ #include <linux/pm_runtime.h>
  #include <linux/slab.h>
 +#include <linux/of.h>
 +#include <linux/of_gpio.h>
  #include <linux/sched.h>
- #include <plat/keypad.h>
+ #include <linux/input/samsung-keypad.h>
  
  #define SAMSUNG_KEYIFCON                      0x00
  #define SAMSUNG_KEYIFSTSCLR                   0x04
@@@ -65,31 -65,38 +67,33 @@@ enum samsung_keypad_type 
  
  struct samsung_keypad {
        struct input_dev *input_dev;
+       struct platform_device *pdev;
        struct clk *clk;
        void __iomem *base;
        wait_queue_head_t wait;
        bool stopped;
+       bool wake_enabled;
        int irq;
 +      enum samsung_keypad_type type;
        unsigned int row_shift;
        unsigned int rows;
        unsigned int cols;
        unsigned int row_state[SAMSUNG_MAX_COLS];
 +#ifdef CONFIG_OF
 +      int row_gpios[SAMSUNG_MAX_ROWS];
 +      int col_gpios[SAMSUNG_MAX_COLS];
 +#endif
        unsigned short keycodes[];
  };
  
 -static int samsung_keypad_is_s5pv210(struct device *dev)
 -{
 -      struct platform_device *pdev = to_platform_device(dev);
 -      enum samsung_keypad_type type =
 -              platform_get_device_id(pdev)->driver_data;
 -
 -      return type == KEYPAD_TYPE_S5PV210;
 -}
 -
  static void samsung_keypad_scan(struct samsung_keypad *keypad,
                                unsigned int *row_state)
  {
 -      struct device *dev = keypad->input_dev->dev.parent;
        unsigned int col;
        unsigned int val;
  
        for (col = 0; col < keypad->cols; col++) {
 -              if (samsung_keypad_is_s5pv210(dev)) {
 +              if (keypad->type == KEYPAD_TYPE_S5PV210) {
                        val = S5PV210_KEYIFCOLEN_MASK;
                        val &= ~(1 << col) << 8;
                } else {
@@@ -155,6 -162,8 +159,8 @@@ static irqreturn_t samsung_keypad_irq(i
        unsigned int val;
        bool key_down;
  
+       pm_runtime_get_sync(&keypad->pdev->dev);
        do {
                val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
                /* Clear interrupt. */
  
        } while (key_down && !keypad->stopped);
  
+       pm_runtime_put_sync(&keypad->pdev->dev);
        return IRQ_HANDLED;
  }
  
@@@ -176,6 -187,8 +184,8 @@@ static void samsung_keypad_start(struc
  {
        unsigned int val;
  
+       pm_runtime_get_sync(&keypad->pdev->dev);
        /* Tell IRQ thread that it may poll the device. */
        keypad->stopped = false;
  
  
        /* KEYIFCOL reg clear. */
        writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+       pm_runtime_put_sync(&keypad->pdev->dev);
  }
  
  static void samsung_keypad_stop(struct samsung_keypad *keypad)
  {
        unsigned int val;
  
+       pm_runtime_get_sync(&keypad->pdev->dev);
        /* Signal IRQ thread to stop polling and disable the handler. */
        keypad->stopped = true;
        wake_up(&keypad->wait);
         * re-enable the handler.
         */
        enable_irq(keypad->irq);
+       pm_runtime_put_sync(&keypad->pdev->dev);
  }
  
  static int samsung_keypad_open(struct input_dev *input_dev)
@@@ -232,126 -251,6 +248,126 @@@ static void samsung_keypad_close(struc
        samsung_keypad_stop(keypad);
  }
  
 +#ifdef CONFIG_OF
 +static struct samsung_keypad_platdata *samsung_keypad_parse_dt(
 +                              struct device *dev)
 +{
 +      struct samsung_keypad_platdata *pdata;
 +      struct matrix_keymap_data *keymap_data;
 +      uint32_t *keymap, num_rows = 0, num_cols = 0;
 +      struct device_node *np = dev->of_node, *key_np;
 +      unsigned int key_count = 0;
 +
 +      pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 +      if (!pdata) {
 +              dev_err(dev, "could not allocate memory for platform data\n");
 +              return NULL;
 +      }
 +
 +      of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows);
 +      of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols);
 +      if (!num_rows || !num_cols) {
 +              dev_err(dev, "number of keypad rows/columns not specified\n");
 +              return NULL;
 +      }
 +      pdata->rows = num_rows;
 +      pdata->cols = num_cols;
 +
 +      keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL);
 +      if (!keymap_data) {
 +              dev_err(dev, "could not allocate memory for keymap data\n");
 +              return NULL;
 +      }
 +      pdata->keymap_data = keymap_data;
 +
 +      for_each_child_of_node(np, key_np)
 +              key_count++;
 +
 +      keymap_data->keymap_size = key_count;
 +      keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL);
 +      if (!keymap) {
 +              dev_err(dev, "could not allocate memory for keymap\n");
 +              return NULL;
 +      }
 +      keymap_data->keymap = keymap;
 +
 +      for_each_child_of_node(np, key_np) {
 +              u32 row, col, key_code;
 +              of_property_read_u32(key_np, "keypad,row", &row);
 +              of_property_read_u32(key_np, "keypad,column", &col);
 +              of_property_read_u32(key_np, "linux,code", &key_code);
 +              *keymap++ = KEY(row, col, key_code);
 +      }
 +
 +      if (of_get_property(np, "linux,input-no-autorepeat", NULL))
 +              pdata->no_autorepeat = true;
 +      if (of_get_property(np, "linux,input-wakeup", NULL))
 +              pdata->wakeup = true;
 +
 +      return pdata;
 +}
 +
 +static void samsung_keypad_parse_dt_gpio(struct device *dev,
 +                              struct samsung_keypad *keypad)
 +{
 +      struct device_node *np = dev->of_node;
 +      int gpio, ret, row, col;
 +
 +      for (row = 0; row < keypad->rows; row++) {
 +              gpio = of_get_named_gpio(np, "row-gpios", row);
 +              keypad->row_gpios[row] = gpio;
 +              if (!gpio_is_valid(gpio)) {
 +                      dev_err(dev, "keypad row[%d]: invalid gpio %d\n",
 +                                      row, gpio);
 +                      continue;
 +              }
 +
 +              ret = gpio_request(gpio, "keypad-row");
 +              if (ret)
 +                      dev_err(dev, "keypad row[%d] gpio request failed\n",
 +                                      row);
 +      }
 +
 +      for (col = 0; col < keypad->cols; col++) {
 +              gpio = of_get_named_gpio(np, "col-gpios", col);
 +              keypad->col_gpios[col] = gpio;
 +              if (!gpio_is_valid(gpio)) {
 +                      dev_err(dev, "keypad column[%d]: invalid gpio %d\n",
 +                                      col, gpio);
 +                      continue;
 +              }
 +
 +              ret = gpio_request(gpio, "keypad-col");
 +              if (ret)
 +                      dev_err(dev, "keypad column[%d] gpio request failed\n",
 +                                      col);
 +      }
 +}
 +
 +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
 +{
 +      int cnt;
 +
 +      for (cnt = 0; cnt < keypad->rows; cnt++)
 +              if (gpio_is_valid(keypad->row_gpios[cnt]))
 +                      gpio_free(keypad->row_gpios[cnt]);
 +
 +      for (cnt = 0; cnt < keypad->cols; cnt++)
 +              if (gpio_is_valid(keypad->col_gpios[cnt]))
 +                      gpio_free(keypad->col_gpios[cnt]);
 +}
 +#else
 +static
 +struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
 +{
 +      return NULL;
 +}
 +
 +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
 +{
 +}
 +#endif
 +
  static int __devinit samsung_keypad_probe(struct platform_device *pdev)
  {
        const struct samsung_keypad_platdata *pdata;
        unsigned int keymap_size;
        int error;
  
 -      pdata = pdev->dev.platform_data;
 +      if (pdev->dev.of_node)
 +              pdata = samsung_keypad_parse_dt(&pdev->dev);
 +      else
 +              pdata = pdev->dev.platform_data;
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data defined\n");
                return -EINVAL;
        }
  
        keypad->input_dev = input_dev;
+       keypad->pdev = pdev;
        keypad->row_shift = row_shift;
        keypad->rows = pdata->rows;
        keypad->cols = pdata->cols;
+       keypad->stopped = true;
        init_waitqueue_head(&keypad->wait);
  
 +      if (pdev->dev.of_node) {
 +#ifdef CONFIG_OF
 +              samsung_keypad_parse_dt_gpio(&pdev->dev, keypad);
 +              keypad->type = of_device_is_compatible(pdev->dev.of_node,
 +                                      "samsung,s5pv210-keypad");
 +#endif
 +      } else {
 +              keypad->type = platform_get_device_id(pdev)->driver_data;
 +      }
 +
        input_dev->name = pdev->name;
        input_dev->id.bustype = BUS_HOST;
        input_dev->dev.parent = &pdev->dev;
                goto err_put_clk;
        }
  
+       device_init_wakeup(&pdev->dev, pdata->wakeup);
+       platform_set_drvdata(pdev, keypad);
+       pm_runtime_enable(&pdev->dev);
        error = input_register_device(keypad->input_dev);
        if (error)
                goto err_free_irq;
  
-       device_init_wakeup(&pdev->dev, pdata->wakeup);
-       platform_set_drvdata(pdev, keypad);
 +      if (pdev->dev.of_node) {
 +              devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap);
 +              devm_kfree(&pdev->dev, (void *)pdata->keymap_data);
 +              devm_kfree(&pdev->dev, (void *)pdata);
 +      }
        return 0;
  
  err_free_irq:
        free_irq(keypad->irq, keypad);
+       pm_runtime_disable(&pdev->dev);
+       device_init_wakeup(&pdev->dev, 0);
+       platform_set_drvdata(pdev, NULL);
  err_put_clk:
        clk_put(keypad->clk);
 +      samsung_keypad_dt_gpio_free(keypad);
  err_unmap_base:
        iounmap(keypad->base);
  err_free_mem:
@@@ -499,6 -385,7 +521,7 @@@ static int __devexit samsung_keypad_rem
  {
        struct samsung_keypad *keypad = platform_get_drvdata(pdev);
  
+       pm_runtime_disable(&pdev->dev);
        device_init_wakeup(&pdev->dev, 0);
        platform_set_drvdata(pdev, NULL);
  
        free_irq(keypad->irq, keypad);
  
        clk_put(keypad->clk);
 +      samsung_keypad_dt_gpio_free(keypad);
  
        iounmap(keypad->base);
        kfree(keypad);
        return 0;
  }
  
- #ifdef CONFIG_PM
+ #ifdef CONFIG_PM_RUNTIME
+ static int samsung_keypad_runtime_suspend(struct device *dev)
+ {
+       struct platform_device *pdev = to_platform_device(dev);
+       struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+       unsigned int val;
+       int error;
+       if (keypad->stopped)
+               return 0;
+       /* This may fail on some SoCs due to lack of controller support */
+       error = enable_irq_wake(keypad->irq);
+       if (!error)
+               keypad->wake_enabled = true;
+       val = readl(keypad->base + SAMSUNG_KEYIFCON);
+       val |= SAMSUNG_KEYIFCON_WAKEUPEN;
+       writel(val, keypad->base + SAMSUNG_KEYIFCON);
+       clk_disable(keypad->clk);
+       return 0;
+ }
+ static int samsung_keypad_runtime_resume(struct device *dev)
+ {
+       struct platform_device *pdev = to_platform_device(dev);
+       struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+       unsigned int val;
+       if (keypad->stopped)
+               return 0;
+       clk_enable(keypad->clk);
+       val = readl(keypad->base + SAMSUNG_KEYIFCON);
+       val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
+       writel(val, keypad->base + SAMSUNG_KEYIFCON);
+       if (keypad->wake_enabled)
+               disable_irq_wake(keypad->irq);
+       return 0;
+ }
+ #endif
+ #ifdef CONFIG_PM_SLEEP
  static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
                                         bool enable)
  {
-       struct device *dev = keypad->input_dev->dev.parent;
        unsigned int val;
  
        clk_enable(keypad->clk);
        val = readl(keypad->base + SAMSUNG_KEYIFCON);
        if (enable) {
                val |= SAMSUNG_KEYIFCON_WAKEUPEN;
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(&keypad->pdev->dev))
                        enable_irq_wake(keypad->irq);
        } else {
                val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
-               if (device_may_wakeup(dev))
+               if (device_may_wakeup(&keypad->pdev->dev))
                        disable_irq_wake(keypad->irq);
        }
        writel(val, keypad->base + SAMSUNG_KEYIFCON);
@@@ -578,24 -510,14 +647,25 @@@ static int samsung_keypad_resume(struc
  
        return 0;
  }
+ #endif
  
  static const struct dev_pm_ops samsung_keypad_pm_ops = {
-       .suspend        = samsung_keypad_suspend,
-       .resume         = samsung_keypad_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend, samsung_keypad_resume)
+       SET_RUNTIME_PM_OPS(samsung_keypad_runtime_suspend,
+                          samsung_keypad_runtime_resume, NULL)
  };
- #endif
  
 +#ifdef CONFIG_OF
 +static const struct of_device_id samsung_keypad_dt_match[] = {
 +      { .compatible = "samsung,s3c6410-keypad" },
 +      { .compatible = "samsung,s5pv210-keypad" },
 +      {},
 +};
 +MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
 +#else
 +#define samsung_keypad_dt_match NULL
 +#endif
 +
  static struct platform_device_id samsung_keypad_driver_ids[] = {
        {
                .name           = "samsung-keypad",
@@@ -614,28 -536,13 +684,14 @@@ static struct platform_driver samsung_k
        .driver         = {
                .name   = "samsung-keypad",
                .owner  = THIS_MODULE,
- #ifdef CONFIG_PM
 +              .of_match_table = samsung_keypad_dt_match,
                .pm     = &samsung_keypad_pm_ops,
- #endif
        },
        .id_table       = samsung_keypad_driver_ids,
  };
- static int __init samsung_keypad_init(void)
- {
-       return platform_driver_register(&samsung_keypad_driver);
- }
- module_init(samsung_keypad_init);
- static void __exit samsung_keypad_exit(void)
- {
-       platform_driver_unregister(&samsung_keypad_driver);
- }
- module_exit(samsung_keypad_exit);
+ module_platform_driver(samsung_keypad_driver);
  
  MODULE_DESCRIPTION("Samsung keypad driver");
  MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
  MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
  MODULE_LICENSE("GPL");
- MODULE_ALIAS("platform:samsung-keypad");
@@@ -42,13 -42,13 +42,13 @@@ static int ati_remote2_set_mask(const c
                                const struct kernel_param *kp,
                                unsigned int max)
  {
-       unsigned long mask;
+       unsigned int mask;
        int ret;
  
        if (!val)
                return -EINVAL;
  
-       ret = strict_strtoul(val, 0, &mask);
+       ret = kstrtouint(val, 0, &mask);
        if (ret)
                return ret;
  
@@@ -720,11 -720,12 +720,12 @@@ static ssize_t ati_remote2_store_channe
        struct usb_device *udev = to_usb_device(dev);
        struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
        struct ati_remote2 *ar2 = usb_get_intfdata(intf);
-       unsigned long mask;
+       unsigned int mask;
        int r;
  
-       if (strict_strtoul(buf, 0, &mask))
-               return -EINVAL;
+       r = kstrtouint(buf, 0, &mask);
+       if (r)
+               return r;
  
        if (mask & ~ATI_REMOTE2_MAX_CHANNEL_MASK)
                return -EINVAL;
@@@ -769,10 -770,12 +770,12 @@@ static ssize_t ati_remote2_store_mode_m
        struct usb_device *udev = to_usb_device(dev);
        struct usb_interface *intf = usb_ifnum_to_if(udev, 0);
        struct ati_remote2 *ar2 = usb_get_intfdata(intf);
-       unsigned long mask;
+       unsigned int mask;
+       int err;
  
-       if (strict_strtoul(buf, 0, &mask))
-               return -EINVAL;
+       err = kstrtouint(buf, 0, &mask);
+       if (err)
+               return err;
  
        if (mask & ~ATI_REMOTE2_MAX_MODE_MASK)
                return -EINVAL;
@@@ -1010,4 -1013,23 +1013,4 @@@ static int ati_remote2_post_reset(struc
        return r;
  }
  
 -static int __init ati_remote2_init(void)
 -{
 -      int r;
 -
 -      r = usb_register(&ati_remote2_driver);
 -      if (r)
 -              printk(KERN_ERR "ati_remote2: usb_register() = %d\n", r);
 -      else
 -              printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n");
 -
 -      return r;
 -}
 -
 -static void __exit ati_remote2_exit(void)
 -{
 -      usb_deregister(&ati_remote2_driver);
 -}
 -
 -module_init(ati_remote2_init);
 -module_exit(ati_remote2_exit);
 +module_usb_driver(ati_remote2_driver);
@@@ -1198,9 -1198,9 +1198,9 @@@ static ssize_
  store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       long x;
+       int x;
  
-       if (strict_strtol(buf, 10, &x)) {
+       if (kstrtoint(buf, 10, &x)) {
                size_t len = buf[count - 1] == '\n' ? count - 1 : count;
  
                if (strncmp(buf, "disable", len))
@@@ -1240,9 -1240,9 +1240,9 @@@ static ssize_
  store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       long y;
+       int y;
  
-       if (strict_strtol(buf, 10, &y)) {
+       if (kstrtoint(buf, 10, &y)) {
                size_t len = buf[count - 1] == '\n' ? count - 1 : count;
  
                if (strncmp(buf, "disable", len))
@@@ -1277,12 -1277,13 +1277,13 @@@ static ssize_
  store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       long j;
+       int err, j;
  
-       if (strict_strtol(buf, 10, &j))
-               return -EINVAL;
+       err = kstrtoint(buf, 10, &j);
+       if (err)
+               return err;
  
-       aiptek->newSetting.jitterDelay = (int)j;
+       aiptek->newSetting.jitterDelay = j;
        return count;
  }
  
@@@ -1306,12 -1307,13 +1307,13 @@@ static ssize_
  store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       long d;
+       int err, d;
  
-       if (strict_strtol(buf, 10, &d))
-               return -EINVAL;
+       err = kstrtoint(buf, 10, &d);
+       if (err)
+               return err;
  
-       aiptek->newSetting.programmableDelay = (int)d;
+       aiptek->newSetting.programmableDelay = d;
        return count;
  }
  
@@@ -1557,11 -1559,13 +1559,13 @@@ static ssize_
  store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
  {
        struct aiptek *aiptek = dev_get_drvdata(dev);
-       long w;
+       int err, w;
  
-       if (strict_strtol(buf, 10, &w)) return -EINVAL;
+       err = kstrtoint(buf, 10, &w);
+       if (err)
+               return err;
  
-       aiptek->newSetting.wheel = (int)w;
+       aiptek->newSetting.wheel = w;
        return count;
  }
  
@@@ -1919,7 -1923,21 +1923,7 @@@ static struct usb_driver aiptek_driver 
        .id_table = aiptek_ids,
  };
  
 -static int __init aiptek_init(void)
 -{
 -      int result = usb_register(&aiptek_driver);
 -      if (result == 0) {
 -              printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
 -                     DRIVER_DESC "\n");
 -              printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_AUTHOR "\n");
 -      }
 -      return result;
 -}
 -
 -static void __exit aiptek_exit(void)
 -{
 -      usb_deregister(&aiptek_driver);
 -}
 +module_usb_driver(aiptek_driver);
  
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);
@@@ -1929,3 -1947,6 +1933,3 @@@ module_param(programmableDelay, int, 0)
  MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming");
  module_param(jitterDelay, int, 0);
  MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay");
 -
 -module_init(aiptek_init);
 -module_exit(aiptek_exit);
@@@ -28,7 -28,9 +28,9 @@@
  #define HID_USAGE_Y_TILT              0x3e
  #define HID_USAGE_FINGER              0x22
  #define HID_USAGE_STYLUS              0x20
- #define HID_COLLECTION                        0xc0
+ #define HID_COLLECTION                        0xa1
+ #define HID_COLLECTION_LOGICAL                0x02
+ #define HID_COLLECTION_END            0xc0
  
  enum {
        WCM_UNDEFINED = 0,
@@@ -66,7 -68,8 +68,8 @@@ static int wacom_get_report(struct usb_
        do {
                retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                                USB_REQ_GET_REPORT,
-                               USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                               USB_DIR_IN | USB_TYPE_CLASS |
+                               USB_RECIP_INTERFACE,
                                (type << 8) + id,
                                intf->altsetting[0].desc.bInterfaceNumber,
                                buf, size, 100);
@@@ -164,7 -167,70 +167,70 @@@ static void wacom_close(struct input_de
                usb_autopm_put_interface(wacom->intf);
  }
  
- static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hid_desc,
+ static int wacom_parse_logical_collection(unsigned char *report,
+                                         struct wacom_features *features)
+ {
+       int length = 0;
+       if (features->type == BAMBOO_PT) {
+               /* Logical collection is only used by 3rd gen Bamboo Touch */
+               features->pktlen = WACOM_PKGLEN_BBTOUCH3;
+               features->device_type = BTN_TOOL_DOUBLETAP;
+               /*
+                * Stylus and Touch have same active area
+                * so compute physical size based on stylus
+                * data before its overwritten.
+                */
+               features->x_phy =
+                       (features->x_max * features->x_resolution) / 100;
+               features->y_phy =
+                       (features->y_max * features->y_resolution) / 100;
+               features->x_max = features->y_max =
+                       get_unaligned_le16(&report[10]);
+               length = 11;
+       }
+       return length;
+ }
+ /*
+  * Interface Descriptor of wacom devices can be incomplete and
+  * inconsistent so wacom_features table is used to store stylus
+  * device's packet lengths, various maximum values, and tablet
+  * resolution based on product ID's.
+  *
+  * For devices that contain 2 interfaces, wacom_features table is
+  * inaccurate for the touch interface.  Since the Interface Descriptor
+  * for touch interfaces has pretty complete data, this function exists
+  * to query tablet for this missing information instead of hard coding in
+  * an additional table.
+  *
+  * A typical Interface Descriptor for a stylus will contain a
+  * boot mouse application collection that is not of interest and this
+  * function will ignore it.
+  *
+  * It also contains a digitizer application collection that also is not
+  * of interest since any information it contains would be duplicate
+  * of what is in wacom_features. Usually it defines a report of an array
+  * of bytes that could be used as max length of the stylus packet returned.
+  * If it happens to define a Digitizer-Stylus Physical Collection then
+  * the X and Y logical values contain valid data but it is ignored.
+  *
+  * A typical Interface Descriptor for a touch interface will contain a
+  * Digitizer-Finger Physical Collection which will define both logical
+  * X/Y maximum as well as the physical size of tablet. Since touch
+  * interfaces haven't supported pressure or distance, this is enough
+  * information to override invalid values in the wacom_features table.
+  *
+  * 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.
+  */
+ static int wacom_parse_hid(struct usb_interface *intf,
+                          struct hid_descriptor *hid_desc,
                           struct wacom_features *features)
  {
        struct usb_device *dev = interface_to_usbdev(intf);
                                                /* penabled only accepts exact bytes of data */
                                                if (features->type == TABLETPC2FG)
                                                        features->pktlen = WACOM_PKGLEN_GRAPHIRE;
-                                               if (features->type == BAMBOO_PT)
-                                                       features->pktlen = WACOM_PKGLEN_BBFUN;
                                                features->device_type = BTN_TOOL_PEN;
                                                features->x_max =
                                                        get_unaligned_le16(&report[i + 3]);
                                                /* penabled only accepts exact bytes of data */
                                                if (features->type == TABLETPC2FG)
                                                        features->pktlen = WACOM_PKGLEN_GRAPHIRE;
-                                               if (features->type == BAMBOO_PT)
-                                                       features->pktlen = WACOM_PKGLEN_BBFUN;
                                                features->device_type = BTN_TOOL_PEN;
                                                features->y_max =
                                                        get_unaligned_le16(&report[i + 3]);
                                i++;
                                break;
  
+                       /*
+                        * Requiring Stylus Usage will ignore boot mouse
+                        * X/Y values and some cases of invalid Digitizer X/Y
+                        * values commonly reported.
+                        */
                        case HID_USAGE_STYLUS:
                                pen = 1;
                                i++;
                        }
                        break;
  
-               case HID_COLLECTION:
+               case HID_COLLECTION_END:
                        /* reset UsagePage and Finger */
                        finger = usage = 0;
                        break;
+               case HID_COLLECTION:
+                       i++;
+                       switch (report[i]) {
+                       case HID_COLLECTION_LOGICAL:
+                               i += wacom_parse_logical_collection(&report[i],
+                                                                   features);
+                               break;
+                       }
+                       break;
                }
        }
  
@@@ -348,7 -425,8 +425,8 @@@ static int wacom_query_tablet_data(stru
                                                WAC_HID_FEATURE_REPORT,
                                                report_id, rep_data, 4, 1);
                } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
-       } else if (features->type != TABLETPC) {
+       } else if (features->type != TABLETPC &&
+                  features->device_type == BTN_TOOL_PEN) {
                do {
                        rep_data[0] = 2;
                        rep_data[1] = 2;
@@@ -485,7 -563,8 +563,8 @@@ static int wacom_led_control(struct wac
        if (!buf)
                return -ENOMEM;
  
-       if (wacom->wacom_wac.features.type == WACOM_21UX2)
+       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;
@@@ -704,6 -783,7 +783,7 @@@ static int wacom_initialize_leds(struc
                                           &intuos4_led_attr_group);
                break;
  
+       case WACOM_24HD:
        case WACOM_21UX2:
                wacom->led.select[0] = 0;
                wacom->led.select[1] = 0;
@@@ -738,6 -818,7 +818,7 @@@ static void wacom_destroy_leds(struct w
                                   &intuos4_led_attr_group);
                break;
  
+       case WACOM_24HD:
        case WACOM_21UX2:
                sysfs_remove_group(&wacom->intf->dev.kobj,
                                   &cintiq_led_attr_group);
@@@ -919,4 -1000,21 +1000,4 @@@ static struct usb_driver wacom_driver 
        .supports_autosuspend = 1,
  };
  
 -static int __init wacom_init(void)
 -{
 -      int result;
 -
 -      result = usb_register(&wacom_driver);
 -      if (result == 0)
 -              printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
 -                     DRIVER_DESC "\n");
 -      return result;
 -}
 -
 -static void __exit wacom_exit(void)
 -{
 -      usb_deregister(&wacom_driver);
 -}
 -
 -module_init(wacom_init);
 -module_exit(wacom_exit);
 +module_usb_driver(wacom_driver);
@@@ -488,10 -488,10 +488,10 @@@ static ssize_t ad7877_disable_store(str
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
-       unsigned long val;
+       unsigned int val;
        int error;
  
-       error = strict_strtoul(buf, 10, &val);
+       error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -518,10 -518,10 +518,10 @@@ static ssize_t ad7877_dac_store(struct 
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
-       unsigned long val;
+       unsigned int val;
        int error;
  
-       error = strict_strtoul(buf, 10, &val);
+       error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -548,10 -548,10 +548,10 @@@ static ssize_t ad7877_gpio3_store(struc
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
-       unsigned long val;
+       unsigned int val;
        int error;
  
-       error = strict_strtoul(buf, 10, &val);
+       error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -579,10 -579,10 +579,10 @@@ static ssize_t ad7877_gpio4_store(struc
                                     const char *buf, size_t count)
  {
        struct ad7877 *ts = dev_get_drvdata(dev);
-       unsigned long val;
+       unsigned int val;
        int error;
  
-       error = strict_strtoul(buf, 10, &val);
+       error = kstrtouint(buf, 10, &val);
        if (error)
                return error;
  
@@@ -612,10 -612,10 +612,10 @@@ static struct attribute *ad7877_attribu
        NULL
  };
  
 -static mode_t ad7877_attr_is_visible(struct kobject *kobj,
 +static umode_t ad7877_attr_is_visible(struct kobject *kobj,
                                     struct attribute *attr, int n)
  {
 -      mode_t mode = attr->mode;
 +      umode_t mode = attr->mode;
  
        if (attr == &dev_attr_aux3.attr) {
                if (gpio3)
@@@ -853,7 -853,6 +853,6 @@@ static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7
  static struct spi_driver ad7877_driver = {
        .driver = {
                .name   = "ad7877",
-               .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
                .pm     = &ad7877_pm,
        },
@@@ -16,6 -16,7 +16,7 @@@
   *  - JASTEC USB touch controller/DigiTech DTR-02U
   *  - Zytronic capacitive touchscreen
   *  - NEXIO/iNexio
+  *  - Elo TouchSystems 2700 IntelliTouch
   *
   * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
   * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@@ -138,6 -139,7 +139,7 @@@ enum 
        DEVTYPE_ZYTRONIC,
        DEVTYPE_TC45USB,
        DEVTYPE_NEXIO,
+       DEVTYPE_ELO,
  };
  
  #define USB_DEVICE_HID_CLASS(vend, prod) \
@@@ -239,6 -241,10 +241,10 @@@ static const struct usb_device_id usbto
                .driver_info = DEVTYPE_NEXIO},
  #endif
  
+ #ifdef CONFIG_TOUCHSCREEN_USB_ELO
+       {USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
+ #endif
        {}
  };
  
@@@ -945,6 -951,24 +951,24 @@@ static int nexio_read_data(struct usbto
  
  
  /*****************************************************************************
+  * ELO part
+  */
+ #ifdef CONFIG_TOUCHSCREEN_USB_ELO
+ static int elo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+ {
+       dev->x = (pkt[3] << 8) | pkt[2];
+       dev->y = (pkt[5] << 8) | pkt[4];
+       dev->touch = pkt[6] > 0;
+       dev->press = pkt[6];
+       return 1;
+ }
+ #endif
+ /*****************************************************************************
   * the different device descriptors
   */
  #ifdef MULTI_PACKET
@@@ -953,6 -977,18 +977,18 @@@ static void usbtouch_process_multi(stru
  #endif
  
  static struct usbtouch_device_info usbtouch_dev_info[] = {
+ #ifdef CONFIG_TOUCHSCREEN_USB_ELO
+       [DEVTYPE_ELO] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x0fff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x0fff,
+               .max_press      = 0xff,
+               .rept_size      = 8,
+               .read_data      = elo_read_data,
+       },
+ #endif
  #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
        [DEVTYPE_EGALAX] = {
                .min_xc         = 0x0,
@@@ -1580,7 -1616,18 +1616,7 @@@ static struct usb_driver usbtouch_drive
        .supports_autosuspend = 1,
  };
  
 -static int __init usbtouch_init(void)
 -{
 -      return usb_register(&usbtouch_driver);
 -}
 -
 -static void __exit usbtouch_cleanup(void)
 -{
 -      usb_deregister(&usbtouch_driver);
 -}
 -
 -module_init(usbtouch_init);
 -module_exit(usbtouch_cleanup);
 +module_usb_driver(usbtouch_driver);
  
  MODULE_AUTHOR(DRIVER_AUTHOR);
  MODULE_DESCRIPTION(DRIVER_DESC);
@@@ -22,7 -22,6 +22,7 @@@
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/delay.h>
 +#include <linux/gpio.h>
  #include <linux/irq.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
@@@ -193,8 -192,8 +193,8 @@@ static int zylonite_wm97xx_probe(struc
        else
                gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26);
  
 -      wm->pen_irq = IRQ_GPIO(gpio_touch_irq);
 -      irq_set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH);
 +      wm->pen_irq = gpio_to_irq(gpio_touch_irq);
 +      irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
  
        wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
                           WM97XX_GPIO_POL_HIGH,
@@@ -224,19 -223,7 +224,7 @@@ static struct platform_driver zylonite_
                .name   = "wm97xx-touch",
        },
  };
- static int __init zylonite_wm97xx_init(void)
- {
-       return platform_driver_register(&zylonite_wm97xx_driver);
- }
- static void __exit zylonite_wm97xx_exit(void)
- {
-       platform_driver_unregister(&zylonite_wm97xx_driver);
- }
- module_init(zylonite_wm97xx_init);
- module_exit(zylonite_wm97xx_exit);
+ module_platform_driver(zylonite_wm97xx_driver);
  
  /* Module information */
  MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");