Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 3 Feb 2020 22:05:15 +0000 (22:05 +0000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 3 Feb 2020 22:05:15 +0000 (22:05 +0000)
Pull input updates from Dmitry Torokhov:

 - a driver for SGI IOC3 PS/2 controller

 - updates to driver for FocalTech FT5x06 series touch screen
   controllers

 - other assorted fixes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: synaptics-rmi4 - switch to reduced reporting mode
  dt-bindings: touchscreen: Convert Goodix touchscreen to json-schema
  dt-bindings: touchscreen: Add touchscreen schema
  Input: add IOC3 serio driver
  Input: axp20x-pek - enable wakeup for all AXP variants
  Input: axp20x-pek - respect userspace wakeup configuration
  Input: ads7846 - use new `delay` structure for SPI transfer delays
  Input: edt-ft5x06 - use pm core to enable/disable the wake irq
  Input: edt-ft5x06 - make wakeup-source switchable
  Input: edt-ft5x06 - document wakeup-source capability
  Input: edt-ft5x06 - alphabetical include reorder
  Input: edt-ft5x06 - work around first register access error
  Input: apbps2 - add __iomem to register struct
  Input: axp20x-pek - make device attributes static
  Input: elants_i2c - check Remark ID when attempting firmware update

14 files changed:
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
Documentation/devicetree/bindings/input/touchscreen/goodix.txt [deleted file]
Documentation/devicetree/bindings/input/touchscreen/goodix.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml [new file with mode: 0644]
drivers/input/misc/axp20x-pek.c
drivers/input/rmi4/rmi_f11.c
drivers/input/serio/Kconfig
drivers/input/serio/Makefile
drivers/input/serio/apbps2.c
drivers/input/serio/ioc3kbd.c [new file with mode: 0644]
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/elants_i2c.c

index 0f69500..0e57315 100644 (file)
@@ -36,6 +36,8 @@ Optional properties:
  - pinctrl-0:   a phandle pointing to the pin settings for the
                 control gpios
 
+ - wakeup-source: If present the device will act as wakeup-source
+
  - threshold:   allows setting the "click"-threshold in the range
                 from 0 to 80.
 
diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
deleted file mode 100644 (file)
index fc03ea4..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-Device tree bindings for Goodix GT9xx series touchscreen controller
-
-Required properties:
-
- - compatible          : Should be "goodix,gt1151"
-                                or "goodix,gt5663"
-                                or "goodix,gt5688"
-                                or "goodix,gt911"
-                                or "goodix,gt9110"
-                                or "goodix,gt912"
-                                or "goodix,gt927"
-                                or "goodix,gt9271"
-                                or "goodix,gt928"
-                                or "goodix,gt967"
- - reg                 : I2C address of the chip. Should be 0x5d or 0x14
- - interrupts          : Interrupt to which the chip is connected
-
-Optional properties:
-
- - irq-gpios           : GPIO pin used for IRQ. The driver uses the
-                         interrupt gpio pin as output to reset the device.
- - reset-gpios         : GPIO pin used for reset
- - AVDD28-supply       : Analog power supply regulator on AVDD28 pin
- - VDDIO-supply                : GPIO power supply regulator on VDDIO pin
- - touchscreen-inverted-x
- - touchscreen-inverted-y
- - touchscreen-size-x
- - touchscreen-size-y
- - touchscreen-swapped-x-y
-
-The touchscreen-* properties are documented in touchscreen.txt in this
-directory.
-
-Example:
-
-       i2c@00000000 {
-               /* ... */
-
-               gt928@5d {
-                       compatible = "goodix,gt928";
-                       reg = <0x5d>;
-                       interrupt-parent = <&gpio>;
-                       interrupts = <0 0>;
-
-                       irq-gpios = <&gpio1 0 0>;
-                       reset-gpios = <&gpio1 1 0>;
-               };
-
-               /* ... */
-       };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml b/Documentation/devicetree/bindings/input/touchscreen/goodix.yaml
new file mode 100644 (file)
index 0000000..d7c3262
--- /dev/null
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/goodix.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Goodix GT9xx series touchscreen controller Bindings
+
+maintainers:
+  - Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+allOf:
+  - $ref: touchscreen.yaml#
+
+properties:
+  compatible:
+    enum:
+      - goodix,gt1151
+      - goodix,gt5663
+      - goodix,gt5688
+      - goodix,gt911
+      - goodix,gt9110
+      - goodix,gt912
+      - goodix,gt927
+      - goodix,gt9271
+      - goodix,gt928
+      - goodix,gt967
+
+  reg:
+    enum: [ 0x5d, 0x14 ]
+
+  interrupts:
+    maxItems: 1
+
+  irq-gpios:
+    description: GPIO pin used for IRQ.
+                 The driver uses the interrupt gpio pin as
+                 output to reset the device.
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+
+  AVDD28-supply:
+    description: Analog power supply regulator on AVDD28 pin
+
+  VDDIO-supply:
+    description: GPIO power supply regulator on VDDIO pin
+
+  touchscreen-inverted-x: true
+  touchscreen-inverted-y: true
+  touchscreen-size-x: true
+  touchscreen-size-y: true
+  touchscreen-swapped-x-y: true
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+examples:
+- |
+    i2c@00000000 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      gt928@5d {
+        compatible = "goodix,gt928";
+        reg = <0x5d>;
+        interrupt-parent = <&gpio>;
+        interrupts = <0 0>;
+        irq-gpios = <&gpio1 0 0>;
+        reset-gpios = <&gpio1 1 0>;
+      };
+    };
+
+...
index 8641a2d..e1adb90 100644 (file)
@@ -1,39 +1 @@
-General Touchscreen Properties:
-
-Optional properties for Touchscreens:
- - touchscreen-min-x           : minimum x coordinate reported (0 if not set)
- - touchscreen-min-y           : minimum y coordinate reported (0 if not set)
- - touchscreen-size-x          : horizontal resolution of touchscreen
-                                 (maximum x coordinate reported + 1)
- - touchscreen-size-y          : vertical resolution of touchscreen
-                                 (maximum y coordinate reported + 1)
- - touchscreen-max-pressure    : maximum reported pressure (arbitrary range
-                                 dependent on the controller)
- - touchscreen-min-pressure    : minimum pressure on the touchscreen to be
-                                 achieved in order for the touchscreen
-                                 driver to report a touch event.
- - touchscreen-fuzz-x          : horizontal noise value of the absolute input
-                                 device (in pixels)
- - touchscreen-fuzz-y          : vertical noise value of the absolute input
-                                 device (in pixels)
- - touchscreen-fuzz-pressure   : pressure noise value of the absolute input
-                                 device (arbitrary range dependent on the
-                                 controller)
- - touchscreen-average-samples : Number of data samples which are averaged
-                                 for each read (valid values dependent on the
-                                 controller)
- - touchscreen-inverted-x      : X axis is inverted (boolean)
- - touchscreen-inverted-y      : Y axis is inverted (boolean)
- - touchscreen-swapped-x-y     : X and Y axis are swapped (boolean)
-                                 Swapping is done after inverting the axis
- - touchscreen-x-mm            : horizontal length in mm of the touchscreen
- - touchscreen-y-mm            : vertical length in mm of the touchscreen
-
-Deprecated properties for Touchscreens:
- - x-size                      : deprecated name for touchscreen-size-x
- - y-size                      : deprecated name for touchscreen-size-y
- - moving-threshold            : deprecated name for a combination of
-                                 touchscreen-fuzz-x and touchscreen-fuzz-y
- - contact-threshold           : deprecated name for touchscreen-fuzz-pressure
- - x-invert                    : deprecated name for touchscreen-inverted-x
- - y-invert                    : deprecated name for touchscreen-inverted-y
+See touchscreen.yaml
diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.yaml
new file mode 100644 (file)
index 0000000..d7dac16
--- /dev/null
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/touchscreen.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Common touchscreen Bindings
+
+maintainers:
+  - Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+properties:
+  touchscreen-min-x:
+    description: minimum x coordinate reported
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 0
+
+  touchscreen-min-y:
+    description: minimum y coordinate reported
+    $ref: /schemas/types.yaml#/definitions/uint32
+    default: 0
+
+  touchscreen-size-x:
+    description: horizontal resolution of touchscreen (maximum x coordinate reported + 1)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-size-y:
+    description: vertical resolution of touchscreen (maximum y coordinate reported + 1)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-max-pressure:
+    description: maximum reported pressure (arbitrary range dependent on the controller)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-min-pressure:
+    description: minimum pressure on the touchscreen to be achieved in order for the
+                 touchscreen driver to report a touch event.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-fuzz-x:
+    description: horizontal noise value of the absolute input device (in pixels)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-fuzz-y:
+    description: vertical noise value of the absolute input device (in pixels)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-fuzz-pressure:
+    description: pressure noise value of the absolute input device (arbitrary range
+                 dependent on the controller)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-average-samples:
+    description: Number of data samples which are averaged for each read (valid values
+                 dependent on the controller)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-inverted-x:
+    description: X axis is inverted
+    type: boolean
+
+  touchscreen-inverted-y:
+    description: Y axis is inverted
+    type: boolean
+
+  touchscreen-swapped-x-y:
+    description: X and Y axis are swapped
+                 Swapping is done after inverting the axis
+    type: boolean
+
+  touchscreen-x-mm:
+    description: horizontal length in mm of the touchscreen
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  touchscreen-y-mm:
+    description: vertical length in mm of the touchscreen
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+dependencies:
+  touchscreen-size-x: [ touchscreen-size-y ]
+  touchscreen-size-y: [ touchscreen-size-x ]
+  touchscreen-x-mm: [ touchscreen-y-mm ]
+  touchscreen-y-mm: [ touchscreen-x-mm ]
index 17c1cca..c8f87df 100644 (file)
@@ -191,9 +191,10 @@ static ssize_t axp20x_store_attr_shutdown(struct device *dev,
                                 axp20x_pek->info->shutdown_mask, buf, count);
 }
 
-DEVICE_ATTR(startup, 0644, axp20x_show_attr_startup, axp20x_store_attr_startup);
-DEVICE_ATTR(shutdown, 0644, axp20x_show_attr_shutdown,
-           axp20x_store_attr_shutdown);
+static DEVICE_ATTR(startup, 0644, axp20x_show_attr_startup,
+                  axp20x_store_attr_startup);
+static DEVICE_ATTR(shutdown, 0644, axp20x_show_attr_shutdown,
+                  axp20x_store_attr_shutdown);
 
 static struct attribute *axp20x_attrs[] = {
        &dev_attr_startup.attr,
@@ -279,8 +280,7 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
                return error;
        }
 
-       if (axp20x_pek->axp20x->variant == AXP288_ID)
-               enable_irq_wake(axp20x_pek->irq_dbr);
+       device_init_wakeup(&pdev->dev, true);
 
        return 0;
 }
@@ -352,6 +352,40 @@ static int axp20x_pek_probe(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused axp20x_pek_suspend(struct device *dev)
+{
+       struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
+
+       /*
+        * As nested threaded IRQs are not automatically disabled during
+        * suspend, we must explicitly disable non-wakeup IRQs.
+        */
+       if (device_may_wakeup(dev)) {
+               enable_irq_wake(axp20x_pek->irq_dbf);
+               enable_irq_wake(axp20x_pek->irq_dbr);
+       } else {
+               disable_irq(axp20x_pek->irq_dbf);
+               disable_irq(axp20x_pek->irq_dbr);
+       }
+
+       return 0;
+}
+
+static int __maybe_unused axp20x_pek_resume(struct device *dev)
+{
+       struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev)) {
+               disable_irq_wake(axp20x_pek->irq_dbf);
+               disable_irq_wake(axp20x_pek->irq_dbr);
+       } else {
+               enable_irq(axp20x_pek->irq_dbf);
+               enable_irq(axp20x_pek->irq_dbr);
+       }
+
+       return 0;
+}
+
 static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
 {
        struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
@@ -371,6 +405,7 @@ static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
 }
 
 static const struct dev_pm_ops axp20x_pek_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(axp20x_pek_suspend, axp20x_pek_resume)
 #ifdef CONFIG_PM_SLEEP
        .resume_noirq = axp20x_pek_resume_noirq,
 #endif
index bbf9ae9..6adea8a 100644 (file)
@@ -412,6 +412,10 @@ struct f11_2d_sensor_queries {
 
 /* Defs for Ctrl0. */
 #define RMI_F11_REPORT_MODE_MASK        0x07
+#define RMI_F11_REPORT_MODE_CONTINUOUS  (0 << 0)
+#define RMI_F11_REPORT_MODE_REDUCED     (1 << 0)
+#define RMI_F11_REPORT_MODE_FS_CHANGE   (2 << 0)
+#define RMI_F11_REPORT_MODE_FP_CHANGE   (3 << 0)
 #define RMI_F11_ABS_POS_FILT            (1 << 3)
 #define RMI_F11_REL_POS_FILT            (1 << 4)
 #define RMI_F11_REL_BALLISTICS          (1 << 5)
@@ -1195,6 +1199,16 @@ static int rmi_f11_initialize(struct rmi_function *fn)
                ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
                        sensor->axis_align.delta_y_threshold;
 
+       /*
+        * If distance threshold values are set, switch to reduced reporting
+        * mode so they actually get used by the controller.
+        */
+       if (ctrl->ctrl0_11[RMI_F11_DELTA_X_THRESHOLD] ||
+           ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD]) {
+               ctrl->ctrl0_11[0] &= ~RMI_F11_REPORT_MODE_MASK;
+               ctrl->ctrl0_11[0] |= RMI_F11_REPORT_MODE_REDUCED;
+       }
+
        if (f11->sens_query.has_dribble) {
                switch (sensor->dribble) {
                case RMI_REG_STATE_OFF:
index f3e18f8..373a164 100644 (file)
@@ -165,6 +165,16 @@ config SERIO_MACEPS2
          To compile this driver as a module, choose M here: the
          module will be called maceps2.
 
+config SERIO_SGI_IOC3
+       tristate "SGI IOC3 PS/2 controller"
+       depends on SGI_MFD_IOC3
+       help
+         Say Y here if you have an SGI Onyx2, SGI Octane or IOC3 PCI card
+         and you want to attach and use a keyboard, mouse, or both.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ioc3kbd.
+
 config SERIO_LIBPS2
        tristate "PS/2 driver library"
        depends on SERIO_I8042 || SERIO_I8042=n
index 67950a5..6d97bad 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_HIL_MLC)         += hp_sdc_mlc.o hil_mlc.o
 obj-$(CONFIG_SERIO_PCIPS2)     += pcips2.o
 obj-$(CONFIG_SERIO_PS2MULT)    += ps2mult.o
 obj-$(CONFIG_SERIO_MACEPS2)    += maceps2.o
+obj-$(CONFIG_SERIO_SGI_IOC3)   += ioc3kbd.o
 obj-$(CONFIG_SERIO_LIBPS2)     += libps2.o
 obj-$(CONFIG_SERIO_RAW)                += serio_raw.o
 obj-$(CONFIG_SERIO_AMS_DELTA)  += ams_delta_serio.o
index f290d5d..594ac4e 100644 (file)
@@ -51,7 +51,7 @@ struct apbps2_regs {
 
 struct apbps2_priv {
        struct serio            *io;
-       struct apbps2_regs      *regs;
+       struct apbps2_regs      __iomem *regs;
 };
 
 static int apbps2_idx;
diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c
new file mode 100644 (file)
index 0000000..d51bfe9
--- /dev/null
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SGI IOC3 PS/2 controller driver for linux
+ *
+ * Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
+ *
+ * Based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org>
+ *               Copyright (C) 2009 Johannes Dickgreber <tanzy@gmx.de>
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/serio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/sn/ioc3.h>
+
+struct ioc3kbd_data {
+       struct ioc3_serioregs __iomem *regs;
+       struct serio *kbd, *aux;
+       bool kbd_exists, aux_exists;
+       int irq;
+};
+
+static int ioc3kbd_wait(struct ioc3_serioregs __iomem *regs, u32 mask)
+{
+       unsigned long timeout = 0;
+
+       while ((readl(&regs->km_csr) & mask) && (timeout < 250)) {
+               udelay(50);
+               timeout++;
+       }
+       return (timeout >= 250) ? -ETIMEDOUT : 0;
+}
+
+static int ioc3kbd_write(struct serio *dev, u8 val)
+{
+       struct ioc3kbd_data *d = dev->port_data;
+       int ret;
+
+       ret = ioc3kbd_wait(d->regs, KM_CSR_K_WRT_PEND);
+       if (ret)
+               return ret;
+
+       writel(val, &d->regs->k_wd);
+
+       return 0;
+}
+
+static int ioc3kbd_start(struct serio *dev)
+{
+       struct ioc3kbd_data *d = dev->port_data;
+
+       d->kbd_exists = true;
+       return 0;
+}
+
+static void ioc3kbd_stop(struct serio *dev)
+{
+       struct ioc3kbd_data *d = dev->port_data;
+
+       d->kbd_exists = false;
+}
+
+static int ioc3aux_write(struct serio *dev, u8 val)
+{
+       struct ioc3kbd_data *d = dev->port_data;
+       int ret;
+
+       ret = ioc3kbd_wait(d->regs, KM_CSR_M_WRT_PEND);
+       if (ret)
+               return ret;
+
+       writel(val, &d->regs->m_wd);
+
+       return 0;
+}
+
+static int ioc3aux_start(struct serio *dev)
+{
+       struct ioc3kbd_data *d = dev->port_data;
+
+       d->aux_exists = true;
+       return 0;
+}
+
+static void ioc3aux_stop(struct serio *dev)
+{
+       struct ioc3kbd_data *d = dev->port_data;
+
+       d->aux_exists = false;
+}
+
+static void ioc3kbd_process_data(struct serio *dev, u32 data)
+{
+       if (data & KM_RD_VALID_0)
+               serio_interrupt(dev, (data >> KM_RD_DATA_0_SHIFT) & 0xff, 0);
+       if (data & KM_RD_VALID_1)
+               serio_interrupt(dev, (data >> KM_RD_DATA_1_SHIFT) & 0xff, 0);
+       if (data & KM_RD_VALID_2)
+               serio_interrupt(dev, (data >> KM_RD_DATA_2_SHIFT) & 0xff, 0);
+}
+
+static irqreturn_t ioc3kbd_intr(int itq, void *dev_id)
+{
+       struct ioc3kbd_data *d = dev_id;
+       u32 data_k, data_m;
+
+       data_k = readl(&d->regs->k_rd);
+       if (d->kbd_exists)
+               ioc3kbd_process_data(d->kbd, data_k);
+
+       data_m = readl(&d->regs->m_rd);
+       if (d->aux_exists)
+               ioc3kbd_process_data(d->aux, data_m);
+
+       return IRQ_HANDLED;
+}
+
+static int ioc3kbd_probe(struct platform_device *pdev)
+{
+       struct ioc3_serioregs __iomem *regs;
+       struct device *dev = &pdev->dev;
+       struct ioc3kbd_data *d;
+       struct serio *sk, *sa;
+       int irq, ret;
+
+       regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return -ENXIO;
+
+       d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       sk = kzalloc(sizeof(*sk), GFP_KERNEL);
+       if (!sk)
+               return -ENOMEM;
+
+       sa = kzalloc(sizeof(*sa), GFP_KERNEL);
+       if (!sa) {
+               kfree(sk);
+               return -ENOMEM;
+       }
+
+       sk->id.type = SERIO_8042;
+       sk->write = ioc3kbd_write;
+       sk->start = ioc3kbd_start;
+       sk->stop = ioc3kbd_stop;
+       snprintf(sk->name, sizeof(sk->name), "IOC3 keyboard %d", pdev->id);
+       snprintf(sk->phys, sizeof(sk->phys), "ioc3/serio%dkbd", pdev->id);
+       sk->port_data = d;
+       sk->dev.parent = dev;
+
+       sa->id.type = SERIO_8042;
+       sa->write = ioc3aux_write;
+       sa->start = ioc3aux_start;
+       sa->stop = ioc3aux_stop;
+       snprintf(sa->name, sizeof(sa->name), "IOC3 auxiliary %d", pdev->id);
+       snprintf(sa->phys, sizeof(sa->phys), "ioc3/serio%daux", pdev->id);
+       sa->port_data = d;
+       sa->dev.parent = dev;
+
+       d->regs = regs;
+       d->kbd = sk;
+       d->aux = sa;
+       d->irq = irq;
+
+       platform_set_drvdata(pdev, d);
+       serio_register_port(d->kbd);
+       serio_register_port(d->aux);
+
+       ret = request_irq(irq, ioc3kbd_intr, IRQF_SHARED, "ioc3-kbd", d);
+       if (ret) {
+               dev_err(dev, "could not request IRQ %d\n", irq);
+               serio_unregister_port(d->kbd);
+               serio_unregister_port(d->aux);
+               return ret;
+       }
+
+       /* enable ports */
+       writel(KM_CSR_K_CLAMP_3 | KM_CSR_M_CLAMP_3, &regs->km_csr);
+
+       return 0;
+}
+
+static int ioc3kbd_remove(struct platform_device *pdev)
+{
+       struct ioc3kbd_data *d = platform_get_drvdata(pdev);
+
+       free_irq(d->irq, d);
+
+       serio_unregister_port(d->kbd);
+       serio_unregister_port(d->aux);
+
+       return 0;
+}
+
+static struct platform_driver ioc3kbd_driver = {
+       .probe          = ioc3kbd_probe,
+       .remove         = ioc3kbd_remove,
+       .driver = {
+               .name = "ioc3-kbd",
+       },
+};
+module_platform_driver(ioc3kbd_driver);
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
+MODULE_DESCRIPTION("SGI IOC3 serio driver");
+MODULE_LICENSE("GPL");
index 51ddb20..8fd7fc3 100644 (file)
@@ -333,7 +333,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
                req->xfer[1].len = 2;
 
                /* for 1uF, settle for 800 usec; no cap, 100 usec.  */
-               req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+               req->xfer[1].delay.value = ts->vref_delay_usecs;
+               req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS;
                spi_message_add_tail(&req->xfer[1], &req->msg);
 
                /* Enable reference voltage */
@@ -1018,7 +1019,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
         * have had enough time to stabilize.
         */
        if (pdata->settle_delay_usecs) {
-               x->delay_usecs = pdata->settle_delay_usecs;
+               x->delay.value = pdata->settle_delay_usecs;
+               x->delay.unit = SPI_DELAY_UNIT_USECS;
 
                x++;
                x->tx_buf = &packet->read_y;
@@ -1061,7 +1063,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
 
        /* ... maybe discard first sample ... */
        if (pdata->settle_delay_usecs) {
-               x->delay_usecs = pdata->settle_delay_usecs;
+               x->delay.value = pdata->settle_delay_usecs;
+               x->delay.unit = SPI_DELAY_UNIT_USECS;
 
                x++;
                x->tx_buf = &packet->read_x;
@@ -1094,7 +1097,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
 
                /* ... maybe discard first sample ... */
                if (pdata->settle_delay_usecs) {
-                       x->delay_usecs = pdata->settle_delay_usecs;
+                       x->delay.value = pdata->settle_delay_usecs;
+                       x->delay.unit = SPI_DELAY_UNIT_USECS;
 
                        x++;
                        x->tx_buf = &packet->read_z1;
@@ -1125,7 +1129,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
 
                /* ... maybe discard first sample ... */
                if (pdata->settle_delay_usecs) {
-                       x->delay_usecs = pdata->settle_delay_usecs;
+                       x->delay.value = pdata->settle_delay_usecs;
+                       x->delay.unit = SPI_DELAY_UNIT_USECS;
 
                        x++;
                        x->tx_buf = &packet->read_z2;
index d61731c..d258772 100644 (file)
  *    http://www.glyn.com/Products/Displays
  */
 
-#include <linux/module.h>
-#include <linux/ratelimit.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/uaccess.h>
-#include <linux/delay.h>
 #include <linux/debugfs.h>
-#include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
-#include <asm/unaligned.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <asm/unaligned.h>
 
 #define WORK_REGISTER_THRESHOLD                0x00
 #define WORK_REGISTER_REPORT_RATE      0x08
@@ -1050,6 +1051,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 {
        const struct edt_i2c_chip_data *chip_data;
        struct edt_ft5x06_ts_data *tsdata;
+       u8 buf[2] = { 0xfc, 0x00 };
        struct input_dev *input;
        unsigned long irq_flags;
        int error;
@@ -1140,6 +1142,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
                return error;
        }
 
+       /*
+        * Dummy read access. EP0700MLP1 returns bogus data on the first
+        * register read access and ignores writes.
+        */
+       edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf);
+
        edt_ft5x06_ts_set_regs(tsdata);
        edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
        edt_ft5x06_ts_get_parameters(tsdata);
@@ -1200,7 +1208,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
                return error;
 
        edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
-       device_init_wakeup(&client->dev, 1);
 
        dev_dbg(&client->dev,
                "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
@@ -1220,29 +1227,6 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
        return 0;
 }
 
-static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-
-       if (device_may_wakeup(dev))
-               enable_irq_wake(client->irq);
-
-       return 0;
-}
-
-static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-
-       if (device_may_wakeup(dev))
-               disable_irq_wake(client->irq);
-
-       return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
-                        edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
-
 static const struct edt_i2c_chip_data edt_ft5x06_data = {
        .max_support_points = 5,
 };
@@ -1281,7 +1265,6 @@ static struct i2c_driver edt_ft5x06_ts_driver = {
        .driver = {
                .name = "edt_ft5x06",
                .of_match_table = edt_ft5x06_of_match,
-               .pm = &edt_ft5x06_ts_pm_ops,
        },
        .id_table = edt_ft5x06_ts_id,
        .probe    = edt_ft5x06_ts_probe,
index d4ad24e..4911799 100644 (file)
 #define CMD_HEADER_WRITE       0x54
 #define CMD_HEADER_READ                0x53
 #define CMD_HEADER_6B_READ     0x5B
+#define CMD_HEADER_ROM_READ    0x96
 #define CMD_HEADER_RESP                0x52
 #define CMD_HEADER_6B_RESP     0x9B
+#define CMD_HEADER_ROM_RESP    0x95
 #define CMD_HEADER_HELLO       0x55
 #define CMD_HEADER_REK         0x66
 
@@ -200,6 +202,10 @@ static int elants_i2c_execute_command(struct i2c_client *client,
                expected_response = CMD_HEADER_6B_RESP;
                break;
 
+       case CMD_HEADER_ROM_READ:
+               expected_response = CMD_HEADER_ROM_RESP;
+               break;
+
        default:
                dev_err(&client->dev, "%s: invalid command %*ph\n",
                        __func__, (int)cmd_size, cmd);
@@ -556,6 +562,8 @@ static int elants_i2c_initialize(struct elants_data *ts)
 
        /* hw version is available even if device in recovery state */
        error2 = elants_i2c_query_hw_version(ts);
+       if (!error2)
+               error2 = elants_i2c_query_bc_version(ts);
        if (!error)
                error = error2;
 
@@ -564,8 +572,6 @@ static int elants_i2c_initialize(struct elants_data *ts)
        if (!error)
                error = elants_i2c_query_test_version(ts);
        if (!error)
-               error = elants_i2c_query_bc_version(ts);
-       if (!error)
                error = elants_i2c_query_ts_info(ts);
 
        if (error)
@@ -613,39 +619,94 @@ static int elants_i2c_fw_write_page(struct i2c_client *client,
        return error;
 }
 
+static int elants_i2c_validate_remark_id(struct elants_data *ts,
+                                        const struct firmware *fw)
+{
+       struct i2c_client *client = ts->client;
+       int error;
+       const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21 };
+       u8 resp[6] = { 0 };
+       u16 ts_remark_id = 0;
+       u16 fw_remark_id = 0;
+
+       /* Compare TS Remark ID and FW Remark ID */
+       error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
+                                       resp, sizeof(resp));
+       if (error) {
+               dev_err(&client->dev, "failed to query Remark ID: %d\n", error);
+               return error;
+       }
+
+       ts_remark_id = get_unaligned_be16(&resp[3]);
+
+       fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]);
+
+       if (fw_remark_id != ts_remark_id) {
+               dev_err(&client->dev,
+                       "Remark ID Mismatched: ts_remark_id=0x%04x, fw_remark_id=0x%04x.\n",
+                       ts_remark_id, fw_remark_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int elants_i2c_do_update_firmware(struct i2c_client *client,
                                         const struct firmware *fw,
                                         bool force)
 {
+       struct elants_data *ts = i2c_get_clientdata(client);
        const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 };
        const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 };
        const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc };
-       const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01};
+       const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 };
        u8 buf[HEADER_SIZE];
        u16 send_id;
        int page, n_fw_pages;
        int error;
+       bool check_remark_id = ts->iap_version >= 0x60;
 
        /* Recovery mode detection! */
        if (force) {
                dev_dbg(&client->dev, "Recovery mode procedure\n");
+
+               if (check_remark_id) {
+                       error = elants_i2c_validate_remark_id(ts, fw);
+                       if (error)
+                               return error;
+               }
+
                error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2));
+               if (error) {
+                       dev_err(&client->dev, "failed to enter IAP mode: %d\n",
+                               error);
+                       return error;
+               }
        } else {
                /* Start IAP Procedure */
                dev_dbg(&client->dev, "Normal IAP procedure\n");
+
                /* Close idle mode */
                error = elants_i2c_send(client, close_idle, sizeof(close_idle));
                if (error)
                        dev_err(&client->dev, "Failed close idle: %d\n", error);
                msleep(60);
+
                elants_i2c_sw_reset(client);
                msleep(20);
-               error = elants_i2c_send(client, enter_iap, sizeof(enter_iap));
-       }
 
-       if (error) {
-               dev_err(&client->dev, "failed to enter IAP mode: %d\n", error);
-               return error;
+               if (check_remark_id) {
+                       error = elants_i2c_validate_remark_id(ts, fw);
+                       if (error)
+                               return error;
+               }
+
+               error = elants_i2c_send(client, enter_iap, sizeof(enter_iap));
+               if (error) {
+                       dev_err(&client->dev, "failed to enter IAP mode: %d\n",
+                               error);
+                       return error;
+               }
        }
 
        msleep(20);