OSDN Git Service

Merge branch 'next' into for-linus
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 22 Jun 2015 16:26:29 +0000 (09:26 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 22 Jun 2015 16:26:29 +0000 (09:26 -0700)
Prepare first round of input updates for 4.2 merge window.

53 files changed:
Documentation/devicetree/bindings/i2c/trivial-devices.txt
Documentation/devicetree/bindings/input/ti,drv2665.txt [new file with mode: 0644]
Documentation/leds/leds-class.txt
MAINTAINERS
drivers/input/Kconfig
drivers/input/Makefile
drivers/input/evdev.c
drivers/input/ff-core.c
drivers/input/input-leds.c [new file with mode: 0644]
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/adp5589-keys.c
drivers/input/keyboard/clps711x-keypad.c
drivers/input/keyboard/max7359_keypad.c
drivers/input/keyboard/samsung-keypad.c
drivers/input/keyboard/spear-keyboard.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/adxl34x-i2c.c
drivers/input/misc/da9063_onkey.c [new file with mode: 0644]
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c [new file with mode: 0644]
drivers/input/misc/gpio-beeper.c
drivers/input/misc/retu-pwrbutton.c
drivers/input/misc/soc_button_array.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/misc/twl6040-vibra.c
drivers/input/misc/wm831x-on.c
drivers/input/mouse/alps.c
drivers/input/mouse/alps.h
drivers/input/mouse/cyapa_gen3.c
drivers/input/mouse/cyapa_gen5.c
drivers/input/mouse/elan_i2c.h
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elan_i2c_i2c.c
drivers/input/mouse/elan_i2c_smbus.c
drivers/input/mouse/focaltech.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/sentelic.h
drivers/input/mouse/synaptics_i2c.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/cyttsp4_core.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/stmpe-ts.c
drivers/input/touchscreen/zforce_ts.c
drivers/leds/Kconfig
drivers/tty/sysrq.c
drivers/tty/vt/keyboard.c
include/linux/mfd/da9063/pdata.h
include/linux/mfd/stmpe.h
include/linux/platform_data/keyboard-spear.h

index aaa8325..03db591 100644 (file)
@@ -19,8 +19,7 @@ adi,adt7475           +/-1C TDM Extended Temp Range I.C
 adi,adt7476            +/-1C TDM Extended Temp Range I.C
 adi,adt7490            +/-1C TDM Extended Temp Range I.C
 adi,adxl345            Three-Axis Digital Accelerometer
-adi,adxl346            Three-Axis Digital Accelerometer
-adi,adxl34x            Three-Axis Digital Accelerometer
+adi,adxl346            Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
 at,24c08               i2c serial eeprom  (24cxx)
 atmel,24c00            i2c serial eeprom  (24cxx)
 atmel,24c01            i2c serial eeprom  (24cxx)
diff --git a/Documentation/devicetree/bindings/input/ti,drv2665.txt b/Documentation/devicetree/bindings/input/ti,drv2665.txt
new file mode 100644 (file)
index 0000000..1ba97ac
--- /dev/null
@@ -0,0 +1,17 @@
+* Texas Instruments - drv2665 Haptics driver
+
+Required properties:
+       - compatible - "ti,drv2665" - DRV2665
+       - reg -  I2C slave address
+       - vbat-supply - Required supply regulator
+
+Example:
+
+haptics: haptics@59 {
+       compatible = "ti,drv2665";
+       reg = <0x59>;
+       vbat-supply = <&vbat>;
+};
+
+For more product information please see the link below:
+http://www.ti.com/product/drv2665
index 79699c2..62261c0 100644 (file)
@@ -2,9 +2,6 @@
 LED handling under Linux
 ========================
 
-If you're reading this and thinking about keyboard leds, these are
-handled by the input subsystem and the led class is *not* needed.
-
 In its simplest form, the LED class just allows control of LEDs from
 userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
 LED is defined in max_brightness file. The brightness file will set the brightness
index 460ab22..fe3b839 100644 (file)
@@ -5043,7 +5043,6 @@ F:        include/linux/input/
 INPUT MULTITOUCH (MT) PROTOCOL
 M:     Henrik Rydberg <rydberg@bitmath.org>
 L:     linux-input@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt.git
 S:     Odd fixes
 F:     Documentation/input/multi-touch-protocol.txt
 F:     drivers/input/input-mt.c
index a11ff74..a35532e 100644 (file)
@@ -25,6 +25,19 @@ config INPUT
 
 if INPUT
 
+config INPUT_LEDS
+       tristate "Export input device LEDs in sysfs"
+       depends on LEDS_CLASS
+       default INPUT
+       help
+         Say Y here if you would like to export LEDs on input devices
+         as standard LED class devices in sysfs.
+
+         If unsure, say Y.
+
+         To compile this driver as a module, choose M here: the
+         module will be called input-leds.
+
 config INPUT_FF_MEMLESS
        tristate "Support for memoryless force-feedback devices"
        help
index 5ca3f63..0c9302c 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_POLLDEV)   += input-polldev.o
 obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
 obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
 
+obj-$(CONFIG_INPUT_LEDS)       += input-leds.o
 obj-$(CONFIG_INPUT_MOUSEDEV)   += mousedev.o
 obj-$(CONFIG_INPUT_JOYDEV)     += joydev.o
 obj-$(CONFIG_INPUT_EVDEV)      += evdev.o
index a18f41b..9d35499 100644 (file)
@@ -422,10 +422,7 @@ static int evdev_release(struct inode *inode, struct file *file)
 
        evdev_detach_client(evdev, client);
 
-       if (is_vmalloc_addr(client))
-               vfree(client);
-       else
-               kfree(client);
+       kvfree(client);
 
        evdev_close_device(evdev);
 
index b81c88c..8f4a30f 100644 (file)
@@ -70,7 +70,7 @@ static int compat_effect(struct ff_device *ff, struct ff_effect *effect)
                        return -EINVAL;
 
                /*
-                * calculate manginude of sine wave as average of rumble's
+                * calculate magnitude of sine wave as average of rumble's
                 * 2/3 of strong magnitude and 1/3 of weak magnitude
                 */
                magnitude = effect->u.rumble.strong_magnitude / 3 +
@@ -213,7 +213,7 @@ static int erase_effect(struct input_dev *dev, int effect_id,
 /**
  * input_ff_erase - erase a force-feedback effect from device
  * @dev: input device to erase effect from
- * @effect_id: id of the ffect to be erased
+ * @effect_id: id of the effect to be erased
  * @file: purported owner of the request
  *
  * This function erases a force-feedback effect from specified device.
diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c
new file mode 100644 (file)
index 0000000..074a65e
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * LED support for the input layer
+ *
+ * Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+
+#if IS_ENABLED(CONFIG_VT)
+#define VT_TRIGGER(_name)      .trigger = _name
+#else
+#define VT_TRIGGER(_name)      .trigger = NULL
+#endif
+
+static const struct {
+       const char *name;
+       const char *trigger;
+} input_led_info[LED_CNT] = {
+       [LED_NUML]      = { "numlock", VT_TRIGGER("kbd-numlock") },
+       [LED_CAPSL]     = { "capslock", VT_TRIGGER("kbd-capslock") },
+       [LED_SCROLLL]   = { "scrolllock", VT_TRIGGER("kbd-scrolllock") },
+       [LED_COMPOSE]   = { "compose" },
+       [LED_KANA]      = { "kana", VT_TRIGGER("kbd-kanalock") },
+       [LED_SLEEP]     = { "sleep" } ,
+       [LED_SUSPEND]   = { "suspend" },
+       [LED_MUTE]      = { "mute" },
+       [LED_MISC]      = { "misc" },
+       [LED_MAIL]      = { "mail" },
+       [LED_CHARGING]  = { "charging" },
+};
+
+struct input_led {
+       struct led_classdev cdev;
+       struct input_handle *handle;
+       unsigned int code; /* One of LED_* constants */
+};
+
+struct input_leds {
+       struct input_handle handle;
+       unsigned int num_leds;
+       struct input_led leds[];
+};
+
+static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
+{
+       struct input_led *led = container_of(cdev, struct input_led, cdev);
+       struct input_dev *input = led->handle->dev;
+
+       return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
+}
+
+static void input_leds_brightness_set(struct led_classdev *cdev,
+                                     enum led_brightness brightness)
+{
+       struct input_led *led = container_of(cdev, struct input_led, cdev);
+
+       input_inject_event(led->handle, EV_LED, led->code, !!brightness);
+}
+
+static void input_leds_event(struct input_handle *handle, unsigned int type,
+                            unsigned int code, int value)
+{
+}
+
+static int input_leds_connect(struct input_handler *handler,
+                             struct input_dev *dev,
+                             const struct input_device_id *id)
+{
+       struct input_leds *leds;
+       unsigned int num_leds;
+       unsigned int led_code;
+       int led_no;
+       int error;
+
+       num_leds = bitmap_weight(dev->ledbit, LED_CNT);
+       if (!num_leds)
+               return -ENXIO;
+
+       leds = kzalloc(sizeof(*leds) + num_leds * sizeof(*leds->leds),
+                      GFP_KERNEL);
+       if (!leds)
+               return -ENOMEM;
+
+       leds->num_leds = num_leds;
+
+       leds->handle.dev = dev;
+       leds->handle.handler = handler;
+       leds->handle.name = "leds";
+       leds->handle.private = leds;
+
+       error = input_register_handle(&leds->handle);
+       if (error)
+               goto err_free_mem;
+
+       error = input_open_device(&leds->handle);
+       if (error)
+               goto err_unregister_handle;
+
+       led_no = 0;
+       for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
+               struct input_led *led = &leds->leds[led_no];
+
+               led->handle = &leds->handle;
+               led->code = led_code;
+
+               if (WARN_ON(!input_led_info[led_code].name))
+                       continue;
+
+               led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
+                                          dev_name(&dev->dev),
+                                          input_led_info[led_code].name);
+               if (!led->cdev.name) {
+                       error = -ENOMEM;
+                       goto err_unregister_leds;
+               }
+
+               led->cdev.max_brightness = 1;
+               led->cdev.brightness_get = input_leds_brightness_get;
+               led->cdev.brightness_set = input_leds_brightness_set;
+               led->cdev.default_trigger = input_led_info[led_code].trigger;
+
+               error = led_classdev_register(&dev->dev, &led->cdev);
+               if (error) {
+                       dev_err(&dev->dev, "failed to register LED %s: %d\n",
+                               led->cdev.name, error);
+                       kfree(led->cdev.name);
+                       goto err_unregister_leds;
+               }
+
+               led_no++;
+       }
+
+       return 0;
+
+err_unregister_leds:
+       while (--led_no >= 0) {
+               struct input_led *led = &leds->leds[led_no];
+
+               led_classdev_unregister(&led->cdev);
+               kfree(led->cdev.name);
+       }
+
+       input_close_device(&leds->handle);
+
+err_unregister_handle:
+       input_unregister_handle(&leds->handle);
+
+err_free_mem:
+       kfree(leds);
+       return error;
+}
+
+static void input_leds_disconnect(struct input_handle *handle)
+{
+       struct input_leds *leds = handle->private;
+       int i;
+
+       for (i = 0; i < leds->num_leds; i++) {
+               struct input_led *led = &leds->leds[i];
+
+               led_classdev_unregister(&led->cdev);
+               kfree(led->cdev.name);
+       }
+
+       input_close_device(handle);
+       input_unregister_handle(handle);
+
+       kfree(leds);
+}
+
+static const struct input_device_id input_leds_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+               .evbit = { BIT_MASK(EV_LED) },
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(input, input_leds_ids);
+
+static struct input_handler input_leds_handler = {
+       .event =        input_leds_event,
+       .connect =      input_leds_connect,
+       .disconnect =   input_leds_disconnect,
+       .name =         "leds",
+       .id_table =     input_leds_ids,
+};
+
+static int __init input_leds_init(void)
+{
+       return input_register_handler(&input_leds_handler);
+}
+module_init(input_leds_init);
+
+static void __exit input_leds_exit(void)
+{
+       input_unregister_handler(&input_leds_handler);
+}
+module_exit(input_leds_exit);
+
+MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
+MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
+MODULE_DESCRIPTION("Input -> LEDs Bridge");
+MODULE_LICENSE("GPL v2");
index cc357f1..f315784 100644 (file)
@@ -2262,7 +2262,7 @@ EXPORT_SYMBOL(input_unregister_handler);
  *
  * Iterate over @bus's list of devices, and call @fn for each, passing
  * it @data and stop when @fn returns a non-zero value. The function is
- * using RCU to traverse the list and therefore may be usind in atonic
+ * using RCU to traverse the list and therefore may be using in atomic
  * contexts. The @fn callback is invoked from RCU critical section and
  * thus must not sleep.
  */
index 106fbac..4d75062 100644 (file)
@@ -367,6 +367,7 @@ config KEYBOARD_MAPLE
 
 config KEYBOARD_MAX7359
        tristate "Maxim MAX7359 Key Switch Controller"
+       select INPUT_MATRIXKMAP
        depends on I2C
        help
          If you say yes here you get support for the Maxim MAX7359 Key
index a452677..6ed83cf 100644 (file)
 #define LOGIC2_STAT    (1 << 7)        /* ADP5589 only */
 #define LOGIC1_STAT    (1 << 6)
 #define LOCK_STAT      (1 << 5)        /* ADP5589 only */
-#define KEC            0xF
+#define KEC            0x1F
 
 /* PIN_CONFIG_D Register */
 #define C4_EXTEND_CFG  (1 << 6)        /* RESET2 */
@@ -726,7 +726,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
 
                pull_mask |= val << (2 * (i & 0x3));
 
-               if (i == 3 || i == kpad->var->max_row_num) {
+               if (i % 4 == 3 || i == kpad->var->max_row_num) {
                        ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A)
                                             + (i >> 2), pull_mask);
                        pull_mask = 0;
@@ -746,7 +746,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
 
                pull_mask |= val << (2 * (i & 0x3));
 
-               if (i == 3 || i == kpad->var->max_col_num) {
+               if (i % 4 == 3 || i == kpad->var->max_col_num) {
                        ret |= adp5589_write(client,
                                             reg(ADP5585_RPULL_CONFIG_C) +
                                             (i >> 2), pull_mask);
index 27ef29f..b637f1a 100644 (file)
@@ -120,14 +120,9 @@ static int clps711x_keypad_probe(struct platform_device *pdev)
        for (i = 0; i < priv->row_count; i++) {
                struct clps711x_gpio_data *data = &priv->gpio_data[i];
 
-               data->desc = devm_gpiod_get_index(dev, "row", i);
-               if (!data->desc)
-                       return -EINVAL;
-
+               data->desc = devm_gpiod_get_index(dev, "row", i, GPIOD_IN);
                if (IS_ERR(data->desc))
                        return PTR_ERR(data->desc);
-
-               gpiod_direction_input(data->desc);
        }
 
        err = of_property_read_u32(np, "poll-interval", &poll_interval);
index faa6da5..5091133 100644 (file)
@@ -84,26 +84,6 @@ static int max7359_read_reg(struct i2c_client *client, int reg)
        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)
 {
@@ -166,7 +146,6 @@ static void max7359_close(struct input_dev *dev)
 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 */
 
@@ -233,7 +212,15 @@ static int max7359_probe(struct i2c_client *client,
        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
        input_set_drvdata(input_dev, keypad);
 
-       max7359_build_keycode(keypad, keymap_data);
+       error = matrix_keypad_build_keymap(keymap_data, NULL,
+                                          MAX7359_MAX_KEY_ROWS,
+                                          MAX7359_MAX_KEY_COLS,
+                                          keypad->keycodes,
+                                          input_dev);
+       if (error) {
+               dev_err(&client->dev, "failed to build keymap\n");
+               return error;
+       }
 
        error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
                                          max7359_interrupt,
index 6b9fdf6..43e48da 100644 (file)
@@ -585,7 +585,7 @@ static const struct of_device_id samsung_keypad_dt_match[] = {
 MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
 #endif
 
-static struct platform_device_id samsung_keypad_driver_ids[] = {
+static const struct platform_device_id samsung_keypad_driver_ids[] = {
        {
                .name           = "samsung-keypad",
                .driver_data    = KEYPAD_TYPE_SAMSUNG,
index f42a543..623d451 100644 (file)
@@ -3,7 +3,7 @@
  * Based on omap-keypad driver
  *
  * Copyright (C) 2010 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ * Rajeev Kumar <rajeevkumar.linux@gmail.com>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
index 4436ab1..d4f0a81 100644 (file)
@@ -610,6 +610,16 @@ config INPUT_DA9055_ONKEY
          To compile this driver as a module, choose M here: the module
          will be called da9055_onkey.
 
+config INPUT_DA9063_ONKEY
+       tristate "Dialog DA9063 OnKey"
+       depends on MFD_DA9063
+       help
+         Support the ONKEY of Dialog DA9063 Power Management IC as an
+         input device reporting power button statue.
+
+         To compile this driver as a module, choose M here: the module
+         will be called da9063_onkey.
+
 config INPUT_DM355EVM
        tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
        depends on MFD_DM355EVM_MSP
@@ -775,6 +785,17 @@ config INPUT_DRV260X_HAPTICS
          To compile this driver as a module, choose M here: the
          module will be called drv260x-haptics.
 
+config INPUT_DRV2665_HAPTICS
+       tristate "TI DRV2665 haptics support"
+       depends on INPUT && I2C
+       select INPUT_FF_MEMLESS
+       select REGMAP_I2C
+       help
+         Say Y to enable support for the TI DRV2665 haptics driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called drv2665-haptics.
+
 config INPUT_DRV2667_HAPTICS
        tristate "TI DRV2667 haptics support"
        depends on INPUT && I2C
@@ -784,6 +805,6 @@ config INPUT_DRV2667_HAPTICS
          Say Y to enable support for the TI DRV2667 haptics driver.
 
          To compile this driver as a module, choose M here: the
-         module will be called drv260x-haptics.
+         module will be called drv2667-haptics.
 
 endif
index 78ba4c1..53df07d 100644 (file)
@@ -25,9 +25,11 @@ obj-$(CONFIG_INPUT_CMA3000_I2C)              += cma3000_d0x_i2c.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)                += cobalt_btns.o
 obj-$(CONFIG_INPUT_DA9052_ONKEY)       += da9052_onkey.o
 obj-$(CONFIG_INPUT_DA9055_ONKEY)       += da9055_onkey.o
+obj-$(CONFIG_INPUT_DA9063_ONKEY)       += da9063_onkey.o
 obj-$(CONFIG_INPUT_DM355EVM)           += dm355evm_keys.o
 obj-$(CONFIG_INPUT_E3X0_BUTTON)                += e3x0-button.o
 obj-$(CONFIG_INPUT_DRV260X_HAPTICS)    += drv260x.o
+obj-$(CONFIG_INPUT_DRV2665_HAPTICS)    += drv2665.o
 obj-$(CONFIG_INPUT_DRV2667_HAPTICS)    += drv2667.o
 obj-$(CONFIG_INPUT_GP2A)               += gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_BEEPER)                += gpio-beeper.o
index 470bfd6..bdb5d03 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/input.h>       /* BUS_I2C */
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/types.h>
 #include <linux/pm.h>
 #include "adxl34x.h"
@@ -135,11 +136,31 @@ static const struct i2c_device_id adxl34x_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, adxl34x_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id adxl34x_of_id[] = {
+       /*
+        * The ADXL346 is backward-compatible with the ADXL345. Differences are
+        * handled by runtime detection of the device model, there's thus no
+        * need for listing the "adi,adxl346" compatible value explicitly.
+        */
+       { .compatible = "adi,adxl345", },
+       /*
+        * Deprecated, DT nodes should use one or more of the device-specific
+        * compatible values "adi,adxl345" and "adi,adxl346".
+        */
+       { .compatible = "adi,adxl34x", },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, adxl34x_of_id);
+#endif
+
 static struct i2c_driver adxl34x_driver = {
        .driver = {
                .name = "adxl34x",
                .owner = THIS_MODULE,
                .pm = &adxl34x_i2c_pm,
+               .of_match_table = of_match_ptr(adxl34x_of_id),
        },
        .probe    = adxl34x_i2c_probe,
        .remove   = adxl34x_i2c_remove,
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
new file mode 100644 (file)
index 0000000..f577585
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * OnKey device driver for DA9063
+ * Copyright (C) 2015  Dialog Semiconductor Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/mfd/da9063/core.h>
+#include <linux/mfd/da9063/pdata.h>
+#include <linux/mfd/da9063/registers.h>
+
+struct da9063_onkey {
+       struct da9063 *hw;
+       struct delayed_work work;
+       struct input_dev *input;
+       struct device *dev;
+       bool key_power;
+};
+
+static void da9063_poll_on(struct work_struct *work)
+{
+       struct da9063_onkey *onkey = container_of(work, struct da9063_onkey,
+                                                 work.work);
+       unsigned int val;
+       int fault_log = 0;
+       bool poll = true;
+       int error;
+
+       /* Poll to see when the pin is released */
+       error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
+       if (error) {
+               dev_err(onkey->dev,
+                       "Failed to read ON status: %d\n", error);
+               goto err_poll;
+       }
+
+       if (!(val & DA9063_NONKEY)) {
+               error = regmap_update_bits(onkey->hw->regmap,
+                                          DA9063_REG_CONTROL_B,
+                                          DA9063_NONKEY_LOCK, 0);
+               if (error) {
+                       dev_err(onkey->dev,
+                               "Failed to reset the Key Delay %d\n", error);
+                       goto err_poll;
+               }
+
+               input_report_key(onkey->input, KEY_POWER, 0);
+               input_sync(onkey->input);
+
+               poll = false;
+       }
+
+       /*
+        * If the fault log KEY_RESET is detected, then clear it
+        * and shut down the system.
+        */
+       error = regmap_read(onkey->hw->regmap,
+                           DA9063_REG_FAULT_LOG, &fault_log);
+       if (error) {
+               dev_warn(&onkey->input->dev,
+                        "Cannot read FAULT_LOG: %d\n", error);
+       } else if (fault_log & DA9063_KEY_RESET) {
+               error = regmap_write(onkey->hw->regmap,
+                                    DA9063_REG_FAULT_LOG,
+                                    DA9063_KEY_RESET);
+               if (error) {
+                       dev_warn(&onkey->input->dev,
+                                "Cannot reset KEY_RESET fault log: %d\n",
+                                error);
+               } else {
+                       /* at this point we do any S/W housekeeping
+                        * and then send shutdown command
+                        */
+                       dev_dbg(&onkey->input->dev,
+                                "Sending SHUTDOWN to DA9063 ...\n");
+                       error = regmap_write(onkey->hw->regmap,
+                                            DA9063_REG_CONTROL_F,
+                                            DA9063_SHUTDOWN);
+                       if (error)
+                               dev_err(&onkey->input->dev,
+                                       "Cannot SHUTDOWN DA9063: %d\n",
+                                       error);
+               }
+       }
+
+err_poll:
+       if (poll)
+               schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+}
+
+static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
+{
+       struct da9063_onkey *onkey = data;
+       unsigned int val;
+       int error;
+
+       error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
+       if (onkey->key_power && !error && (val & DA9063_NONKEY)) {
+               input_report_key(onkey->input, KEY_POWER, 1);
+               input_sync(onkey->input);
+               schedule_delayed_work(&onkey->work, 0);
+               dev_dbg(onkey->dev, "KEY_POWER pressed.\n");
+       } else {
+               input_report_key(onkey->input, KEY_SLEEP, 1);
+               input_sync(onkey->input);
+               input_report_key(onkey->input, KEY_SLEEP, 0);
+               input_sync(onkey->input);
+               dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void da9063_cancel_poll(void *data)
+{
+       struct da9063_onkey *onkey = data;
+
+       cancel_delayed_work_sync(&onkey->work);
+}
+
+static int da9063_onkey_probe(struct platform_device *pdev)
+{
+       struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
+       struct da9063_pdata *pdata = dev_get_platdata(da9063->dev);
+       struct da9063_onkey *onkey;
+       int irq;
+       int error;
+
+       onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
+                            GFP_KERNEL);
+       if (!onkey) {
+               dev_err(&pdev->dev, "Failed to allocate memory.\n");
+               return -ENOMEM;
+       }
+
+       onkey->dev = &pdev->dev;
+       onkey->hw = da9063;
+
+       if (pdata)
+               onkey->key_power = pdata->key_power;
+       else
+               onkey->key_power =
+                       !of_property_read_bool(pdev->dev.of_node,
+                                              "dlg,disable-key-power");
+
+       onkey->input = devm_input_allocate_device(&pdev->dev);
+       if (!onkey->input) {
+               dev_err(&pdev->dev, "Failed to allocated input device.\n");
+               return -ENOMEM;
+       }
+
+       onkey->input->name = DA9063_DRVNAME_ONKEY;
+       onkey->input->phys = DA9063_DRVNAME_ONKEY "/input0";
+       onkey->input->dev.parent = &pdev->dev;
+
+       if (onkey->key_power)
+               input_set_capability(onkey->input, EV_KEY, KEY_POWER);
+
+       input_set_capability(onkey->input, EV_KEY, KEY_SLEEP);
+
+       INIT_DELAYED_WORK(&onkey->work, da9063_poll_on);
+
+       error = devm_add_action(&pdev->dev, da9063_cancel_poll, onkey);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "Failed to add cancel poll action: %d\n",
+                       error);
+               return error;
+       }
+
+       irq = platform_get_irq_byname(pdev, "ONKEY");
+       if (irq < 0) {
+               error = irq;
+               dev_err(&pdev->dev, "Failed to get platform IRQ: %d\n", error);
+               return error;
+       }
+
+       error = devm_request_threaded_irq(&pdev->dev, irq,
+                                         NULL, da9063_onkey_irq_handler,
+                                         IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                         "ONKEY", onkey);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "Failed to request IRQ %d: %d\n", irq, error);
+               return error;
+       }
+
+       error = input_register_device(onkey->input);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "Failed to register input device: %d\n", error);
+               return error;
+       }
+
+       platform_set_drvdata(pdev, onkey);
+       return 0;
+}
+
+static struct platform_driver da9063_onkey_driver = {
+       .probe  = da9063_onkey_probe,
+       .driver = {
+               .name   = DA9063_DRVNAME_ONKEY,
+       },
+};
+module_platform_driver(da9063_onkey_driver);
+
+MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
index 5995780..e5d60ec 100644 (file)
@@ -580,15 +580,10 @@ static int drv260x_probe(struct i2c_client *client,
                return error;
        }
 
-       haptics->enable_gpio = devm_gpiod_get(&client->dev, "enable");
-       if (IS_ERR(haptics->enable_gpio)) {
-               error = PTR_ERR(haptics->enable_gpio);
-               if (error != -ENOENT && error != -ENOSYS)
-                       return error;
-               haptics->enable_gpio = NULL;
-       } else {
-               gpiod_direction_output(haptics->enable_gpio, 1);
-       }
+       haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
+                                                      GPIOD_OUT_HIGH);
+       if (IS_ERR(haptics->enable_gpio))
+               return PTR_ERR(haptics->enable_gpio);
 
        haptics->input_dev = devm_input_allocate_device(&client->dev);
        if (!haptics->input_dev) {
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
new file mode 100644 (file)
index 0000000..0afaa33
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * DRV2665 haptics driver family
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright: (C) 2015 Texas Instruments, Inc.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+/* Contol registers */
+#define DRV2665_STATUS 0x00
+#define DRV2665_CTRL_1 0x01
+#define DRV2665_CTRL_2 0x02
+#define DRV2665_FIFO   0x0b
+
+/* Status Register */
+#define DRV2665_FIFO_FULL              BIT(0)
+#define DRV2665_FIFO_EMPTY             BIT(1)
+
+/* Control 1 Register */
+#define DRV2665_25_VPP_GAIN            0x00
+#define DRV2665_50_VPP_GAIN            0x01
+#define DRV2665_75_VPP_GAIN            0x02
+#define DRV2665_100_VPP_GAIN           0x03
+#define DRV2665_DIGITAL_IN             0xfc
+#define DRV2665_ANALOG_IN              BIT(2)
+
+/* Control 2 Register */
+#define DRV2665_BOOST_EN               BIT(1)
+#define DRV2665_STANDBY                        BIT(6)
+#define DRV2665_DEV_RST                        BIT(7)
+#define DRV2665_5_MS_IDLE_TOUT         0x00
+#define DRV2665_10_MS_IDLE_TOUT                0x04
+#define DRV2665_15_MS_IDLE_TOUT                0x08
+#define DRV2665_20_MS_IDLE_TOUT                0x0c
+
+/**
+ * struct drv2665_data -
+ * @input_dev - Pointer to the input device
+ * @client - Pointer to the I2C client
+ * @regmap - Register map of the device
+ * @work - Work item used to off load the enable/disable of the vibration
+ * @regulator - Pointer to the regulator for the IC
+ */
+struct drv2665_data {
+       struct input_dev *input_dev;
+       struct i2c_client *client;
+       struct regmap *regmap;
+       struct work_struct work;
+       struct regulator *regulator;
+};
+
+/* 8kHz Sine wave to stream to the FIFO */
+static const u8 drv2665_sine_wave_form[] = {
+       0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
+       0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
+       0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
+       0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
+};
+
+static struct reg_default drv2665_reg_defs[] = {
+       { DRV2665_STATUS, 0x02 },
+       { DRV2665_CTRL_1, 0x28 },
+       { DRV2665_CTRL_2, 0x40 },
+       { DRV2665_FIFO, 0x00 },
+};
+
+static void drv2665_worker(struct work_struct *work)
+{
+       struct drv2665_data *haptics =
+                               container_of(work, struct drv2665_data, work);
+       unsigned int read_buf;
+       int error;
+
+       error = regmap_read(haptics->regmap, DRV2665_STATUS, &read_buf);
+       if (error) {
+               dev_err(&haptics->client->dev,
+                       "Failed to read status: %d\n", error);
+               return;
+       }
+
+       if (read_buf & DRV2665_FIFO_EMPTY) {
+               error = regmap_bulk_write(haptics->regmap,
+                                         DRV2665_FIFO,
+                                         drv2665_sine_wave_form,
+                                         ARRAY_SIZE(drv2665_sine_wave_form));
+               if (error) {
+                       dev_err(&haptics->client->dev,
+                               "Failed to write FIFO: %d\n", error);
+                       return;
+               }
+       }
+}
+
+static int drv2665_haptics_play(struct input_dev *input, void *data,
+                               struct ff_effect *effect)
+{
+       struct drv2665_data *haptics = input_get_drvdata(input);
+
+       schedule_work(&haptics->work);
+
+       return 0;
+}
+
+static void drv2665_close(struct input_dev *input)
+{
+       struct drv2665_data *haptics = input_get_drvdata(input);
+       int error;
+
+       cancel_work_sync(&haptics->work);
+
+       error = regmap_update_bits(haptics->regmap,
+                                  DRV2665_CTRL_2, DRV2665_STANDBY, 1);
+       if (error)
+               dev_err(&haptics->client->dev,
+                       "Failed to enter standby mode: %d\n", error);
+}
+
+static const struct reg_default drv2665_init_regs[] = {
+       { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
+       { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
+};
+
+static int drv2665_init(struct drv2665_data *haptics)
+{
+       int error;
+
+       error = regmap_register_patch(haptics->regmap,
+                                     drv2665_init_regs,
+                                     ARRAY_SIZE(drv2665_init_regs));
+       if (error) {
+               dev_err(&haptics->client->dev,
+                       "Failed to write init registers: %d\n",
+                       error);
+               return error;
+       }
+
+       return 0;
+}
+
+static const struct regmap_config drv2665_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = DRV2665_FIFO,
+       .reg_defaults = drv2665_reg_defs,
+       .num_reg_defaults = ARRAY_SIZE(drv2665_reg_defs),
+       .cache_type = REGCACHE_NONE,
+};
+
+static int drv2665_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct drv2665_data *haptics;
+       int error;
+
+       haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+       if (!haptics)
+               return -ENOMEM;
+
+       haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+       if (IS_ERR(haptics->regulator)) {
+               error = PTR_ERR(haptics->regulator);
+               dev_err(&client->dev,
+                       "unable to get regulator, error: %d\n", error);
+               return error;
+       }
+
+       haptics->input_dev = devm_input_allocate_device(&client->dev);
+       if (!haptics->input_dev) {
+               dev_err(&client->dev, "Failed to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       haptics->input_dev->name = "drv2665:haptics";
+       haptics->input_dev->dev.parent = client->dev.parent;
+       haptics->input_dev->close = drv2665_close;
+       input_set_drvdata(haptics->input_dev, haptics);
+       input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
+
+       error = input_ff_create_memless(haptics->input_dev, NULL,
+                                       drv2665_haptics_play);
+       if (error) {
+               dev_err(&client->dev, "input_ff_create() failed: %d\n",
+                       error);
+               return error;
+       }
+
+       INIT_WORK(&haptics->work, drv2665_worker);
+
+       haptics->client = client;
+       i2c_set_clientdata(client, haptics);
+
+       haptics->regmap = devm_regmap_init_i2c(client, &drv2665_regmap_config);
+       if (IS_ERR(haptics->regmap)) {
+               error = PTR_ERR(haptics->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       error);
+               return error;
+       }
+
+       error = drv2665_init(haptics);
+       if (error) {
+               dev_err(&client->dev, "Device init failed: %d\n", error);
+               return error;
+       }
+
+       error = input_register_device(haptics->input_dev);
+       if (error) {
+               dev_err(&client->dev, "couldn't register input device: %d\n",
+                       error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused drv2665_suspend(struct device *dev)
+{
+       struct drv2665_data *haptics = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&haptics->input_dev->mutex);
+
+       if (haptics->input_dev->users) {
+               ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+                               DRV2665_STANDBY, 1);
+               if (ret) {
+                       dev_err(dev, "Failed to set standby mode\n");
+                       regulator_disable(haptics->regulator);
+                       goto out;
+               }
+
+               ret = regulator_disable(haptics->regulator);
+               if (ret) {
+                       dev_err(dev, "Failed to disable regulator\n");
+                       regmap_update_bits(haptics->regmap,
+                                          DRV2665_CTRL_2,
+                                          DRV2665_STANDBY, 0);
+               }
+       }
+out:
+       mutex_unlock(&haptics->input_dev->mutex);
+       return ret;
+}
+
+static int __maybe_unused drv2665_resume(struct device *dev)
+{
+       struct drv2665_data *haptics = dev_get_drvdata(dev);
+       int ret = 0;
+
+       mutex_lock(&haptics->input_dev->mutex);
+
+       if (haptics->input_dev->users) {
+               ret = regulator_enable(haptics->regulator);
+               if (ret) {
+                       dev_err(dev, "Failed to enable regulator\n");
+                       goto out;
+               }
+
+               ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+                                        DRV2665_STANDBY, 0);
+               if (ret) {
+                       dev_err(dev, "Failed to unset standby mode\n");
+                       regulator_disable(haptics->regulator);
+                       goto out;
+               }
+
+       }
+
+out:
+       mutex_unlock(&haptics->input_dev->mutex);
+       return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
+
+static const struct i2c_device_id drv2665_id[] = {
+       { "drv2665", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, drv2665_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id drv2665_of_match[] = {
+       { .compatible = "ti,drv2665", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, drv2665_of_match);
+#endif
+
+static struct i2c_driver drv2665_driver = {
+       .probe          = drv2665_probe,
+       .driver         = {
+               .name   = "drv2665-haptics",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(drv2665_of_match),
+               .pm     = &drv2665_pm_ops,
+       },
+       .id_table = drv2665_id,
+};
+module_i2c_driver(drv2665_driver);
+
+MODULE_DESCRIPTION("TI DRV2665 haptics driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
index 4817c5f..16272ff 100644 (file)
@@ -66,13 +66,12 @@ static int gpio_beeper_probe(struct platform_device *pdev)
 {
        struct gpio_beeper *beep;
        struct input_dev *input;
-       int err;
 
        beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
        if (!beep)
                return -ENOMEM;
 
-       beep->desc = devm_gpiod_get(&pdev->dev, NULL);
+       beep->desc = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
        if (IS_ERR(beep->desc))
                return PTR_ERR(beep->desc);
 
@@ -92,10 +91,6 @@ static int gpio_beeper_probe(struct platform_device *pdev)
 
        input_set_capability(input, EV_SND, SND_BELL);
 
-       err = gpiod_direction_output(beep->desc, 0);
-       if (err)
-               return err;
-
        input_set_drvdata(input, beep);
 
        return input_register_device(input);
index 0c8ac60..30b459b 100644 (file)
@@ -63,7 +63,8 @@ static int retu_pwrbutton_probe(struct platform_device *pdev)
        input_set_drvdata(idev, rdev);
 
        error = devm_request_threaded_irq(&pdev->dev, irq,
-                                         NULL, retu_pwrbutton_irq, 0,
+                                         NULL, retu_pwrbutton_irq,
+                                         IRQF_ONESHOT,
                                          "retu-pwrbutton", idev);
        if (error)
                return error;
index e8e010a..c14b827 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/gpio/consumer.h>
 #include <linux/gpio_keys.h>
 #include <linux/platform_device.h>
-#include <linux/acpi.h>
 
 /*
  * Definition of buttons on the tablet. The ACPI index of each button
index e98cc81..603fc2f 100644 (file)
@@ -71,7 +71,8 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev)
        pwr->dev.parent = &pdev->dev;
 
        err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq,
-                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                       IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+                       IRQF_ONESHOT,
                        "twl4030_pwrbutton", pwr);
        if (err < 0) {
                dev_err(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
index 0e0d094..ea63fad 100644 (file)
@@ -308,7 +308,8 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
        mutex_init(&info->mutex);
 
        error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
-                                         twl6040_vib_irq_handler, 0,
+                                         twl6040_vib_irq_handler,
+                                         IRQF_ONESHOT,
                                          "twl6040_irq_vib", info);
        if (error) {
                dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
index 59d4f7b..1b44de2 100644 (file)
@@ -99,7 +99,8 @@ static int wm831x_on_probe(struct platform_device *pdev)
        wm831x_on->dev->dev.parent = &pdev->dev;
 
        ret = request_threaded_irq(irq, NULL, wm831x_on_irq,
-                                  IRQF_TRIGGER_RISING, "wm831x_on",
+                                  IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                  "wm831x_on",
                                   wm831x_on);
        if (ret < 0) {
                dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
index a353b7d..113d6f1 100644 (file)
@@ -159,8 +159,8 @@ static const struct alps_protocol_info alps_v8_protocol_data = {
 
 static void alps_set_abs_params_st(struct alps_data *priv,
                                   struct input_dev *dev1);
-static void alps_set_abs_params_mt(struct alps_data *priv,
-                                  struct input_dev *dev1);
+static void alps_set_abs_params_semi_mt(struct alps_data *priv,
+                                       struct input_dev *dev1);
 static void alps_set_abs_params_v7(struct alps_data *priv,
                                   struct input_dev *dev1);
 static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
@@ -310,53 +310,6 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
        input_sync(dev);
 }
 
-/*
- * Process bitmap data for V5 protocols. Return value is null.
- *
- * The bitmaps don't have enough data to track fingers, so this function
- * only generates points representing a bounding box of at most two contacts.
- * These two points are returned in fields->mt.
- */
-static void alps_process_bitmap_dolphin(struct alps_data *priv,
-                                       struct alps_fields *fields)
-{
-       int box_middle_x, box_middle_y;
-       unsigned int x_map, y_map;
-       unsigned char start_bit, end_bit;
-       unsigned char x_msb, x_lsb, y_msb, y_lsb;
-
-       x_map = fields->x_map;
-       y_map = fields->y_map;
-
-       if (!x_map || !y_map)
-               return;
-
-       /* Get Most-significant and Least-significant bit */
-       x_msb = fls(x_map);
-       x_lsb = ffs(x_map);
-       y_msb = fls(y_map);
-       y_lsb = ffs(y_map);
-
-       /* Most-significant bit should never exceed max sensor line number */
-       if (x_msb > priv->x_bits || y_msb > priv->y_bits)
-               return;
-
-       if (fields->fingers > 1) {
-               start_bit = priv->x_bits - x_msb;
-               end_bit = priv->x_bits - x_lsb;
-               box_middle_x = (priv->x_max * (start_bit + end_bit)) /
-                               (2 * (priv->x_bits - 1));
-
-               start_bit = y_lsb - 1;
-               end_bit = y_msb - 1;
-               box_middle_y = (priv->y_max * (start_bit + end_bit)) /
-                               (2 * (priv->y_bits - 1));
-               fields->mt[0] = fields->st;
-               fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
-               fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
-       }
-}
-
 static void alps_get_bitmap_points(unsigned int map,
                                   struct alps_bitmap_point *low,
                                   struct alps_bitmap_point *high,
@@ -384,7 +337,7 @@ static void alps_get_bitmap_points(unsigned int map,
 }
 
 /*
- * Process bitmap data from v3 and v4 protocols. Returns the number of
+ * Process bitmap data from semi-mt protocols. Returns the number of
  * fingers detected. A return value of 0 means at least one of the
  * bitmaps was empty.
  *
@@ -396,9 +349,10 @@ static void alps_get_bitmap_points(unsigned int map,
 static int alps_process_bitmap(struct alps_data *priv,
                               struct alps_fields *fields)
 {
-       int i, fingers_x = 0, fingers_y = 0, fingers;
+       int i, fingers_x = 0, fingers_y = 0, fingers, closest;
        struct alps_bitmap_point x_low = {0,}, x_high = {0,};
        struct alps_bitmap_point y_low = {0,}, y_high = {0,};
+       struct input_mt_pos corner[4];
 
        if (!fields->x_map || !fields->y_map)
                return 0;
@@ -429,26 +383,76 @@ static int alps_process_bitmap(struct alps_data *priv,
                y_high.num_bits = max(i, 1);
        }
 
-       fields->mt[0].x =
+       /* top-left corner */
+       corner[0].x =
                (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
                (2 * (priv->x_bits - 1));
-       fields->mt[0].y =
+       corner[0].y =
                (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
                (2 * (priv->y_bits - 1));
 
-       fields->mt[1].x =
+       /* top-right corner */
+       corner[1].x =
                (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
                (2 * (priv->x_bits - 1));
-       fields->mt[1].y =
+       corner[1].y =
+               (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+               (2 * (priv->y_bits - 1));
+
+       /* bottom-right corner */
+       corner[2].x =
+               (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
+               (2 * (priv->x_bits - 1));
+       corner[2].y =
+               (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
+               (2 * (priv->y_bits - 1));
+
+       /* bottom-left corner */
+       corner[3].x =
+               (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+               (2 * (priv->x_bits - 1));
+       corner[3].y =
                (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
                (2 * (priv->y_bits - 1));
 
-       /* y-bitmap order is reversed, except on rushmore */
-       if (priv->proto_version != ALPS_PROTO_V3_RUSHMORE) {
-               fields->mt[0].y = priv->y_max - fields->mt[0].y;
-               fields->mt[1].y = priv->y_max - fields->mt[1].y;
+       /* x-bitmap order is reversed on v5 touchpads  */
+       if (priv->proto_version == ALPS_PROTO_V5) {
+               for (i = 0; i < 4; i++)
+                       corner[i].x = priv->x_max - corner[i].x;
+       }
+
+       /* y-bitmap order is reversed on v3 and v4 touchpads  */
+       if (priv->proto_version == ALPS_PROTO_V3 ||
+           priv->proto_version == ALPS_PROTO_V4) {
+               for (i = 0; i < 4; i++)
+                       corner[i].y = priv->y_max - corner[i].y;
+       }
+
+       /*
+        * We only select a corner for the second touch once per 2 finger
+        * touch sequence to avoid the chosen corner (and thus the coordinates)
+        * jumping around when the first touch is in the middle.
+        */
+       if (priv->second_touch == -1) {
+               /* Find corner closest to our st coordinates */
+               closest = 0x7fffffff;
+               for (i = 0; i < 4; i++) {
+                       int dx = fields->st.x - corner[i].x;
+                       int dy = fields->st.y - corner[i].y;
+                       int distance = dx * dx + dy * dy;
+
+                       if (distance < closest) {
+                               priv->second_touch = i;
+                               closest = distance;
+                       }
+               }
+               /* And select the opposite corner to use for the 2nd touch */
+               priv->second_touch = (priv->second_touch + 2) % 4;
        }
 
+       fields->mt[0] = fields->st;
+       fields->mt[1] = corner[priv->second_touch];
+
        return fingers;
 }
 
@@ -485,9 +489,14 @@ static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
                f->mt[0].x = f->st.x;
                f->mt[0].y = f->st.y;
                fingers = f->pressure > 0 ? 1 : 0;
+               priv->second_touch = -1;
        }
 
-       alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
+       if (fingers >= 1)
+               alps_set_slot(dev, 0, f->mt[0].x, f->mt[0].y);
+       if (fingers >= 2)
+               alps_set_slot(dev, 1, f->mt[1].x, f->mt[1].y);
+       input_mt_sync_frame(dev);
 
        input_mt_report_finger_count(dev, fingers);
 
@@ -584,20 +593,22 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
        f->first_mp = !!(p[4] & 0x40);
        f->is_mp = !!(p[0] & 0x40);
 
-       f->fingers = (p[5] & 0x3) + 1;
-       f->x_map = ((p[4] & 0x7e) << 8) |
-                  ((p[1] & 0x7f) << 2) |
-                  ((p[0] & 0x30) >> 4);
-       f->y_map = ((p[3] & 0x70) << 4) |
-                  ((p[2] & 0x7f) << 1) |
-                  (p[4] & 0x01);
-
-       f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
-              ((p[0] & 0x30) >> 4);
-       f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
-       f->pressure = p[5] & 0x7f;
+       if (f->is_mp) {
+               f->fingers = (p[5] & 0x3) + 1;
+               f->x_map = ((p[4] & 0x7e) << 8) |
+                          ((p[1] & 0x7f) << 2) |
+                          ((p[0] & 0x30) >> 4);
+               f->y_map = ((p[3] & 0x70) << 4) |
+                          ((p[2] & 0x7f) << 1) |
+                          (p[4] & 0x01);
+       } else {
+               f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+                      ((p[0] & 0x30) >> 4);
+               f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+               f->pressure = p[5] & 0x7f;
 
-       alps_decode_buttons_v3(f, p);
+               alps_decode_buttons_v3(f, p);
+       }
 
        return 0;
 }
@@ -605,13 +616,27 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
 static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
                                 struct psmouse *psmouse)
 {
-       alps_decode_pinnacle(f, p, psmouse);
-
-       /* Rushmore's packet decode has a bit difference with Pinnacle's */
+       f->first_mp = !!(p[4] & 0x40);
        f->is_mp = !!(p[5] & 0x40);
-       f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
-       f->x_map |= (p[5] & 0x10) << 11;
-       f->y_map |= (p[5] & 0x20) << 6;
+
+       if (f->is_mp) {
+               f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
+               f->x_map = ((p[5] & 0x10) << 11) |
+                          ((p[4] & 0x7e) << 8) |
+                          ((p[1] & 0x7f) << 2) |
+                          ((p[0] & 0x30) >> 4);
+               f->y_map = ((p[5] & 0x20) << 6) |
+                          ((p[3] & 0x70) << 4) |
+                          ((p[2] & 0x7f) << 1) |
+                          (p[4] & 0x01);
+       } else {
+               f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+                      ((p[0] & 0x30) >> 4);
+               f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+               f->pressure = p[5] & 0x7f;
+
+               alps_decode_buttons_v3(f, p);
+       }
 
        return 0;
 }
@@ -680,30 +705,13 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
                 */
                if (f->is_mp) {
                        fingers = f->fingers;
-                       if (priv->proto_version == ALPS_PROTO_V3 ||
-                           priv->proto_version == ALPS_PROTO_V3_RUSHMORE) {
-                               if (alps_process_bitmap(priv, f) == 0)
-                                       fingers = 0; /* Use st data */
-
-                               /* Now process position packet */
-                               priv->decode_fields(f, priv->multi_data,
-                                                   psmouse);
-                       } else {
-                               /*
-                                * Because Dolphin uses position packet's
-                                * coordinate data as Pt1 and uses it to
-                                * calculate Pt2, so we need to do position
-                                * packet decode first.
-                                */
-                               priv->decode_fields(f, priv->multi_data,
-                                                   psmouse);
-
-                               /*
-                                * Since Dolphin's finger number is reliable,
-                                * there is no need to compare with bmap_fn.
-                                */
-                               alps_process_bitmap_dolphin(priv, f);
-                       }
+                       /*
+                        * Bitmap processing uses position packet's coordinate
+                        * data, so we need to do decode it first.
+                        */
+                       priv->decode_fields(f, priv->multi_data, psmouse);
+                       if (alps_process_bitmap(priv, f) == 0)
+                               fingers = 0; /* Use st data */
                } else {
                        priv->multi_packet = 0;
                }
@@ -865,6 +873,14 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
        priv->multi_data[offset] = packet[6];
        priv->multi_data[offset + 1] = packet[7];
 
+       f->left = !!(packet[4] & 0x01);
+       f->right = !!(packet[4] & 0x02);
+
+       f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
+                 ((packet[0] & 0x30) >> 4);
+       f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
+       f->pressure = packet[5] & 0x7f;
+
        if (++priv->multi_packet > 2) {
                priv->multi_packet = 0;
 
@@ -879,14 +895,6 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
                f->fingers = alps_process_bitmap(priv, f);
        }
 
-       f->left = !!(packet[4] & 0x01);
-       f->right = !!(packet[4] & 0x02);
-
-       f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
-                 ((packet[0] & 0x30) >> 4);
-       f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
-       f->pressure = packet[5] & 0x7f;
-
        alps_report_semi_mt_data(psmouse, f->fingers);
 }
 
@@ -2561,7 +2569,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
        case ALPS_PROTO_V3:
                priv->hw_init = alps_hw_init_v3;
                priv->process_packet = alps_process_packet_v3;
-               priv->set_abs_params = alps_set_abs_params_mt;
+               priv->set_abs_params = alps_set_abs_params_semi_mt;
                priv->decode_fields = alps_decode_pinnacle;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
@@ -2570,7 +2578,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
        case ALPS_PROTO_V3_RUSHMORE:
                priv->hw_init = alps_hw_init_rushmore_v3;
                priv->process_packet = alps_process_packet_v3;
-               priv->set_abs_params = alps_set_abs_params_mt;
+               priv->set_abs_params = alps_set_abs_params_semi_mt;
                priv->decode_fields = alps_decode_rushmore;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
@@ -2586,7 +2594,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
        case ALPS_PROTO_V4:
                priv->hw_init = alps_hw_init_v4;
                priv->process_packet = alps_process_packet_v4;
-               priv->set_abs_params = alps_set_abs_params_mt;
+               priv->set_abs_params = alps_set_abs_params_semi_mt;
                priv->nibble_commands = alps_v4_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_DISABLE;
                break;
@@ -2595,7 +2603,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
                priv->hw_init = alps_hw_init_dolphin_v1;
                priv->process_packet = alps_process_touchpad_packet_v3_v5;
                priv->decode_fields = alps_decode_dolphin;
-               priv->set_abs_params = alps_set_abs_params_mt;
+               priv->set_abs_params = alps_set_abs_params_semi_mt;
                priv->nibble_commands = alps_v3_nibble_commands;
                priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
                priv->x_bits = 23;
@@ -2777,15 +2785,15 @@ static void alps_set_abs_params_mt_common(struct alps_data *priv,
        set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
 }
 
-static void alps_set_abs_params_mt(struct alps_data *priv,
-                                  struct input_dev *dev1)
+static void alps_set_abs_params_semi_mt(struct alps_data *priv,
+                                       struct input_dev *dev1)
 {
        alps_set_abs_params_mt_common(priv, dev1);
        input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
 
        input_mt_init_slots(dev1, MAX_TOUCHES,
                            INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
-                               INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
+                               INPUT_MT_SEMI_MT);
 }
 
 static void alps_set_abs_params_v7(struct alps_data *priv,
index 6dfdccc..d37f814 100644 (file)
@@ -278,6 +278,7 @@ struct alps_data {
 
        int prev_fin;
        int multi_packet;
+       int second_touch;
        unsigned char multi_data[6];
        struct alps_fields f;
        u8 quirks;
index 1e2291c..3faf01c 100644 (file)
@@ -950,14 +950,13 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode)
  * Device power mode can only be set when device is in operational mode.
  */
 static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
-               u16 always_unused)
+                                    u16 always_unused)
 {
        int ret;
        u8 power;
        int tries;
        u16 sleep_time;
 
-       always_unused = 0;
        if (cyapa->state != CYAPA_STATE_OP)
                return 0;
 
index 5b611dd..afc39e7 100644 (file)
@@ -352,7 +352,7 @@ struct gen5_app_cmd_head {
        u8 parameter_data[0];  /* Parameter data variable based on cmd_code */
 } __packed;
 
-/* Applicaton get/set parameter command data structure */
+/* Application get/set parameter command data structure */
 struct gen5_app_set_parameter_data {
        u8 parameter_id;
        u8 parameter_size;
@@ -832,7 +832,7 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
        int ret;
 
        /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
-        * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
+        * 0x20 0x00 0xFF is Gen5 Bootloader HID Description Header.
         *
         * Must read HID Description content through out,
         * otherwise Gen5 trackpad cannot response next command
@@ -1654,8 +1654,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
                 * that trackpad unable to report signal to wake system up
                 * in the special situation that system is in suspending, and
                 * at the same time, user touch trackpad to wake system up.
-                * This function can avoid the data to be buffured when system
-                * is suspending which may cause interrput line unable to be
+                * This function can avoid the data to be buffered when system
+                * is suspending which may cause interrupt line unable to be
                 * asserted again.
                 */
                cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
@@ -2546,16 +2546,11 @@ static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
                        gen5_pip->resp_sort_func(cyapa,
                                gen5_pip->irq_cmd_buf, length))) {
                        /*
-                        * Cover the Gen5 V1 firmware issue.
-                        * The issue is there is no interrut will be
-                        * asserted to notityf host to read a command
-                        * data out when always has finger touch on
-                        * trackpad during the command is issued to
-                        * trackad device.
-                        * This issue has the scenario is that,
-                        * user always has his fingers touched on
-                        * trackpad device when booting/rebooting
-                        * their chrome book.
+                        * Work around the Gen5 V1 firmware
+                        * that does not assert interrupt signalling
+                        * that command response is ready if user
+                        * keeps touching the trackpad while command
+                        * is sent to the device.
                         */
                        length = 0;
                        if (gen5_pip->resp_len)
index 6d5f8a4..73670f2 100644 (file)
 #define ETP_PRESSURE_OFFSET    25
 
 /* IAP Firmware handling */
-#define ETP_FW_NAME            "elan_i2c.bin"
+#define ETP_PRODUCT_ID_FORMAT_STRING   "%d.0"
+#define ETP_FW_NAME            "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
 #define ETP_IAP_START_ADDR     0x0083
 #define ETP_FW_IAP_PAGE_ERR    (1 << 5)
 #define ETP_FW_IAP_INTF_ERR    (1 << 4)
 #define ETP_FW_PAGE_SIZE       64
-#define ETP_FW_VAILDPAGE_COUNT 768
 #define ETP_FW_SIGNATURE_SIZE  6
-#define ETP_FW_SIGNATURE_ADDRESS       0xBFFA
 
 struct i2c_client;
 struct completion;
@@ -58,7 +57,8 @@ struct elan_transport_ops {
                                 bool max_baseliune, u8 *value);
 
        int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
-       int (*get_sm_version)(struct i2c_client *client, u8 *version);
+       int (*get_sm_version)(struct i2c_client *client,
+                             u8* ic_type, u8 *version);
        int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
        int (*get_product_id)(struct i2c_client *client, u8 *id);
 
index fd5068b..62641f2 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2013 ELAN Microelectronics Corp.
  *
  * Author: æž—政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.7
+ * Version: 1.5.9
  *
  * Based on cyapa driver:
  * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +40,7 @@
 #include "elan_i2c.h"
 
 #define DRIVER_NAME            "elan_i2c"
-#define ELAN_DRIVER_VERSION    "1.5.7"
+#define ELAN_DRIVER_VERSION    "1.5.9"
 #define ETP_MAX_PRESSURE       255
 #define ETP_FWIDTH_REDUCE      90
 #define ETP_FINGER_WIDTH       15
@@ -83,6 +83,9 @@ struct elan_tp_data {
        u16                     fw_checksum;
        int                     pressure_adjustment;
        u8                      mode;
+       u8                      ic_type;
+       u16                     fw_vaildpage_count;
+       u16                     fw_signature_address;
 
        bool                    irq_wake;
 
@@ -91,6 +94,29 @@ struct elan_tp_data {
        bool                    baseline_ready;
 };
 
+static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count,
+                          u16 *signature_address)
+{
+       switch(ic_type) {
+       case 0x09:
+               *vaildpage_count = 768;
+               break;
+       case 0x0D:
+               *vaildpage_count = 896;
+               break;
+       default:
+               /* unknown ic type clear value */
+               *vaildpage_count = 0;
+               *signature_address = 0;
+               return -ENXIO;
+       }
+
+       *signature_address =
+               (*vaildpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;
+
+       return 0;
+}
+
 static int elan_enable_power(struct elan_tp_data *data)
 {
        int repeat = ETP_RETRY_COUNT;
@@ -221,7 +247,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
        if (error)
                return error;
 
-       error = data->ops->get_sm_version(data->client, &data->sm_version);
+       error = data->ops->get_sm_version(data->client, &data->ic_type,
+                                         &data->sm_version);
        if (error)
                return error;
 
@@ -234,6 +261,14 @@ static int elan_query_device_info(struct elan_tp_data *data)
        if (error)
                return error;
 
+       error = elan_get_fwinfo(data->ic_type, &data->fw_vaildpage_count,
+                               &data->fw_signature_address);
+       if (error) {
+               dev_err(&data->client->dev,
+                       "unknown ic type %d\n", data->ic_type);
+               return error;
+       }
+
        return 0;
 }
 
@@ -318,7 +353,7 @@ static int __elan_update_firmware(struct elan_tp_data *data,
        iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
 
        boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
-       for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) {
+       for (i = boot_page_count; i < data->fw_vaildpage_count; i++) {
                u16 checksum = 0;
                const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
 
@@ -403,7 +438,8 @@ static ssize_t elan_sysfs_read_product_id(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct elan_tp_data *data = i2c_get_clientdata(client);
 
-       return sprintf(buf, "%d.0\n", data->product_id);
+       return sprintf(buf, ETP_PRODUCT_ID_FORMAT_STRING "\n",
+                      data->product_id);
 }
 
 static ssize_t elan_sysfs_read_fw_ver(struct device *dev,
@@ -442,19 +478,28 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
 {
        struct elan_tp_data *data = dev_get_drvdata(dev);
        const struct firmware *fw;
+       char *fw_name;
        int error;
        const u8 *fw_signature;
        static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
 
-       error = request_firmware(&fw, ETP_FW_NAME, dev);
+       /* Look for a firmware with the product id appended. */
+       fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id);
+       if (!fw_name) {
+               dev_err(dev, "failed to allocate memory for firmware name\n");
+               return -ENOMEM;
+       }
+
+       dev_info(dev, "requesting fw '%s'\n", fw_name);
+       error = request_firmware(&fw, fw_name, dev);
+       kfree(fw_name);
        if (error) {
-               dev_err(dev, "cannot load firmware %s: %d\n",
-                       ETP_FW_NAME, error);
+               dev_err(dev, "failed to request firmware: %d\n", error);
                return error;
        }
 
        /* Firmware file must match signature data */
-       fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS];
+       fw_signature = &fw->data[data->fw_signature_address];
        if (memcmp(fw_signature, signature, sizeof(signature)) != 0) {
                dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
                        (int)sizeof(signature), signature,
index a0acbbf..683c840 100644 (file)
@@ -259,7 +259,8 @@ static int elan_i2c_get_version(struct i2c_client *client,
        return 0;
 }
 
-static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_i2c_get_sm_version(struct i2c_client *client,
+                                  u8 *ic_type, u8 *version)
 {
        int error;
        u8 val[3];
@@ -271,6 +272,7 @@ static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
        }
 
        *version = val[0];
+       *ic_type = val[1];
        return 0;
 }
 
index 30ab80d..ff36a36 100644 (file)
@@ -165,7 +165,8 @@ static int elan_smbus_get_version(struct i2c_client *client,
        return 0;
 }
 
-static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
+static int elan_smbus_get_sm_version(struct i2c_client *client,
+                                    u8 *ic_type, u8 *version)
 {
        int error;
        u8 val[3];
@@ -177,7 +178,8 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
                return error;
        }
 
-       *version = val[0]; /* XXX Why 0 and not 2 as in IAP/FW versions? */
+       *version = val[0];
+       *ic_type = val[1];
        return 0;
 }
 
index 23d2594..4d5576d 100644 (file)
@@ -103,6 +103,16 @@ struct focaltech_hw_state {
         */
        struct focaltech_finger_state fingers[FOC_MAX_FINGERS];
 
+       /*
+        * Finger width 0-7 and 15 for a very big contact area.
+        * 15 value stays until the finger is released.
+        * Width is reported only in absolute packets.
+        * Since hardware reports width only for last touching finger,
+        * there is no need to store width for every specific finger,
+        * so we keep only last value reported.
+        */
+       unsigned int width;
+
        /* True if the clickpad has been pressed. */
        bool pressed;
 };
@@ -137,6 +147,7 @@ static void focaltech_report_state(struct psmouse *psmouse)
                        input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
                        input_report_abs(dev, ABS_MT_POSITION_Y,
                                         priv->y_max - clamped_y);
+                       input_report_abs(dev, ABS_TOOL_WIDTH, state->width);
                }
        }
        input_mt_report_pointer_emulation(dev, true);
@@ -187,6 +198,7 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse,
 
        state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
        state->fingers[finger].y = (packet[3] << 8) | packet[4];
+       state->width = packet[5] >> 4;
        state->fingers[finger].valid = true;
 }
 
@@ -331,6 +343,7 @@ static void focaltech_set_input_params(struct psmouse *psmouse)
        __set_bit(EV_ABS, dev->evbit);
        input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
        input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
+       input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
        input_mt_init_slots(dev, 5, INPUT_MT_POINTER);
        __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
 }
index 5bb1658..7c4ba43 100644 (file)
@@ -63,7 +63,7 @@ static unsigned int psmouse_rate = 100;
 module_param_named(rate, psmouse_rate, uint, 0644);
 MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
 
-static bool psmouse_smartscroll = 1;
+static bool psmouse_smartscroll = true;
 module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
index aa697ec..42df9e3 100644 (file)
@@ -123,11 +123,11 @@ struct fsp_data {
 extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
 extern int fsp_init(struct psmouse *psmouse);
 #else
-inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
+static inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
 {
        return -ENOSYS;
 }
-inline int fsp_init(struct psmouse *psmouse)
+static inline int fsp_init(struct psmouse *psmouse)
 {
        return -ENOSYS;
 }
index 878f184..ffceedc 100644 (file)
 #define NO_DATA_SLEEP_MSECS    (MSEC_PER_SEC / 4)
 
 /* Control touchpad's No Deceleration option */
-static bool no_decel = 1;
+static bool no_decel = true;
 module_param(no_decel, bool, 0644);
 MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
 
@@ -340,9 +340,9 @@ static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
        s32 data;
        s8 x_delta, y_delta;
 
-       /* Deal with spontanious resets and errors */
+       /* Deal with spontaneous resets and errors */
        if (synaptics_i2c_check_error(touch->client))
-               return 0;
+               return false;
 
        /* Get Gesture Bit */
        data = synaptics_i2c_reg_get(touch->client, DATA_REG0);
index 547f67d..a398d63 100644 (file)
@@ -958,6 +958,7 @@ config TOUCHSCREEN_ST1232
 config TOUCHSCREEN_STMPE
        tristate "STMicroelectronics STMPE touchscreens"
        depends on MFD_STMPE
+       depends on (OF || COMPILE_TEST)
        help
          Say Y here if you want support for STMicroelectronics
          STMPE touchscreen controllers.
index 40b98dd..dfc7309 100644 (file)
@@ -726,15 +726,15 @@ static void mxt_input_button(struct mxt_data *data, u8 *message)
 {
        struct input_dev *input = data->input_dev;
        const struct mxt_platform_data *pdata = data->pdata;
-       bool button;
        int i;
 
-       /* Active-low switch */
        for (i = 0; i < pdata->t19_num_keys; i++) {
                if (pdata->t19_keymap[i] == KEY_RESERVED)
                        continue;
-               button = !(message[1] & (1 << i));
-               input_report_key(input, pdata->t19_keymap[i], button);
+
+               /* Active-low switch */
+               input_report_key(input, pdata->t19_keymap[i],
+                                !(message[1] & BIT(i)));
        }
 }
 
index 568a3d3..5ed3105 100644 (file)
@@ -775,7 +775,6 @@ static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
        struct device *dev = &md->input->dev;
        struct cyttsp4_sysinfo *si = md->si;
        enum cyttsp4_tch_abs abs;
-       int tmp;
        bool flipped;
 
        for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
@@ -790,9 +789,7 @@ static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
        }
 
        if (md->pdata->flags & CY_FLAG_FLIP) {
-               tmp = touch->abs[CY_TCH_X];
-               touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
-               touch->abs[CY_TCH_Y] = tmp;
+               swap(touch->abs[CY_TCH_X], touch->abs[CY_TCH_Y]);
                flipped = true;
        } else
                flipped = false;
index 3af1698..b4d12e2 100644 (file)
@@ -47,7 +47,7 @@ struct goodix_ts_data {
 /* Register defines */
 #define GOODIX_READ_COOR_ADDR          0x814E
 #define GOODIX_REG_CONFIG_DATA         0x8047
-#define GOODIX_REG_VERSION             0x8140
+#define GOODIX_REG_ID                  0x8140
 
 #define RESOLUTION_LOC         1
 #define MAX_CONTACTS_LOC       5
@@ -69,7 +69,7 @@ static const unsigned long goodix_irq_flags[] = {
  * @len: length of the buffer to write
  */
 static int goodix_i2c_read(struct i2c_client *client,
-                               u16 reg, u8 *buf, int len)
+                          u16 reg, u8 *buf, int len)
 {
        struct i2c_msg msgs[2];
        u16 wbuf = cpu_to_be16(reg);
@@ -78,7 +78,7 @@ static int goodix_i2c_read(struct i2c_client *client,
        msgs[0].flags = 0;
        msgs[0].addr  = client->addr;
        msgs[0].len   = 2;
-       msgs[0].buf   = (u8 *) &wbuf;
+       msgs[0].buf   = (u8 *)&wbuf;
 
        msgs[1].flags = I2C_M_RD;
        msgs[1].addr  = client->addr;
@@ -101,6 +101,9 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
                return error;
        }
 
+       if (!(data[0] & 0x80))
+               return -EAGAIN;
+
        touch_num = data[0] & 0x0f;
        if (touch_num > ts->max_touch_num)
                return -EPROTO;
@@ -144,7 +147,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
  */
 static void goodix_process_events(struct goodix_ts_data *ts)
 {
-       u8  point_data[1 + GOODIX_CONTACT_SIZE * ts->max_touch_num];
+       u8  point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
        int touch_num;
        int i;
 
@@ -196,8 +199,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
        int error;
 
        error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
-                             config,
-                          GOODIX_CONFIG_MAX_LENGTH);
+                               config,
+                               GOODIX_CONFIG_MAX_LENGTH);
        if (error) {
                dev_warn(&ts->client->dev,
                         "Error reading config (%d), using defaults\n",
@@ -227,22 +230,28 @@ static void goodix_read_config(struct goodix_ts_data *ts)
  *
  * @client: the i2c client
  * @version: output buffer containing the version on success
+ * @id: output buffer containing the id on success
  */
-static int goodix_read_version(struct i2c_client *client, u16 *version)
+static int goodix_read_version(struct i2c_client *client, u16 *version, u16 *id)
 {
        int error;
        u8 buf[6];
+       char id_str[5];
 
-       error = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf));
+       error = goodix_i2c_read(client, GOODIX_REG_ID, buf, sizeof(buf));
        if (error) {
                dev_err(&client->dev, "read version failed: %d\n", error);
                return error;
        }
 
-       if (version)
-               *version = get_unaligned_le16(&buf[4]);
+       memcpy(id_str, buf, 4);
+       id_str[4] = 0;
+       if (kstrtou16(id_str, 10, id))
+               *id = 0x1001;
+
+       *version = get_unaligned_le16(&buf[4]);
 
-       dev_info(&client->dev, "IC VERSION: %6ph\n", buf);
+       dev_info(&client->dev, "ID %d, version: %04x\n", *id, *version);
 
        return 0;
 }
@@ -276,10 +285,13 @@ static int goodix_i2c_test(struct i2c_client *client)
  * goodix_request_input_dev - Allocate, populate and register the input device
  *
  * @ts: our goodix_ts_data pointer
+ * @version: device firmware version
+ * @id: device ID
  *
  * Must be called during probe
  */
-static int goodix_request_input_dev(struct goodix_ts_data *ts)
+static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
+                                   u16 id)
 {
        int error;
 
@@ -289,14 +301,10 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
                return -ENOMEM;
        }
 
-       ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) |
-                                 BIT_MASK(EV_KEY) |
-                                 BIT_MASK(EV_ABS);
-
-       input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
-                               ts->abs_x_max, 0, 0);
-       input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
-                               ts->abs_y_max, 0, 0);
+       input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+                            0, ts->abs_x_max, 0, 0);
+       input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+                            0, ts->abs_y_max, 0, 0);
        input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
        input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
 
@@ -307,8 +315,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
        ts->input_dev->phys = "input/ts";
        ts->input_dev->id.bustype = BUS_I2C;
        ts->input_dev->id.vendor = 0x0416;
-       ts->input_dev->id.product = 0x1001;
-       ts->input_dev->id.version = 10427;
+       ts->input_dev->id.product = id;
+       ts->input_dev->id.version = version;
 
        error = input_register_device(ts->input_dev);
        if (error) {
@@ -326,7 +334,7 @@ static int goodix_ts_probe(struct i2c_client *client,
        struct goodix_ts_data *ts;
        unsigned long irq_flags;
        int error;
-       u16 version_info;
+       u16 version_info, id_info;
 
        dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
 
@@ -348,7 +356,7 @@ static int goodix_ts_probe(struct i2c_client *client,
                return error;
        }
 
-       error = goodix_read_version(client, &version_info);
+       error = goodix_read_version(client, &version_info, &id_info);
        if (error) {
                dev_err(&client->dev, "Read version failed.\n");
                return error;
@@ -356,7 +364,7 @@ static int goodix_ts_probe(struct i2c_client *client,
 
        goodix_read_config(ts);
 
-       error = goodix_request_input_dev(ts);
+       error = goodix_request_input_dev(ts, version_info, id_info);
        if (error)
                return error;
 
index bdfa27d..a4a103e 100644 (file)
@@ -411,7 +411,7 @@ static const struct dev_pm_ops s3c_ts_pmops = {
 };
 #endif
 
-static struct platform_device_id s3cts_driver_ids[] = {
+static const struct platform_device_id s3cts_driver_ids[] = {
        { "s3c2410-ts", 0 },
        { "s3c2440-ts", 0 },
        { "s3c64xx-ts", FEAT_PEN_IRQ },
index e4c3125..e414d43 100644 (file)
@@ -267,27 +267,10 @@ static void stmpe_ts_close(struct input_dev *dev)
 static void stmpe_ts_get_platform_info(struct platform_device *pdev,
                                        struct stmpe_touch *ts)
 {
-       struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
        struct device_node *np = pdev->dev.of_node;
-       struct stmpe_ts_platform_data *ts_pdata = NULL;
-
-       ts->stmpe = stmpe;
-
-       if (stmpe->pdata && stmpe->pdata->ts) {
-               ts_pdata = stmpe->pdata->ts;
-
-               ts->sample_time = ts_pdata->sample_time;
-               ts->mod_12b = ts_pdata->mod_12b;
-               ts->ref_sel = ts_pdata->ref_sel;
-               ts->adc_freq = ts_pdata->adc_freq;
-               ts->ave_ctrl = ts_pdata->ave_ctrl;
-               ts->touch_det_delay = ts_pdata->touch_det_delay;
-               ts->settling = ts_pdata->settling;
-               ts->fraction_z = ts_pdata->fraction_z;
-               ts->i_drive = ts_pdata->i_drive;
-       } else if (np) {
-               u32 val;
+       u32 val;
 
+       if (np) {
                if (!of_property_read_u32(np, "st,sample-time", &val))
                        ts->sample_time = val;
                if (!of_property_read_u32(np, "st,mod-12b", &val))
@@ -311,6 +294,7 @@ static void stmpe_ts_get_platform_info(struct platform_device *pdev,
 
 static int stmpe_input_probe(struct platform_device *pdev)
 {
+       struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
        struct stmpe_touch *ts;
        struct input_dev *idev;
        int error;
@@ -329,6 +313,7 @@ static int stmpe_input_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, ts);
+       ts->stmpe = stmpe;
        ts->idev = idev;
        ts->dev = &pdev->dev;
 
@@ -351,14 +336,13 @@ static int stmpe_input_probe(struct platform_device *pdev)
        idev->name = STMPE_TS_NAME;
        idev->phys = STMPE_TS_NAME"/input0";
        idev->id.bustype = BUS_I2C;
-       idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-       idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
        idev->open = stmpe_ts_open;
        idev->close = stmpe_ts_close;
 
        input_set_drvdata(idev, ts);
 
+       input_set_capability(idev, EV_KEY, BTN_TOUCH);
        input_set_abs_params(idev, ABS_X, 0, XY_MASK, 0, 0);
        input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
        input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
@@ -383,14 +367,19 @@ static int stmpe_ts_remove(struct platform_device *pdev)
 
 static struct platform_driver stmpe_ts_driver = {
        .driver = {
-                  .name = STMPE_TS_NAME,
-                  },
+               .name = STMPE_TS_NAME,
+       },
        .probe = stmpe_input_probe,
        .remove = stmpe_ts_remove,
 };
 module_platform_driver(stmpe_ts_driver);
 
+static const struct of_device_id stmpe_ts_ids[] = {
+       { .compatible = "st,stmpe-ts", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, stmpe_ts_ids);
+
 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
 MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" STMPE_TS_NAME);
index 19880c7..f58a196 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/input/mt.h>
 #include <linux/platform_data/zforce_ts.h>
 #include <linux/regulator/consumer.h>
-#include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 
index 25b320d..95029df 100644 (file)
@@ -11,9 +11,6 @@ menuconfig NEW_LEDS
          Say Y to enable Linux LED support.  This allows control of supported
          LEDs from both userspace and optionally, by kernel events (triggers).
 
-         This is not related to standard keyboard LEDs which are controlled
-         via the input system.
-
 if NEW_LEDS
 
 config LEDS_CLASS
index 259a4d5..b21881e 100644 (file)
@@ -55,9 +55,6 @@
 static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
-unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
-int sysrq_reset_downtime_ms __weak;
-
 static bool sysrq_on(void)
 {
        return sysrq_enabled || sysrq_always_enabled;
@@ -568,6 +565,7 @@ void handle_sysrq(int key)
 EXPORT_SYMBOL(handle_sysrq);
 
 #ifdef CONFIG_INPUT
+static int sysrq_reset_downtime_ms;
 
 /* Simple translation table for the SysRq keys */
 static const unsigned char sysrq_xlate[KEY_CNT] =
@@ -948,23 +946,8 @@ static bool sysrq_handler_registered;
 
 static inline void sysrq_register_handler(void)
 {
-       unsigned short key;
        int error;
-       int i;
-
-       /* First check if a __weak interface was instantiated. */
-       for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
-               key = platform_sysrq_reset_seq[i];
-               if (key == KEY_RESERVED || key > KEY_MAX)
-                       break;
-
-               sysrq_reset_seq[sysrq_reset_seq_len++] = key;
-       }
 
-       /*
-        * DT configuration takes precedence over anything that would
-        * have been defined via the __weak interface.
-        */
        sysrq_of_get_keyreset_config();
 
        error = input_register_handler(&sysrq_handler);
index 8a89f6e..6f0336f 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <linux/kbd_kern.h>
 #include <linux/kbd_diacr.h>
@@ -129,7 +130,7 @@ static char rep;                                    /* flag telling character repeat */
 
 static int shift_state = 0;
 
-static unsigned char ledstate = 0xff;                  /* undefined */
+static unsigned int ledstate = -1U;                    /* undefined */
 static unsigned char ledioctl;
 
 /*
@@ -961,6 +962,122 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
        }
 }
 
+#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS)
+
+struct kbd_led_trigger {
+       struct led_trigger trigger;
+       unsigned int mask;
+};
+
+static void kbd_led_trigger_activate(struct led_classdev *cdev)
+{
+       struct kbd_led_trigger *trigger =
+               container_of(cdev->trigger, struct kbd_led_trigger, trigger);
+
+       tasklet_disable(&keyboard_tasklet);
+       if (ledstate != -1U)
+               led_trigger_event(&trigger->trigger,
+                                 ledstate & trigger->mask ?
+                                       LED_FULL : LED_OFF);
+       tasklet_enable(&keyboard_tasklet);
+}
+
+#define KBD_LED_TRIGGER(_led_bit, _name) {                     \
+               .trigger = {                                    \
+                       .name = _name,                          \
+                       .activate = kbd_led_trigger_activate,   \
+               },                                              \
+               .mask   = BIT(_led_bit),                        \
+       }
+
+#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name)         \
+       KBD_LED_TRIGGER((_led_bit) + 8, _name)
+
+static struct kbd_led_trigger kbd_led_triggers[] = {
+       KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"),
+       KBD_LED_TRIGGER(VC_NUMLOCK,   "kbd-numlock"),
+       KBD_LED_TRIGGER(VC_CAPSLOCK,  "kbd-capslock"),
+       KBD_LED_TRIGGER(VC_KANALOCK,  "kbd-kanalock"),
+
+       KBD_LOCKSTATE_TRIGGER(VC_SHIFTLOCK,  "kbd-shiftlock"),
+       KBD_LOCKSTATE_TRIGGER(VC_ALTGRLOCK,  "kbd-altgrlock"),
+       KBD_LOCKSTATE_TRIGGER(VC_CTRLLOCK,   "kbd-ctrllock"),
+       KBD_LOCKSTATE_TRIGGER(VC_ALTLOCK,    "kbd-altlock"),
+       KBD_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"),
+       KBD_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"),
+       KBD_LOCKSTATE_TRIGGER(VC_CTRLLLOCK,  "kbd-ctrlllock"),
+       KBD_LOCKSTATE_TRIGGER(VC_CTRLRLOCK,  "kbd-ctrlrlock"),
+};
+
+static void kbd_propagate_led_state(unsigned int old_state,
+                                   unsigned int new_state)
+{
+       struct kbd_led_trigger *trigger;
+       unsigned int changed = old_state ^ new_state;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
+               trigger = &kbd_led_triggers[i];
+
+               if (changed & trigger->mask)
+                       led_trigger_event(&trigger->trigger,
+                                         new_state & trigger->mask ?
+                                               LED_FULL : LED_OFF);
+       }
+}
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+       unsigned int led_state = *(unsigned int *)data;
+
+       if (test_bit(EV_LED, handle->dev->evbit))
+               kbd_propagate_led_state(~led_state, led_state);
+
+       return 0;
+}
+
+static void kbd_init_leds(void)
+{
+       int error;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
+               error = led_trigger_register(&kbd_led_triggers[i].trigger);
+               if (error)
+                       pr_err("error %d while registering trigger %s\n",
+                              error, kbd_led_triggers[i].trigger.name);
+       }
+}
+
+#else
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+       unsigned int leds = *(unsigned int *)data;
+
+       if (test_bit(EV_LED, handle->dev->evbit)) {
+               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
+               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+       }
+
+       return 0;
+}
+
+static void kbd_propagate_led_state(unsigned int old_state,
+                                   unsigned int new_state)
+{
+       input_handler_for_each_handle(&kbd_handler, &new_state,
+                                     kbd_update_leds_helper);
+}
+
+static void kbd_init_leds(void)
+{
+}
+
+#endif
+
 /*
  * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
  * or (ii) whatever pattern of lights people want to show using KDSETLED,
@@ -968,7 +1085,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
  */
 static unsigned char getledstate(void)
 {
-       return ledstate;
+       return ledstate & 0xff;
 }
 
 void setledstate(struct kbd_struct *kb, unsigned int led)
@@ -995,20 +1112,6 @@ static inline unsigned char getleds(void)
        return kb->ledflagstate;
 }
 
-static int kbd_update_leds_helper(struct input_handle *handle, void *data)
-{
-       unsigned char leds = *(unsigned char *)data;
-
-       if (test_bit(EV_LED, handle->dev->evbit)) {
-               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
-               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
-       }
-
-       return 0;
-}
-
 /**
  *     vt_get_leds     -       helper for braille console
  *     @console: console to read
@@ -1085,24 +1188,23 @@ void vt_kbd_con_stop(int console)
 }
 
 /*
- * This is the tasklet that updates LED state on all keyboards
- * attached to the box. The reason we use tasklet is that we
- * need to handle the scenario when keyboard handler is not
- * registered yet but we already getting updates from the VT to
- * update led state.
+ * This is the tasklet that updates LED state of LEDs using standard
+ * keyboard triggers. The reason we use tasklet is that we need to
+ * handle the scenario when keyboard handler is not registered yet
+ * but we already getting updates from the VT to update led state.
  */
 static void kbd_bh(unsigned long dummy)
 {
-       unsigned char leds;
+       unsigned int leds;
        unsigned long flags;
-       
+
        spin_lock_irqsave(&led_lock, flags);
        leds = getleds();
+       leds |= (unsigned int)kbd->lockstate << 8;
        spin_unlock_irqrestore(&led_lock, flags);
 
        if (leds != ledstate) {
-               input_handler_for_each_handle(&kbd_handler, &leds,
-                                             kbd_update_leds_helper);
+               kbd_propagate_led_state(ledstate, leds);
                ledstate = leds;
        }
 }
@@ -1450,7 +1552,7 @@ static void kbd_start(struct input_handle *handle)
 {
        tasklet_disable(&keyboard_tasklet);
 
-       if (ledstate != 0xff)
+       if (ledstate != -1U)
                kbd_update_leds_helper(handle, &ledstate);
 
        tasklet_enable(&keyboard_tasklet);
@@ -1497,6 +1599,8 @@ int __init kbd_init(void)
                kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
        }
 
+       kbd_init_leds();
+
        error = input_register_handler(&kbd_handler);
        if (error)
                return error;
index 95c8742..612383b 100644 (file)
@@ -103,6 +103,7 @@ struct da9063;
 struct da9063_pdata {
        int                             (*init)(struct da9063 *da9063);
        int                             irq_base;
+       bool                            key_power;
        unsigned                        flags;
        struct da9063_regulators_pdata  *regulators_pdata;
        struct led_platform_data        *leds_pdata;
index c9d8690..cb83883 100644 (file)
@@ -118,47 +118,6 @@ extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks);
 #define STMPE_GPIO_NOREQ_811_TOUCH     (0xf0)
 
 /**
- * struct stmpe_ts_platform_data - stmpe811 touch screen controller platform
- * data
- * @sample_time: ADC converstion time in number of clock.
- * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks,
- * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks),
- * recommended is 4.
- * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
- * @ref_sel: ADC reference source
- * (0 -> internal reference, 1 -> external reference)
- * @adc_freq: ADC Clock speed
- * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
- * @ave_ctrl: Sample average control
- * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
- * @touch_det_delay: Touch detect interrupt delay
- * (0 -> 10 us, 1 -> 50 us, 2 -> 100 us, 3 -> 500 us,
- * 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms)
- * recommended is 3
- * @settling: Panel driver settling time
- * (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3 -> 1 ms,
- * 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms)
- * recommended is 2
- * @fraction_z: Length of the fractional part in z
- * (fraction_z ([0..7]) = Count of the fractional part)
- * recommended is 7
- * @i_drive: current limit value of the touchscreen drivers
- * (0 -> 20 mA typical 35 mA max, 1 -> 50 mA typical 80 mA max)
- *
- * */
-struct stmpe_ts_platform_data {
-       u8 sample_time;
-       u8 mod_12b;
-       u8 ref_sel;
-       u8 adc_freq;
-       u8 ave_ctrl;
-       u8 touch_det_delay;
-       u8 settling;
-       u8 fraction_z;
-       u8 i_drive;
-};
-
-/**
  * struct stmpe_platform_data - STMPE platform data
  * @id: device id to distinguish between multiple STMPEs on the same board
  * @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*)
@@ -168,7 +127,6 @@ struct stmpe_ts_platform_data {
  * @irq_over_gpio: true if gpio is used to get irq
  * @irq_gpio: gpio number over which irq will be requested (significant only if
  *           irq_over_gpio is true)
- * @ts: touchscreen-specific platform data
  */
 struct stmpe_platform_data {
        int id;
@@ -178,8 +136,6 @@ struct stmpe_platform_data {
        bool irq_over_gpio;
        int irq_gpio;
        int autosleep_timeout;
-
-       struct stmpe_ts_platform_data *ts;
 };
 
 #endif
index 9248e3a..5e3ff65 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2010 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ * Rajeev Kumar <rajeevkumar.linux@gmail.com>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any