Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Feb 2021 22:56:23 +0000 (14:56 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Feb 2021 22:56:23 +0000 (14:56 -0800)
Pull input updates from Dmitry Torokhov:
 "Mostly existing driver fixes plus a new driver for game controllers
  directly connected to Nintendo 64, and an enhancement for keyboards
  driven by Chrome OS EC to communicate layout of the top row to
  userspace"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (47 commits)
  Input: st1232 - fix NORMAL vs. IDLE state handling
  Input: aiptek - convert sysfs sprintf/snprintf family to sysfs_emit
  Input: alps - fix spelling of "positive"
  ARM: dts: cros-ec-keyboard: Use keymap macros
  dt-bindings: input: Fix the keymap for LOCK key
  dt-bindings: input: Create macros for cros-ec keymap
  Input: cros-ec-keyb - expose function row physical map to userspace
  dt-bindings: input: cros-ec-keyb: Add a new property describing top row
  Input: applespi - fix occasional crc errors under load.
  Input: applespi - don't wait for responses to commands indefinitely.
  Input: st1232 - add IDLE state as ready condition
  Input: zinitix - fix return type of zinitix_init_touch()
  Input: i8042 - add ASUS Zenbook Flip to noselftest list
  Input: add missing dependencies on CONFIG_HAS_IOMEM
  Input: joydev - prevent potential read overflow in ioctl
  Input: elo - fix an error code in elo_connect()
  Input: xpad - add support for PowerA Enhanced Wired Controller for Xbox Series X|S
  Input: sur40 - fix an error code in sur40_probe()
  Input: elants_i2c - detect enum overflow
  Input: zinitix - remove unneeded semicolon
  ...

32 files changed:
Documentation/ABI/testing/sysfs-driver-input-cros-ec-keyb [new file with mode: 0644]
Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml
arch/arm/boot/dts/cros-ec-keyboard.dtsi
drivers/input/joydev.c
drivers/input/joystick/Kconfig
drivers/input/joystick/Makefile
drivers/input/joystick/n64joy.c [new file with mode: 0644]
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/applespi.c
drivers/input/keyboard/cros_ec_keyb.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/misc/da7280.c
drivers/input/mouse/alps.c
drivers/input/mouse/synaptics.c
drivers/input/serio/Kconfig
drivers/input/serio/i8042-x86ia64io.h
drivers/input/tablet/aiptek.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/elants_i2c.c
drivers/input/touchscreen/elo.c
drivers/input/touchscreen/iqs5xx.c
drivers/input/touchscreen/melfas_mip4.c
drivers/input/touchscreen/raydium_i2c_ts.c
drivers/input/touchscreen/st1232.c
drivers/input/touchscreen/stmpe-ts.c
drivers/input/touchscreen/sur40.c
drivers/input/touchscreen/surface3_spi.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/zinitix.c
include/dt-bindings/input/cros-ec-keyboard.h [new file with mode: 0644]

diff --git a/Documentation/ABI/testing/sysfs-driver-input-cros-ec-keyb b/Documentation/ABI/testing/sysfs-driver-input-cros-ec-keyb
new file mode 100644 (file)
index 0000000..c7afc23
--- /dev/null
@@ -0,0 +1,6 @@
+What:          /sys/class/input/input(x)/device/function_row_physmap
+Date:          January 2021
+Contact:       Philip Chen <philipchen@chromium.org>
+Description:   A space separated list of scancodes for the top row keys,
+               ordered by the physical positions of the keys, from left
+               to right.
index 8e50c14..5377b23 100644 (file)
@@ -31,6 +31,17 @@ properties:
       if the EC does not have its own logic or hardware for this.
     type: boolean
 
+  function-row-physmap:
+    minItems: 1
+    maxItems: 15
+    description: |
+      An ordered u32 array describing the rows/columns (in the scan matrix)
+      of top row keys from physical left (KEY_F1) to right. Each entry
+      encodes the row/column as:
+      (((row) & 0xFF) << 24) | (((column) & 0xFF) << 16)
+      where the lower 16 bits are reserved. This property is specified only
+      when the keyboard has a custom design for the top row keys.
+
 required:
   - compatible
 
@@ -38,11 +49,24 @@ unevaluatedProperties: false
 
 examples:
   - |
+    #include <dt-bindings/input/input.h>
     cros-ec-keyb {
         compatible = "google,cros-ec-keyb";
         keypad,num-rows = <8>;
         keypad,num-columns = <13>;
         google,needs-ghost-filter;
+        function-row-physmap = <
+            MATRIX_KEY(0x00, 0x02, 0)   /* T1 */
+            MATRIX_KEY(0x03, 0x02, 0)   /* T2 */
+            MATRIX_KEY(0x02, 0x02, 0)   /* T3 */
+            MATRIX_KEY(0x01, 0x02, 0)   /* T4 */
+            MATRIX_KEY(0x03, 0x04, 0)   /* T5 */
+            MATRIX_KEY(0x02, 0x04, 0)   /* T6 */
+            MATRIX_KEY(0x01, 0x04, 0)   /* T7 */
+            MATRIX_KEY(0x02, 0x09, 0)   /* T8 */
+            MATRIX_KEY(0x01, 0x09, 0)   /* T9 */
+            MATRIX_KEY(0x00, 0x04, 0)   /* T10 */
+        >;
         /*
          * Keymap entries take the form of 0xRRCCKKKK where
          * RR=Row CC=Column KKKK=Key Code
index 165c5bc..55c4744 100644 (file)
 */
 
 #include <dt-bindings/input/input.h>
+#include <dt-bindings/input/cros-ec-keyboard.h>
 
 &cros_ec {
-       keyboard-controller {
+       keyboard_controller: keyboard-controller {
                compatible = "google,cros-ec-keyb";
                keypad,num-rows = <8>;
                keypad,num-columns = <13>;
                google,needs-ghost-filter;
 
                linux,keymap = <
-                       MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA)
-                       MATRIX_KEY(0x00, 0x02, KEY_F1)
-                       MATRIX_KEY(0x00, 0x03, KEY_B)
-                       MATRIX_KEY(0x00, 0x04, KEY_F10)
-                       MATRIX_KEY(0x00, 0x05, KEY_RO)
-                       MATRIX_KEY(0x00, 0x06, KEY_N)
-                       MATRIX_KEY(0x00, 0x08, KEY_EQUAL)
-                       MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT)
-
-                       MATRIX_KEY(0x01, 0x01, KEY_ESC)
-                       MATRIX_KEY(0x01, 0x02, KEY_F4)
-                       MATRIX_KEY(0x01, 0x03, KEY_G)
-                       MATRIX_KEY(0x01, 0x04, KEY_F7)
-                       MATRIX_KEY(0x01, 0x06, KEY_H)
-                       MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE)
-                       MATRIX_KEY(0x01, 0x09, KEY_F9)
-                       MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE)
-                       MATRIX_KEY(0x01, 0x0c, KEY_HENKAN)
-
-                       MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL)
-                       MATRIX_KEY(0x02, 0x01, KEY_TAB)
-                       MATRIX_KEY(0x02, 0x02, KEY_F3)
-                       MATRIX_KEY(0x02, 0x03, KEY_T)
-                       MATRIX_KEY(0x02, 0x04, KEY_F6)
-                       MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE)
-                       MATRIX_KEY(0x02, 0x06, KEY_Y)
-                       MATRIX_KEY(0x02, 0x07, KEY_102ND)
-                       MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE)
-                       MATRIX_KEY(0x02, 0x09, KEY_F8)
-                       MATRIX_KEY(0x02, 0x0a, KEY_YEN)
-
-                       MATRIX_KEY(0x03, 0x00, KEY_LEFTMETA)
-                       MATRIX_KEY(0x03, 0x01, KEY_GRAVE)
-                       MATRIX_KEY(0x03, 0x02, KEY_F2)
-                       MATRIX_KEY(0x03, 0x03, KEY_5)
-                       MATRIX_KEY(0x03, 0x04, KEY_F5)
-                       MATRIX_KEY(0x03, 0x06, KEY_6)
-                       MATRIX_KEY(0x03, 0x08, KEY_MINUS)
-                       MATRIX_KEY(0x03, 0x09, KEY_F13)
-                       MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH)
-                       MATRIX_KEY(0x03, 0x0c, KEY_MUHENKAN)
-
-                       MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL)
-                       MATRIX_KEY(0x04, 0x01, KEY_A)
-                       MATRIX_KEY(0x04, 0x02, KEY_D)
-                       MATRIX_KEY(0x04, 0x03, KEY_F)
-                       MATRIX_KEY(0x04, 0x04, KEY_S)
-                       MATRIX_KEY(0x04, 0x05, KEY_K)
-                       MATRIX_KEY(0x04, 0x06, KEY_J)
-                       MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON)
-                       MATRIX_KEY(0x04, 0x09, KEY_L)
-                       MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH)
-                       MATRIX_KEY(0x04, 0x0b, KEY_ENTER)
-
-                       MATRIX_KEY(0x05, 0x01, KEY_Z)
-                       MATRIX_KEY(0x05, 0x02, KEY_C)
-                       MATRIX_KEY(0x05, 0x03, KEY_V)
-                       MATRIX_KEY(0x05, 0x04, KEY_X)
-                       MATRIX_KEY(0x05, 0x05, KEY_COMMA)
-                       MATRIX_KEY(0x05, 0x06, KEY_M)
-                       MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT)
-                       MATRIX_KEY(0x05, 0x08, KEY_SLASH)
-                       MATRIX_KEY(0x05, 0x09, KEY_DOT)
-                       MATRIX_KEY(0x05, 0x0b, KEY_SPACE)
-
-                       MATRIX_KEY(0x06, 0x01, KEY_1)
-                       MATRIX_KEY(0x06, 0x02, KEY_3)
-                       MATRIX_KEY(0x06, 0x03, KEY_4)
-                       MATRIX_KEY(0x06, 0x04, KEY_2)
-                       MATRIX_KEY(0x06, 0x05, KEY_8)
-                       MATRIX_KEY(0x06, 0x06, KEY_7)
-                       MATRIX_KEY(0x06, 0x08, KEY_0)
-                       MATRIX_KEY(0x06, 0x09, KEY_9)
-                       MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT)
-                       MATRIX_KEY(0x06, 0x0b, KEY_DOWN)
-                       MATRIX_KEY(0x06, 0x0c, KEY_RIGHT)
-
-                       MATRIX_KEY(0x07, 0x01, KEY_Q)
-                       MATRIX_KEY(0x07, 0x02, KEY_E)
-                       MATRIX_KEY(0x07, 0x03, KEY_R)
-                       MATRIX_KEY(0x07, 0x04, KEY_W)
-                       MATRIX_KEY(0x07, 0x05, KEY_I)
-                       MATRIX_KEY(0x07, 0x06, KEY_U)
-                       MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT)
-                       MATRIX_KEY(0x07, 0x08, KEY_P)
-                       MATRIX_KEY(0x07, 0x09, KEY_O)
-                       MATRIX_KEY(0x07, 0x0b, KEY_UP)
-                       MATRIX_KEY(0x07, 0x0c, KEY_LEFT)
+                       CROS_STD_TOP_ROW_KEYMAP
+                       CROS_STD_MAIN_KEYMAP
                >;
        };
 };
index a2b5fbb..430dc69 100644 (file)
@@ -456,7 +456,7 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
        if (IS_ERR(abspam))
                return PTR_ERR(abspam);
 
-       for (i = 0; i < joydev->nabs; i++) {
+       for (i = 0; i < len && i < joydev->nabs; i++) {
                if (abspam[i] > ABS_MAX) {
                        retval = -EINVAL;
                        goto out;
@@ -480,6 +480,9 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
        int i;
        int retval = 0;
 
+       if (len % sizeof(*keypam))
+               return -EINVAL;
+
        len = min(len, sizeof(joydev->keypam));
 
        /* Validate the map. */
@@ -487,7 +490,7 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
        if (IS_ERR(keypam))
                return PTR_ERR(keypam);
 
-       for (i = 0; i < joydev->nkey; i++) {
+       for (i = 0; i < (len / 2) && i < joydev->nkey; i++) {
                if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
                        retval = -EINVAL;
                        goto out;
index b080f0c..5e38899 100644 (file)
@@ -382,4 +382,11 @@ config JOYSTICK_FSIA6B
          To compile this driver as a module, choose M here: the
          module will be called fsia6b.
 
+config JOYSTICK_N64
+       bool "N64 controller"
+       depends on MACH_NINTENDO64
+       help
+         Say Y here if you want enable support for the four
+         built-in controller ports on the Nintendo 64 console.
+
 endif
index 58232b3..31d720c 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_JOYSTICK_INTERACT)               += interact.o
 obj-$(CONFIG_JOYSTICK_JOYDUMP)         += joydump.o
 obj-$(CONFIG_JOYSTICK_MAGELLAN)                += magellan.o
 obj-$(CONFIG_JOYSTICK_MAPLE)           += maplecontrol.o
+obj-$(CONFIG_JOYSTICK_N64)             += n64joy.o
 obj-$(CONFIG_JOYSTICK_PSXPAD_SPI)      += psxpad-spi.o
 obj-$(CONFIG_JOYSTICK_PXRC)            += pxrc.o
 obj-$(CONFIG_JOYSTICK_SIDEWINDER)      += sidewinder.o
@@ -37,4 +38,3 @@ obj-$(CONFIG_JOYSTICK_WARRIOR)                += warrior.o
 obj-$(CONFIG_JOYSTICK_WALKERA0701)     += walkera0701.o
 obj-$(CONFIG_JOYSTICK_XPAD)            += xpad.o
 obj-$(CONFIG_JOYSTICK_ZHENHUA)         += zhenhua.o
-
diff --git a/drivers/input/joystick/n64joy.c b/drivers/input/joystick/n64joy.c
new file mode 100644 (file)
index 0000000..8bcc529
--- /dev/null
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for the four N64 controllers.
+ *
+ * Copyright (c) 2021 Lauri Kasanen
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/limits.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+
+MODULE_AUTHOR("Lauri Kasanen <cand@gmx.com>");
+MODULE_DESCRIPTION("Driver for N64 controllers");
+MODULE_LICENSE("GPL");
+
+#define PIF_RAM 0x1fc007c0
+
+#define SI_DRAM_REG 0
+#define SI_READ_REG 1
+#define SI_WRITE_REG 4
+#define SI_STATUS_REG 6
+
+#define SI_STATUS_DMA_BUSY  BIT(0)
+#define SI_STATUS_IO_BUSY   BIT(1)
+
+#define N64_CONTROLLER_ID 0x0500
+
+#define MAX_CONTROLLERS 4
+
+static const char *n64joy_phys[MAX_CONTROLLERS] = {
+       "n64joy/port0",
+       "n64joy/port1",
+       "n64joy/port2",
+       "n64joy/port3",
+};
+
+struct n64joy_priv {
+       u64 si_buf[8] ____cacheline_aligned;
+       struct timer_list timer;
+       struct mutex n64joy_mutex;
+       struct input_dev *n64joy_dev[MAX_CONTROLLERS];
+       u32 __iomem *reg_base;
+       u8 n64joy_opened;
+};
+
+struct joydata {
+       unsigned int: 16; /* unused */
+       unsigned int err: 2;
+       unsigned int: 14; /* unused */
+
+       union {
+               u32 data;
+
+               struct {
+                       unsigned int a: 1;
+                       unsigned int b: 1;
+                       unsigned int z: 1;
+                       unsigned int start: 1;
+                       unsigned int up: 1;
+                       unsigned int down: 1;
+                       unsigned int left: 1;
+                       unsigned int right: 1;
+                       unsigned int: 2; /* unused */
+                       unsigned int l: 1;
+                       unsigned int r: 1;
+                       unsigned int c_up: 1;
+                       unsigned int c_down: 1;
+                       unsigned int c_left: 1;
+                       unsigned int c_right: 1;
+                       signed int x: 8;
+                       signed int y: 8;
+               };
+       };
+};
+
+static void n64joy_write_reg(u32 __iomem *reg_base, const u8 reg, const u32 value)
+{
+       writel(value, reg_base + reg);
+}
+
+static u32 n64joy_read_reg(u32 __iomem *reg_base, const u8 reg)
+{
+       return readl(reg_base + reg);
+}
+
+static void n64joy_wait_si_dma(u32 __iomem *reg_base)
+{
+       while (n64joy_read_reg(reg_base, SI_STATUS_REG) &
+              (SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY))
+               cpu_relax();
+}
+
+static void n64joy_exec_pif(struct n64joy_priv *priv, const u64 in[8])
+{
+       unsigned long flags;
+
+       dma_cache_wback_inv((unsigned long) in, 8 * 8);
+       dma_cache_inv((unsigned long) priv->si_buf, 8 * 8);
+
+       local_irq_save(flags);
+
+       n64joy_wait_si_dma(priv->reg_base);
+
+       barrier();
+       n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(in));
+       barrier();
+       n64joy_write_reg(priv->reg_base, SI_WRITE_REG, PIF_RAM);
+       barrier();
+
+       n64joy_wait_si_dma(priv->reg_base);
+
+       barrier();
+       n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(priv->si_buf));
+       barrier();
+       n64joy_write_reg(priv->reg_base, SI_READ_REG, PIF_RAM);
+       barrier();
+
+       n64joy_wait_si_dma(priv->reg_base);
+
+       local_irq_restore(flags);
+}
+
+static const u64 polldata[] ____cacheline_aligned = {
+       0xff010401ffffffff,
+       0xff010401ffffffff,
+       0xff010401ffffffff,
+       0xff010401ffffffff,
+       0xfe00000000000000,
+       0,
+       0,
+       1
+};
+
+static void n64joy_poll(struct timer_list *t)
+{
+       const struct joydata *data;
+       struct n64joy_priv *priv = container_of(t, struct n64joy_priv, timer);
+       struct input_dev *dev;
+       u32 i;
+
+       n64joy_exec_pif(priv, polldata);
+
+       data = (struct joydata *) priv->si_buf;
+
+       for (i = 0; i < MAX_CONTROLLERS; i++) {
+               if (!priv->n64joy_dev[i])
+                       continue;
+
+               dev = priv->n64joy_dev[i];
+
+               /* d-pad */
+               input_report_key(dev, BTN_DPAD_UP, data[i].up);
+               input_report_key(dev, BTN_DPAD_DOWN, data[i].down);
+               input_report_key(dev, BTN_DPAD_LEFT, data[i].left);
+               input_report_key(dev, BTN_DPAD_RIGHT, data[i].right);
+
+               /* c buttons */
+               input_report_key(dev, BTN_FORWARD, data[i].c_up);
+               input_report_key(dev, BTN_BACK, data[i].c_down);
+               input_report_key(dev, BTN_LEFT, data[i].c_left);
+               input_report_key(dev, BTN_RIGHT, data[i].c_right);
+
+               /* matching buttons */
+               input_report_key(dev, BTN_START, data[i].start);
+               input_report_key(dev, BTN_Z, data[i].z);
+
+               /* remaining ones: a, b, l, r */
+               input_report_key(dev, BTN_0, data[i].a);
+               input_report_key(dev, BTN_1, data[i].b);
+               input_report_key(dev, BTN_2, data[i].l);
+               input_report_key(dev, BTN_3, data[i].r);
+
+               input_report_abs(dev, ABS_X, data[i].x);
+               input_report_abs(dev, ABS_Y, data[i].y);
+
+               input_sync(dev);
+       }
+
+       mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
+}
+
+static int n64joy_open(struct input_dev *dev)
+{
+       struct n64joy_priv *priv = input_get_drvdata(dev);
+       int err;
+
+       err = mutex_lock_interruptible(&priv->n64joy_mutex);
+       if (err)
+               return err;
+
+       if (!priv->n64joy_opened) {
+               /*
+                * We could use the vblank irq, but it's not important if
+                * the poll point slightly changes.
+                */
+               timer_setup(&priv->timer, n64joy_poll, 0);
+               mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
+       }
+
+       priv->n64joy_opened++;
+
+       mutex_unlock(&priv->n64joy_mutex);
+       return err;
+}
+
+static void n64joy_close(struct input_dev *dev)
+{
+       struct n64joy_priv *priv = input_get_drvdata(dev);
+
+       mutex_lock(&priv->n64joy_mutex);
+       if (!--priv->n64joy_opened)
+               del_timer_sync(&priv->timer);
+       mutex_unlock(&priv->n64joy_mutex);
+}
+
+static const u64 __initconst scandata[] ____cacheline_aligned = {
+       0xff010300ffffffff,
+       0xff010300ffffffff,
+       0xff010300ffffffff,
+       0xff010300ffffffff,
+       0xfe00000000000000,
+       0,
+       0,
+       1
+};
+
+/*
+ * The target device is embedded and RAM-constrained. We save RAM
+ * by initializing in __init code that gets dropped late in boot.
+ * For the same reason there is no module or unloading support.
+ */
+static int __init n64joy_probe(struct platform_device *pdev)
+{
+       const struct joydata *data;
+       struct n64joy_priv *priv;
+       struct input_dev *dev;
+       int err = 0;
+       u32 i, j, found = 0;
+
+       priv = kzalloc(sizeof(struct n64joy_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       mutex_init(&priv->n64joy_mutex);
+
+       priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (!priv->reg_base) {
+               err = -EINVAL;
+               goto fail;
+       }
+
+       /* The controllers are not hotpluggable, so we can scan in init */
+       n64joy_exec_pif(priv, scandata);
+
+       data = (struct joydata *) priv->si_buf;
+
+       for (i = 0; i < MAX_CONTROLLERS; i++) {
+               if (!data[i].err && data[i].data >> 16 == N64_CONTROLLER_ID) {
+                       found++;
+
+                       dev = priv->n64joy_dev[i] = input_allocate_device();
+                       if (!priv->n64joy_dev[i]) {
+                               err = -ENOMEM;
+                               goto fail;
+                       }
+
+                       input_set_drvdata(dev, priv);
+
+                       dev->name = "N64 controller";
+                       dev->phys = n64joy_phys[i];
+                       dev->id.bustype = BUS_HOST;
+                       dev->id.vendor = 0;
+                       dev->id.product = data[i].data >> 16;
+                       dev->id.version = 0;
+                       dev->dev.parent = &pdev->dev;
+
+                       dev->open = n64joy_open;
+                       dev->close = n64joy_close;
+
+                       /* d-pad */
+                       input_set_capability(dev, EV_KEY, BTN_DPAD_UP);
+                       input_set_capability(dev, EV_KEY, BTN_DPAD_DOWN);
+                       input_set_capability(dev, EV_KEY, BTN_DPAD_LEFT);
+                       input_set_capability(dev, EV_KEY, BTN_DPAD_RIGHT);
+                       /* c buttons */
+                       input_set_capability(dev, EV_KEY, BTN_LEFT);
+                       input_set_capability(dev, EV_KEY, BTN_RIGHT);
+                       input_set_capability(dev, EV_KEY, BTN_FORWARD);
+                       input_set_capability(dev, EV_KEY, BTN_BACK);
+                       /* matching buttons */
+                       input_set_capability(dev, EV_KEY, BTN_START);
+                       input_set_capability(dev, EV_KEY, BTN_Z);
+                       /* remaining ones: a, b, l, r */
+                       input_set_capability(dev, EV_KEY, BTN_0);
+                       input_set_capability(dev, EV_KEY, BTN_1);
+                       input_set_capability(dev, EV_KEY, BTN_2);
+                       input_set_capability(dev, EV_KEY, BTN_3);
+
+                       for (j = 0; j < 2; j++)
+                               input_set_abs_params(dev, ABS_X + j,
+                                                    S8_MIN, S8_MAX, 0, 0);
+
+                       err = input_register_device(dev);
+                       if (err) {
+                               input_free_device(dev);
+                               goto fail;
+                       }
+               }
+       }
+
+       pr_info("%u controller(s) connected\n", found);
+
+       if (!found)
+               return -ENODEV;
+
+       return 0;
+fail:
+       for (i = 0; i < MAX_CONTROLLERS; i++) {
+               if (!priv->n64joy_dev[i])
+                       continue;
+               input_unregister_device(priv->n64joy_dev[i]);
+       }
+       return err;
+}
+
+static struct platform_driver n64joy_driver = {
+       .driver = {
+               .name = "n64joy",
+       },
+};
+
+static int __init n64joy_init(void)
+{
+       return platform_driver_probe(&n64joy_driver, n64joy_probe);
+}
+
+module_init(n64joy_init);
index 8cc8ca4..9f0d07d 100644 (file)
@@ -305,6 +305,7 @@ static const struct xpad_device {
        { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
        { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
        { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
+       { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
        { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
        { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
        { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
index 2b321c1..32d1580 100644 (file)
@@ -446,7 +446,7 @@ config KEYBOARD_MPR121
 
 config KEYBOARD_SNVS_PWRKEY
        tristate "IMX SNVS Power Key Driver"
-       depends on ARCH_MXC || COMPILE_TEST
+       depends on ARCH_MXC || (COMPILE_TEST && HAS_IOMEM)
        depends on OF
        help
          This is the snvs powerkey driver for the Freescale i.MX application
@@ -685,7 +685,7 @@ config KEYBOARD_OMAP
 
 config KEYBOARD_OMAP4
        tristate "TI OMAP4+ keypad support"
-       depends on OF || ARCH_OMAP2PLUS
+       depends on (OF && HAS_IOMEM) || ARCH_OMAP2PLUS
        select INPUT_MATRIXKMAP
        help
          Say Y here if you want to use the OMAP4+ keypad.
@@ -773,7 +773,7 @@ config KEYBOARD_CAP11XX
 
 config KEYBOARD_BCM
        tristate "Broadcom keypad driver"
-       depends on OF && HAVE_CLK
+       depends on OF && HAVE_CLK && HAS_IOMEM
        select INPUT_MATRIXKMAP
        default ARCH_BCM_CYGNUS
        help
index d222231..eda1b23 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/efi.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
+#include <linux/ktime.h>
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
@@ -409,7 +410,7 @@ struct applespi_data {
        unsigned int                    cmd_msg_cntr;
        /* lock to protect the above parameters and flags below */
        spinlock_t                      cmd_msg_lock;
-       bool                            cmd_msg_queued;
+       ktime_t                         cmd_msg_queued;
        enum applespi_evt_type          cmd_evt_type;
 
        struct led_classdev             backlight_info;
@@ -729,7 +730,7 @@ static void applespi_msg_complete(struct applespi_data *applespi,
                wake_up_all(&applespi->drain_complete);
 
        if (is_write_msg) {
-               applespi->cmd_msg_queued = false;
+               applespi->cmd_msg_queued = 0;
                applespi_send_cmd_msg(applespi);
        }
 
@@ -748,6 +749,8 @@ static void applespi_async_write_complete(void *context)
                                         applespi->tx_status,
                                         APPLESPI_STATUS_SIZE);
 
+       udelay(SPI_RW_CHG_DELAY_US);
+
        if (!applespi_check_write_status(applespi, applespi->wr_m.status)) {
                /*
                 * If we got an error, we presumably won't get the expected
@@ -771,8 +774,16 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
                return 0;
 
        /* check whether send is in progress */
-       if (applespi->cmd_msg_queued)
-               return 0;
+       if (applespi->cmd_msg_queued) {
+               if (ktime_ms_delta(ktime_get(), applespi->cmd_msg_queued) < 1000)
+                       return 0;
+
+               dev_warn(&applespi->spi->dev, "Command %d timed out\n",
+                        applespi->cmd_evt_type);
+
+               applespi->cmd_msg_queued = 0;
+               applespi->write_active = false;
+       }
 
        /* set up packet */
        memset(packet, 0, APPLESPI_PACKET_SIZE);
@@ -869,7 +880,7 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
                return sts;
        }
 
-       applespi->cmd_msg_queued = true;
+       applespi->cmd_msg_queued = ktime_get_coarse();
        applespi->write_active = true;
 
        return 0;
@@ -1921,7 +1932,7 @@ static int __maybe_unused applespi_resume(struct device *dev)
        applespi->drain = false;
        applespi->have_cl_led_on = false;
        applespi->have_bl_level = 0;
-       applespi->cmd_msg_queued = false;
+       applespi->cmd_msg_queued = 0;
        applespi->read_active = false;
        applespi->write_active = false;
 
index b379ed7..38457d9 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <asm/unaligned.h>
 
+#define MAX_NUM_TOP_ROW_KEYS   15
+
 /**
  * struct cros_ec_keyb - Structure representing EC keyboard device
  *
@@ -42,6 +44,9 @@
  * @idev: The input device for the matrix keys.
  * @bs_idev: The input device for non-matrix buttons and switches (or NULL).
  * @notifier: interrupt event notifier for transport devices
+ * @function_row_physmap: An array of the encoded rows/columns for the top
+ *                        row function keys, in an order from left to right
+ * @num_function_row_keys: The number of top row keys in a custom keyboard
  */
 struct cros_ec_keyb {
        unsigned int rows;
@@ -58,6 +63,9 @@ struct cros_ec_keyb {
        struct input_dev *idev;
        struct input_dev *bs_idev;
        struct notifier_block notifier;
+
+       u16 function_row_physmap[MAX_NUM_TOP_ROW_KEYS];
+       size_t num_function_row_keys;
 };
 
 /**
@@ -527,6 +535,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
        struct input_dev *idev;
        const char *phys;
        int err;
+       struct property *prop;
+       const __be32 *p;
+       u16 *physmap;
+       u32 key_pos;
+       int row, col;
 
        err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols);
        if (err)
@@ -578,6 +591,21 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
        ckdev->idev = idev;
        cros_ec_keyb_compute_valid_keys(ckdev);
 
+       physmap = ckdev->function_row_physmap;
+       of_property_for_each_u32(dev->of_node, "function-row-physmap",
+                                prop, p, key_pos) {
+               if (ckdev->num_function_row_keys == MAX_NUM_TOP_ROW_KEYS) {
+                       dev_warn(dev, "Only support up to %d top row keys\n",
+                                MAX_NUM_TOP_ROW_KEYS);
+                       break;
+               }
+               row = KEY_ROW(key_pos);
+               col = KEY_COL(key_pos);
+               *physmap = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
+               physmap++;
+               ckdev->num_function_row_keys++;
+       }
+
        err = input_register_device(ckdev->idev);
        if (err) {
                dev_err(dev, "cannot register input device\n");
@@ -587,6 +615,51 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
        return 0;
 }
 
+static ssize_t function_row_physmap_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       ssize_t size = 0;
+       int i;
+       struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
+       u16 *physmap = ckdev->function_row_physmap;
+
+       for (i = 0; i < ckdev->num_function_row_keys; i++)
+               size += scnprintf(buf + size, PAGE_SIZE - size,
+                                 "%s%02X", size ? " " : "", physmap[i]);
+       if (size)
+               size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
+
+       return size;
+}
+
+static DEVICE_ATTR_RO(function_row_physmap);
+
+static struct attribute *cros_ec_keyb_attrs[] = {
+       &dev_attr_function_row_physmap.attr,
+       NULL,
+};
+
+static umode_t cros_ec_keyb_attr_is_visible(struct kobject *kobj,
+                                           struct attribute *attr,
+                                           int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
+
+       if (attr == &dev_attr_function_row_physmap.attr &&
+           !ckdev->num_function_row_keys)
+               return 0;
+
+       return attr->mode;
+}
+
+static const struct attribute_group cros_ec_keyb_attr_group = {
+       .is_visible = cros_ec_keyb_attr_is_visible,
+       .attrs = cros_ec_keyb_attrs,
+};
+
+
 static int cros_ec_keyb_probe(struct platform_device *pdev)
 {
        struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
@@ -617,6 +690,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
                return err;
        }
 
+       err = devm_device_add_group(dev, &cros_ec_keyb_attr_group);
+       if (err) {
+               dev_err(dev, "failed to create attributes. err=%d\n", err);
+               return err;
+       }
+
        ckdev->notifier.notifier_call = cros_ec_keyb_work;
        err = blocking_notifier_chain_register(&ckdev->ec->event_notifier,
                                               &ckdev->notifier);
index b17ac2a..43375b3 100644 (file)
@@ -60,6 +60,8 @@
        ((((dbms) * 1000) / ((1 << ((ptv) + 1)) * (1000000 / 32768))) - 1)
 #define OMAP4_VAL_DEBOUNCINGTIME_16MS                                  \
        OMAP4_KEYPAD_DEBOUNCINGTIME_MS(16, OMAP4_KEYPAD_PTV_DIV_128)
+#define OMAP4_KEYPAD_AUTOIDLE_MS       50      /* Approximate measured time */
+#define OMAP4_KEYPAD_IDLE_CHECK_MS     (OMAP4_KEYPAD_AUTOIDLE_MS / 2)
 
 enum {
        KBD_REVISION_OMAP4 = 0,
@@ -71,6 +73,7 @@ struct omap4_keypad {
 
        void __iomem *base;
        unsigned int irq;
+       struct mutex lock;              /* for key scan */
 
        unsigned int rows;
        unsigned int cols;
@@ -78,7 +81,7 @@ struct omap4_keypad {
        u32 irqreg_offset;
        unsigned int row_shift;
        bool no_autorepeat;
-       unsigned char key_state[8];
+       u64 keys;
        unsigned short *keymap;
 };
 
@@ -107,6 +110,55 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
                     keypad_data->base + keypad_data->irqreg_offset + offset);
 }
 
+static int omap4_keypad_report_keys(struct omap4_keypad *keypad_data,
+                                   u64 keys, bool down)
+{
+       struct input_dev *input_dev = keypad_data->input;
+       unsigned int col, row, code;
+       DECLARE_BITMAP(mask, 64);
+       unsigned long bit;
+       int events = 0;
+
+       bitmap_from_u64(mask, keys);
+
+       for_each_set_bit(bit, mask, keypad_data->rows * BITS_PER_BYTE) {
+               row = bit / BITS_PER_BYTE;
+               col = bit % BITS_PER_BYTE;
+               code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift);
+
+               input_event(input_dev, EV_MSC, MSC_SCAN, code);
+               input_report_key(input_dev, keypad_data->keymap[code], down);
+
+               events++;
+       }
+
+       if (events)
+               input_sync(input_dev);
+
+       return events;
+}
+
+static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys)
+{
+       u64 changed;
+
+       mutex_lock(&keypad_data->lock);
+
+       changed = keys ^ keypad_data->keys;
+
+       /*
+        * Report key up events separately and first. This matters in case we
+        * lost key-up interrupt and just now catching up.
+        */
+       omap4_keypad_report_keys(keypad_data, changed & ~keys, false);
+
+       /* Report key down events */
+       omap4_keypad_report_keys(keypad_data, changed & keys, true);
+
+       keypad_data->keys = keys;
+
+       mutex_unlock(&keypad_data->lock);
+}
 
 /* Interrupt handlers */
 static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
@@ -122,48 +174,44 @@ static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
 static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
 {
        struct omap4_keypad *keypad_data = dev_id;
-       struct input_dev *input_dev = keypad_data->input;
-       unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
-       unsigned int col, row, code, changed;
-       u32 *new_state = (u32 *) key_state;
-
-       *new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
-       *(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
-
-       for (row = 0; row < keypad_data->rows; row++) {
-               changed = key_state[row] ^ keypad_data->key_state[row];
-               if (!changed)
-                       continue;
-
-               for (col = 0; col < keypad_data->cols; col++) {
-                       if (changed & (1 << col)) {
-                               code = MATRIX_SCAN_CODE(row, col,
-                                               keypad_data->row_shift);
-                               input_event(input_dev, EV_MSC, MSC_SCAN, code);
-                               input_report_key(input_dev,
-                                                keypad_data->keymap[code],
-                                                key_state[row] & (1 << col));
-                       }
-               }
+       struct device *dev = keypad_data->input->dev.parent;
+       u32 low, high;
+       int error;
+       u64 keys;
+
+       error = pm_runtime_get_sync(dev);
+       if (error < 0) {
+               pm_runtime_put_noidle(dev);
+               return IRQ_NONE;
        }
 
-       input_sync(input_dev);
+       low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
+       high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
+       keys = low | (u64)high << 32;
 
-       memcpy(keypad_data->key_state, key_state,
-               sizeof(keypad_data->key_state));
+       omap4_keypad_scan_keys(keypad_data, keys);
 
        /* clear pending interrupts */
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
                         kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
 
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
        return IRQ_HANDLED;
 }
 
 static int omap4_keypad_open(struct input_dev *input)
 {
        struct omap4_keypad *keypad_data = input_get_drvdata(input);
+       struct device *dev = input->dev.parent;
+       int error;
 
-       pm_runtime_get_sync(input->dev.parent);
+       error = pm_runtime_get_sync(dev);
+       if (error < 0) {
+               pm_runtime_put_noidle(dev);
+               return error;
+       }
 
        disable_irq(keypad_data->irq);
 
@@ -176,13 +224,15 @@ static int omap4_keypad_open(struct input_dev *input)
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
                         kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
        kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
-                       OMAP4_DEF_IRQENABLE_EVENTEN |
-                               OMAP4_DEF_IRQENABLE_LONGKEY);
+                       OMAP4_DEF_IRQENABLE_EVENTEN);
        kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
-                       OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA);
+                       OMAP4_DEF_WUP_EVENT_ENA);
 
        enable_irq(keypad_data->irq);
 
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
+
        return 0;
 }
 
@@ -200,14 +250,20 @@ static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
 
 static void omap4_keypad_close(struct input_dev *input)
 {
-       struct omap4_keypad *keypad_data;
+       struct omap4_keypad *keypad_data = input_get_drvdata(input);
+       struct device *dev = input->dev.parent;
+       int error;
+
+       error = pm_runtime_get_sync(dev);
+       if (error < 0)
+               pm_runtime_put_noidle(dev);
 
-       keypad_data = input_get_drvdata(input);
        disable_irq(keypad_data->irq);
        omap4_keypad_stop(keypad_data);
        enable_irq(keypad_data->irq);
 
-       pm_runtime_put_sync(input->dev.parent);
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
 }
 
 static int omap4_keypad_parse_dt(struct device *dev,
@@ -252,8 +308,41 @@ static int omap4_keypad_check_revision(struct device *dev,
        return 0;
 }
 
+/*
+ * Errata ID i689 "1.32 Keyboard Key Up Event Can Be Missed".
+ * Interrupt may not happen for key-up events. We must clear stuck
+ * key-up events after the keyboard hardware has auto-idled.
+ */
+static int __maybe_unused omap4_keypad_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
+       u32 active;
+
+       active = kbd_readl(keypad_data, OMAP4_KBD_STATEMACHINE);
+       if (active) {
+               pm_runtime_mark_last_busy(dev);
+               return -EBUSY;
+       }
+
+       omap4_keypad_scan_keys(keypad_data, 0);
+
+       return 0;
+}
+
+static const struct dev_pm_ops omap4_keypad_pm_ops = {
+       SET_RUNTIME_PM_OPS(omap4_keypad_runtime_suspend, NULL, NULL)
+};
+
+static void omap4_disable_pm(void *d)
+{
+       pm_runtime_dont_use_autosuspend(d);
+       pm_runtime_disable(d);
+}
+
 static int omap4_keypad_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct omap4_keypad *keypad_data;
        struct input_dev *input_dev;
        struct resource *res;
@@ -271,63 +360,62 @@ static int omap4_keypad_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
+       keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
        if (!keypad_data) {
-               dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
+               dev_err(dev, "keypad_data memory allocation failed\n");
                return -ENOMEM;
        }
 
        keypad_data->irq = irq;
+       mutex_init(&keypad_data->lock);
+       platform_set_drvdata(pdev, keypad_data);
 
-       error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
+       error = omap4_keypad_parse_dt(dev, keypad_data);
        if (error)
-               goto err_free_keypad;
+               return error;
 
-       res = request_mem_region(res->start, resource_size(res), pdev->name);
-       if (!res) {
-               dev_err(&pdev->dev, "can't request mem region\n");
-               error = -EBUSY;
-               goto err_free_keypad;
-       }
+       keypad_data->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(keypad_data->base))
+               return PTR_ERR(keypad_data->base);
 
-       keypad_data->base = ioremap(res->start, resource_size(res));
-       if (!keypad_data->base) {
-               dev_err(&pdev->dev, "can't ioremap mem resource\n");
-               error = -ENOMEM;
-               goto err_release_mem;
-       }
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_autosuspend_delay(dev, OMAP4_KEYPAD_IDLE_CHECK_MS);
+       pm_runtime_enable(dev);
 
-       pm_runtime_enable(&pdev->dev);
+       error = devm_add_action_or_reset(dev, omap4_disable_pm, dev);
+       if (error) {
+               dev_err(dev, "unable to register cleanup action\n");
+               return error;
+       }
 
        /*
         * Enable clocks for the keypad module so that we can read
         * revision register.
         */
-       error = pm_runtime_get_sync(&pdev->dev);
+       error = pm_runtime_get_sync(dev);
        if (error) {
-               dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
-               pm_runtime_put_noidle(&pdev->dev);
-       } else {
-               error = omap4_keypad_check_revision(&pdev->dev,
-                                                   keypad_data);
-               if (!error) {
-                       /* Ensure device does not raise interrupts */
-                       omap4_keypad_stop(keypad_data);
-               }
-               pm_runtime_put_sync(&pdev->dev);
+               dev_err(dev, "pm_runtime_get_sync() failed\n");
+               pm_runtime_put_noidle(dev);
+               return error;
+       }
+
+       error = omap4_keypad_check_revision(dev, keypad_data);
+       if (!error) {
+               /* Ensure device does not raise interrupts */
+               omap4_keypad_stop(keypad_data);
        }
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
        if (error)
-               goto err_pm_disable;
+               return error;
 
        /* input device allocation */
-       keypad_data->input = input_dev = input_allocate_device();
-       if (!input_dev) {
-               error = -ENOMEM;
-               goto err_pm_disable;
-       }
+       keypad_data->input = input_dev = devm_input_allocate_device(dev);
+       if (!input_dev)
+               return -ENOMEM;
 
        input_dev->name = pdev->name;
-       input_dev->dev.parent = &pdev->dev;
        input_dev->id.bustype = BUS_HOST;
        input_dev->id.vendor = 0x0001;
        input_dev->id.product = 0x0001;
@@ -344,84 +432,51 @@ static int omap4_keypad_probe(struct platform_device *pdev)
 
        keypad_data->row_shift = get_count_order(keypad_data->cols);
        max_keys = keypad_data->rows << keypad_data->row_shift;
-       keypad_data->keymap = kcalloc(max_keys,
-                                     sizeof(keypad_data->keymap[0]),
-                                     GFP_KERNEL);
+       keypad_data->keymap = devm_kcalloc(dev,
+                                          max_keys,
+                                          sizeof(keypad_data->keymap[0]),
+                                          GFP_KERNEL);
        if (!keypad_data->keymap) {
-               dev_err(&pdev->dev, "Not enough memory for keymap\n");
-               error = -ENOMEM;
-               goto err_free_input;
+               dev_err(dev, "Not enough memory for keymap\n");
+               return -ENOMEM;
        }
 
        error = matrix_keypad_build_keymap(NULL, NULL,
                                           keypad_data->rows, keypad_data->cols,
                                           keypad_data->keymap, input_dev);
        if (error) {
-               dev_err(&pdev->dev, "failed to build keymap\n");
-               goto err_free_keymap;
+               dev_err(dev, "failed to build keymap\n");
+               return error;
        }
 
-       error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
-                                    omap4_keypad_irq_thread_fn, IRQF_ONESHOT,
-                                    "omap4-keypad", keypad_data);
+       error = devm_request_threaded_irq(dev, keypad_data->irq,
+                                         omap4_keypad_irq_handler,
+                                         omap4_keypad_irq_thread_fn,
+                                         IRQF_ONESHOT,
+                                         "omap4-keypad", keypad_data);
        if (error) {
-               dev_err(&pdev->dev, "failed to register interrupt\n");
-               goto err_free_keymap;
+               dev_err(dev, "failed to register interrupt\n");
+               return error;
        }
 
        error = input_register_device(keypad_data->input);
-       if (error < 0) {
-               dev_err(&pdev->dev, "failed to register input device\n");
-               goto err_free_irq;
+       if (error) {
+               dev_err(dev, "failed to register input device\n");
+               return error;
        }
 
-       device_init_wakeup(&pdev->dev, true);
-       error = dev_pm_set_wake_irq(&pdev->dev, keypad_data->irq);
+       device_init_wakeup(dev, true);
+       error = dev_pm_set_wake_irq(dev, keypad_data->irq);
        if (error)
-               dev_warn(&pdev->dev,
-                        "failed to set up wakeup irq: %d\n", error);
-
-       platform_set_drvdata(pdev, keypad_data);
+               dev_warn(dev, "failed to set up wakeup irq: %d\n", error);
 
        return 0;
-
-err_free_irq:
-       free_irq(keypad_data->irq, keypad_data);
-err_free_keymap:
-       kfree(keypad_data->keymap);
-err_free_input:
-       input_free_device(input_dev);
-err_pm_disable:
-       pm_runtime_disable(&pdev->dev);
-       iounmap(keypad_data->base);
-err_release_mem:
-       release_mem_region(res->start, resource_size(res));
-err_free_keypad:
-       kfree(keypad_data);
-       return error;
 }
 
 static int omap4_keypad_remove(struct platform_device *pdev)
 {
-       struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
-       struct resource *res;
-
        dev_pm_clear_wake_irq(&pdev->dev);
 
-       free_irq(keypad_data->irq, keypad_data);
-
-       pm_runtime_disable(&pdev->dev);
-
-       input_unregister_device(keypad_data->input);
-
-       iounmap(keypad_data->base);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       kfree(keypad_data->keymap);
-       kfree(keypad_data);
-
        return 0;
 }
 
@@ -437,6 +492,7 @@ static struct platform_driver omap4_keypad_driver = {
        .driver         = {
                .name   = "omap4-keypad",
                .of_match_table = omap_keypad_dt_match,
+               .pm = &omap4_keypad_pm_ops,
        },
 };
 module_platform_driver(omap4_keypad_driver);
index 37568b0..b08610d 100644 (file)
@@ -863,6 +863,7 @@ static void da7280_parse_properties(struct device *dev,
                gpi_str3[7] = '0' + i;
                haptics->gpi_ctl[i].polarity = 0;
                error = device_property_read_string(dev, gpi_str3, &str);
+               if (!error)
                        haptics->gpi_ctl[i].polarity =
                                da7280_haptic_of_gpi_pol_str(dev, str);
        }
@@ -1299,11 +1300,13 @@ static int __maybe_unused da7280_resume(struct device *dev)
        return retval;
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id da7280_of_match[] = {
        { .compatible = "dlg,da7280", },
        { }
 };
 MODULE_DEVICE_TABLE(of, da7280_of_match);
+#endif
 
 static const struct i2c_device_id da7280_i2c_id[] = {
        { "da7280", },
index b067bfd..4a6b33b 100644 (file)
@@ -986,7 +986,7 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
        case V7_PACKET_ID_TWO:
                mt[1].x &= ~0x000F;
                mt[1].y |= 0x000F;
-               /* Detect false-postive touches where x & y report max value */
+               /* Detect false-positive touches where x & y report max value */
                if (mt[1].y == 0x7ff && mt[1].x == 0xff0) {
                        mt[1].x = 0;
                        /* y gets set to 0 at the end of this function */
index 8fb7b43..ffad142 100644 (file)
@@ -1106,8 +1106,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
                                        num_fingers = hw.w + 2;
                                break;
                        case 2:
-                               if (SYN_MODEL_PEN(info->model_id))
-                                       ;   /* Nothing, treat a pen as a single finger */
+                               /*
+                                * SYN_MODEL_PEN(info->model_id): even if
+                                * the device supports pen, we treat it as
+                                * a single finger.
+                                */
                                break;
                        case 4 ... 15:
                                if (SYN_CAP_PALMDETECT(info->capabilities))
index 0754744..f39b7b3 100644 (file)
@@ -255,7 +255,7 @@ config SERIO_ARC_PS2
 
 config SERIO_APBPS2
        tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller"
-       depends on OF
+       depends on OF && HAS_IOMEM
        help
          Say Y here if you want support for GRLIB APBPS2 peripherals used
          to connect to PS/2 keyboard and/or mouse.
index c74b020..9119e12 100644 (file)
@@ -588,6 +588,10 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
                },
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */
+               },
        },
        { }
 };
index e08b0ef..fcb1b64 100644 (file)
@@ -1036,9 +1036,9 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%dx%d\n",
-                       input_abs_get_max(aiptek->inputdev, ABS_X) + 1,
-                       input_abs_get_max(aiptek->inputdev, ABS_Y) + 1);
+       return sysfs_emit(buf, "%dx%d\n",
+                         input_abs_get_max(aiptek->inputdev, ABS_X) + 1,
+                         input_abs_get_max(aiptek->inputdev, ABS_Y) + 1);
 }
 
 /* These structs define the sysfs files, param #1 is the name of the
@@ -1064,9 +1064,8 @@ static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribut
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(pointer_mode_map,
-                                       aiptek->curSetting.pointerMode));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(pointer_mode_map,
+                                                     aiptek->curSetting.pointerMode));
 }
 
 static ssize_t
@@ -1101,9 +1100,8 @@ static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attri
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(coordinate_mode_map,
-                                       aiptek->curSetting.coordinateMode));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(coordinate_mode_map,
+                                                     aiptek->curSetting.coordinateMode));
 }
 
 static ssize_t
@@ -1143,9 +1141,8 @@ static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(tool_mode_map,
-                                       aiptek->curSetting.toolMode));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(tool_mode_map,
+                                                     aiptek->curSetting.toolMode));
 }
 
 static ssize_t
@@ -1174,10 +1171,9 @@ static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *att
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
        if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
-               return snprintf(buf, PAGE_SIZE, "disable\n");
+               return sysfs_emit(buf, "disable\n");
        } else {
-               return snprintf(buf, PAGE_SIZE, "%d\n",
-                               aiptek->curSetting.xTilt);
+               return sysfs_emit(buf, "%d\n", aiptek->curSetting.xTilt);
        }
 }
 
@@ -1216,10 +1212,9 @@ static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *att
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
        if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
-               return snprintf(buf, PAGE_SIZE, "disable\n");
+               return sysfs_emit(buf, "disable\n");
        } else {
-               return snprintf(buf, PAGE_SIZE, "%d\n",
-                               aiptek->curSetting.yTilt);
+               return sysfs_emit(buf, "%d\n", aiptek->curSetting.yTilt);
        }
 }
 
@@ -1257,7 +1252,7 @@ static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribut
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay);
+       return sysfs_emit(buf, "%d\n", aiptek->curSetting.jitterDelay);
 }
 
 static ssize_t
@@ -1286,8 +1281,7 @@ static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_at
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-                       aiptek->curSetting.programmableDelay);
+       return sysfs_emit(buf, "%d\n", aiptek->curSetting.programmableDelay);
 }
 
 static ssize_t
@@ -1316,7 +1310,7 @@ static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attri
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount);
+       return sysfs_emit(buf, "%ld\n", aiptek->eventCount);
 }
 
 static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL);
@@ -1355,7 +1349,7 @@ static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_at
        default:
                return 0;
        }
-       return snprintf(buf, PAGE_SIZE, retMsg);
+       return sysfs_emit(buf, retMsg);
 }
 
 static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
@@ -1375,9 +1369,8 @@ static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribut
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(stylus_button_map,
-                                       aiptek->curSetting.stylusButtonUpper));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(stylus_button_map,
+                                                     aiptek->curSetting.stylusButtonUpper));
 }
 
 static ssize_t
@@ -1406,9 +1399,8 @@ static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribut
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(stylus_button_map,
-                                       aiptek->curSetting.stylusButtonLower));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(stylus_button_map,
+                                                     aiptek->curSetting.stylusButtonLower));
 }
 
 static ssize_t
@@ -1444,9 +1436,8 @@ static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(mouse_button_map,
-                                       aiptek->curSetting.mouseButtonLeft));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
+                                                     aiptek->curSetting.mouseButtonLeft));
 }
 
 static ssize_t
@@ -1474,9 +1465,8 @@ static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribut
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(mouse_button_map,
-                                       aiptek->curSetting.mouseButtonMiddle));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
+                                                     aiptek->curSetting.mouseButtonMiddle));
 }
 
 static ssize_t
@@ -1504,9 +1494,8 @@ static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       map_val_to_str(mouse_button_map,
-                                       aiptek->curSetting.mouseButtonRight));
+       return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
+                                                     aiptek->curSetting.mouseButtonRight));
 }
 
 static ssize_t
@@ -1535,10 +1524,9 @@ static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *att
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
        if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
-               return snprintf(buf, PAGE_SIZE, "disable\n");
+               return sysfs_emit(buf, "disable\n");
        } else {
-               return snprintf(buf, PAGE_SIZE, "%d\n",
-                               aiptek->curSetting.wheel);
+               return sysfs_emit(buf, "%d\n", aiptek->curSetting.wheel);
        }
 }
 
@@ -1568,8 +1556,7 @@ static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *a
        /* There is nothing useful to display, so a one-line manual
         * is in order...
         */
-       return snprintf(buf, PAGE_SIZE,
-                       "Write anything to this file to program your tablet.\n");
+       return sysfs_emit(buf, "Write anything to this file to program your tablet.\n");
 }
 
 static ssize_t
@@ -1600,7 +1587,7 @@ static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *a
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);
+       return sysfs_emit(buf, "0x%04x\n", aiptek->features.odmCode);
 }
 
 static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);
@@ -1613,7 +1600,7 @@ static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);
+       return sysfs_emit(buf, "0x%04x\n", aiptek->features.modelCode);
 }
 
 static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);
@@ -1626,8 +1613,7 @@ static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *at
 {
        struct aiptek *aiptek = dev_get_drvdata(dev);
 
-       return snprintf(buf, PAGE_SIZE, "%04x\n",
-                       aiptek->features.firmwareCode);
+       return sysfs_emit(buf, "%04x\n", aiptek->features.firmwareCode);
 }
 
 static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);
index cc18f54..529614d 100644 (file)
@@ -608,7 +608,7 @@ config TOUCHSCREEN_MTOUCH
 
 config TOUCHSCREEN_IMX6UL_TSC
        tristate "Freescale i.MX6UL touchscreen controller"
-       depends on (OF && GPIOLIB) || COMPILE_TEST
+       depends on ((OF && GPIOLIB) || COMPILE_TEST) && HAS_IOMEM
        help
          Say Y here if you have a Freescale i.MX6UL, and want to
          use the internal touchscreen controller.
index a703870..f113a27 100644 (file)
 
 struct ads7846_buf {
        u8 cmd;
-       /*
-        * This union is a temporary hack. The driver does an in-place
-        * endianness conversion. This will be cleaned up in the next
-        * patch.
-        */
-       union {
-               __be16 data_be16;
-               u16 data;
-       };
+       __be16 data;
 } __packed;
 
-
-struct ts_event {
-       bool ignore;
-       struct ads7846_buf x;
-       struct ads7846_buf y;
-       struct ads7846_buf z1;
-       struct ads7846_buf z2;
+struct ads7846_buf_layout {
+       unsigned int offset;
+       unsigned int count;
+       unsigned int skip;
 };
 
 /*
@@ -90,12 +79,18 @@ struct ts_event {
  * systems where main memory is not DMA-coherent (most non-x86 boards).
  */
 struct ads7846_packet {
-       struct ts_event tc;
-       struct ads7846_buf read_x_cmd;
-       struct ads7846_buf read_y_cmd;
-       struct ads7846_buf read_z1_cmd;
-       struct ads7846_buf read_z2_cmd;
+       unsigned int count;
+       unsigned int count_skip;
+       unsigned int cmds;
+       unsigned int last_cmd_idx;
+       struct ads7846_buf_layout l[5];
+       struct ads7846_buf *rx;
+       struct ads7846_buf *tx;
+
        struct ads7846_buf pwrdown_cmd;
+
+       bool ignore;
+       u16 x, y, z1, z2;
 };
 
 struct ads7846 {
@@ -194,7 +189,6 @@ struct ads7846 {
 #define        READ_Y(vref)    (READ_12BIT_DFR(y,  1, vref))
 #define        READ_Z1(vref)   (READ_12BIT_DFR(z1, 1, vref))
 #define        READ_Z2(vref)   (READ_12BIT_DFR(z2, 1, vref))
-
 #define        READ_X(vref)    (READ_12BIT_DFR(x,  1, vref))
 #define        PWRDOWN         (READ_12BIT_DFR(y,  0, 0))      /* LAST */
 
@@ -207,6 +201,21 @@ struct ads7846 {
 #define        REF_ON  (READ_12BIT_DFR(x, 1, 1))
 #define        REF_OFF (READ_12BIT_DFR(y, 0, 0))
 
+/* Order commands in the most optimal way to reduce Vref switching and
+ * settling time:
+ * Measure:  X; Vref: X+, X-; IN: Y+
+ * Measure:  Y; Vref: Y+, Y-; IN: X+
+ * Measure: Z1; Vref: Y+, X-; IN: X+
+ * Measure: Z2; Vref: Y+, X-; IN: Y-
+ */
+enum ads7846_cmds {
+       ADS7846_X,
+       ADS7846_Y,
+       ADS7846_Z1,
+       ADS7846_Z2,
+       ADS7846_PWDOWN,
+};
+
 static int get_pendown_state(struct ads7846 *ts)
 {
        if (ts->get_pendown_state)
@@ -689,26 +698,109 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val)
        return ADS7846_FILTER_OK;
 }
 
-static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
+static int ads7846_get_value(struct ads7846_buf *buf)
 {
        int value;
-       struct spi_transfer *t =
-               list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-       struct ads7846_buf *buf = t->rx_buf;
 
-       value = be16_to_cpup(&buf->data_be16);
+       value = be16_to_cpup(&buf->data);
 
        /* enforce ADC output is 12 bits width */
        return (value >> 3) & 0xfff;
 }
 
-static void ads7846_update_value(struct spi_message *m, int val)
+static void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx,
+                               u16 val)
+{
+       struct ads7846_packet *packet = ts->packet;
+
+       switch (cmd_idx) {
+       case ADS7846_Y:
+               packet->y = val;
+               break;
+       case ADS7846_X:
+               packet->x = val;
+               break;
+       case ADS7846_Z1:
+               packet->z1 = val;
+               break;
+       case ADS7846_Z2:
+               packet->z2 = val;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
+}
+
+static u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref)
+{
+       switch (cmd_idx) {
+       case ADS7846_Y:
+               return READ_Y(vref);
+       case ADS7846_X:
+               return READ_X(vref);
+
+       /* 7846 specific commands  */
+       case ADS7846_Z1:
+               return READ_Z1(vref);
+       case ADS7846_Z2:
+               return READ_Z2(vref);
+       case ADS7846_PWDOWN:
+               return PWRDOWN;
+       default:
+               WARN_ON_ONCE(1);
+       }
+
+       return 0;
+}
+
+static bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx)
+{
+       switch (cmd_idx) {
+       case ADS7846_X:
+       case ADS7846_Y:
+       case ADS7846_Z1:
+       case ADS7846_Z2:
+               return true;
+       case ADS7846_PWDOWN:
+               return false;
+       default:
+               WARN_ON_ONCE(1);
+       }
+
+       return false;
+}
+
+static int ads7846_filter(struct ads7846 *ts)
 {
-       struct spi_transfer *t =
-               list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-       struct ads7846_buf *buf = t->rx_buf;
+       struct ads7846_packet *packet = ts->packet;
+       int action;
+       int val;
+       unsigned int cmd_idx, b;
 
-       buf->data = val;
+       packet->ignore = false;
+       for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) {
+               struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+
+               packet->last_cmd_idx = cmd_idx;
+
+               for (b = l->skip; b < l->count; b++) {
+                       val = ads7846_get_value(&packet->rx[l->offset + b]);
+
+                       action = ts->filter(ts->filter_data, cmd_idx, &val);
+                       if (action == ADS7846_FILTER_REPEAT) {
+                               if (b == l->count - 1)
+                                       return -EAGAIN;
+                       } else if (action == ADS7846_FILTER_OK) {
+                               ads7846_set_cmd_val(ts, cmd_idx, val);
+                               break;
+                       } else {
+                               packet->ignore = true;
+                               return 0;
+                       }
+               }
+       }
+
+       return 0;
 }
 
 static void ads7846_read_state(struct ads7846 *ts)
@@ -716,52 +808,26 @@ static void ads7846_read_state(struct ads7846 *ts)
        struct ads7846_packet *packet = ts->packet;
        struct spi_message *m;
        int msg_idx = 0;
-       int val;
-       int action;
        int error;
 
-       while (msg_idx < ts->msg_count) {
+       packet->last_cmd_idx = 0;
 
+       while (true) {
                ts->wait_for_sync();
 
                m = &ts->msg[msg_idx];
                error = spi_sync(ts->spi, m);
                if (error) {
                        dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
-                       packet->tc.ignore = true;
+                       packet->ignore = true;
                        return;
                }
 
-               /*
-                * Last message is power down request, no need to convert
-                * or filter the value.
-                */
-               if (msg_idx < ts->msg_count - 1) {
-
-                       val = ads7846_get_value(ts, m);
-
-                       action = ts->filter(ts->filter_data, msg_idx, &val);
-                       switch (action) {
-                       case ADS7846_FILTER_REPEAT:
-                               continue;
-
-                       case ADS7846_FILTER_IGNORE:
-                               packet->tc.ignore = true;
-                               msg_idx = ts->msg_count - 1;
-                               continue;
-
-                       case ADS7846_FILTER_OK:
-                               ads7846_update_value(m, val);
-                               packet->tc.ignore = false;
-                               msg_idx++;
-                               break;
+               error = ads7846_filter(ts);
+               if (error)
+                       continue;
 
-                       default:
-                               BUG();
-                       }
-               } else {
-                       msg_idx++;
-               }
+               return;
        }
 }
 
@@ -771,19 +837,14 @@ static void ads7846_report_state(struct ads7846 *ts)
        unsigned int Rt;
        u16 x, y, z1, z2;
 
-       /*
-        * ads7846_get_value() does in-place conversion (including byte swap)
-        * from on-the-wire format as part of debouncing to get stable
-        * readings.
-        */
-       x = packet->tc.x.data;
-       y = packet->tc.y.data;
+       x = packet->x;
+       y = packet->y;
        if (ts->model == 7845) {
                z1 = 0;
                z2 = 0;
        } else {
-               z1 = packet->tc.z1.data;
-               z2 = packet->tc.z2.data;
+               z1 = packet->z1;
+               z2 = packet->z2;
        }
 
        /* range filtering */
@@ -816,9 +877,9 @@ static void ads7846_report_state(struct ads7846 *ts)
         * the maximum. Don't report it to user space, repeat at least
         * once more the measurement
         */
-       if (packet->tc.ignore || Rt > ts->pressure_max) {
+       if (packet->ignore || Rt > ts->pressure_max) {
                dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
-                        packet->tc.ignore, Rt);
+                        packet->ignore, Rt);
                return;
        }
 
@@ -979,13 +1040,59 @@ static int ads7846_setup_pendown(struct spi_device *spi,
  * Set up the transfers to read touchscreen state; this assumes we
  * use formula #2 for pressure, not #3.
  */
-static void ads7846_setup_spi_msg(struct ads7846 *ts,
+static int ads7846_setup_spi_msg(struct ads7846 *ts,
                                  const struct ads7846_platform_data *pdata)
 {
        struct spi_message *m = &ts->msg[0];
        struct spi_transfer *x = ts->xfer;
        struct ads7846_packet *packet = ts->packet;
        int vref = pdata->keep_vref_on;
+       unsigned int count, offset = 0;
+       unsigned int cmd_idx, b;
+       unsigned long time;
+       size_t size = 0;
+
+       /* time per bit */
+       time = NSEC_PER_SEC / ts->spi->max_speed_hz;
+
+       count = pdata->settle_delay_usecs * NSEC_PER_USEC / time;
+       packet->count_skip = DIV_ROUND_UP(count, 24);
+
+       if (ts->debounce_max && ts->debounce_rep)
+               /* ads7846_debounce_filter() is making ts->debounce_rep + 2
+                * reads. So we need to get all samples for normal case. */
+               packet->count = ts->debounce_rep + 2;
+       else
+               packet->count = 1;
+
+       if (ts->model == 7846)
+               packet->cmds = 5; /* x, y, z1, z2, pwdown */
+       else
+               packet->cmds = 3; /* x, y, pwdown */
+
+       for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
+               struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+               unsigned int max_count;
+
+               if (ads7846_cmd_need_settle(cmd_idx))
+                       max_count = packet->count + packet->count_skip;
+               else
+                       max_count = packet->count;
+
+               l->offset = offset;
+               offset += max_count;
+               l->count = max_count;
+               l->skip = packet->count_skip;
+               size += sizeof(*packet->tx) * max_count;
+       }
+
+       packet->tx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
+       if (!packet->tx)
+               return -ENOMEM;
+
+       packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
+       if (!packet->rx)
+               return -ENOMEM;
 
        if (ts->model == 7873) {
                /*
@@ -1001,117 +1108,20 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
        spi_message_init(m);
        m->context = ts;
 
-       packet->read_y_cmd.cmd = READ_Y(vref);
-       x->tx_buf = &packet->read_y_cmd;
-       x->rx_buf = &packet->tc.y;
-       x->len = 3;
-       spi_message_add_tail(x, m);
+       for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
+               struct ads7846_buf_layout *l = &packet->l[cmd_idx];
+               u8 cmd = ads7846_get_cmd(cmd_idx, vref);
 
-       /*
-        * The first sample after switching drivers can be low quality;
-        * optionally discard it, using a second one after the signals
-        * have had enough time to stabilize.
-        */
-       if (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_cmd;
-               x->rx_buf = &packet->tc.y;
-               x->len = 3;
-               spi_message_add_tail(x, m);
+               for (b = 0; b < l->count; b++)
+                       packet->tx[l->offset + b].cmd = cmd;
        }
 
-       ts->msg_count++;
-       m++;
-       spi_message_init(m);
-       m->context = ts;
-
-       /* turn y- off, x+ on, then leave in lowpower */
-       x++;
-       packet->read_x_cmd.cmd = READ_X(vref);
-       x->tx_buf = &packet->read_x_cmd;
-       x->rx_buf = &packet->tc.x;
-       x->len = 3;
+       x->tx_buf = packet->tx;
+       x->rx_buf = packet->rx;
+       x->len = size;
        spi_message_add_tail(x, m);
 
-       /* ... maybe discard first sample ... */
-       if (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_cmd;
-               x->rx_buf = &packet->tc.x;
-               x->len = 3;
-               spi_message_add_tail(x, m);
-       }
-
-       /* turn y+ off, x- on; we'll use formula #2 */
-       if (ts->model == 7846) {
-               ts->msg_count++;
-               m++;
-               spi_message_init(m);
-               m->context = ts;
-
-               x++;
-               packet->read_z1_cmd.cmd = READ_Z1(vref);
-               x->tx_buf = &packet->read_z1_cmd;
-               x->rx_buf = &packet->tc.z1;
-               x->len = 3;
-               spi_message_add_tail(x, m);
-
-               /* ... maybe discard first sample ... */
-               if (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_cmd;
-                       x->rx_buf = &packet->tc.z1;
-                       x->len = 3;
-                       spi_message_add_tail(x, m);
-               }
-
-               ts->msg_count++;
-               m++;
-               spi_message_init(m);
-               m->context = ts;
-
-               x++;
-               packet->read_z2_cmd.cmd = READ_Z2(vref);
-               x->tx_buf = &packet->read_z2_cmd;
-               x->rx_buf = &packet->tc.z2;
-               x->len = 3;
-               spi_message_add_tail(x, m);
-
-               /* ... maybe discard first sample ... */
-               if (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_cmd;
-                       x->rx_buf = &packet->tc.z2;
-                       x->len = 3;
-                       spi_message_add_tail(x, m);
-               }
-       }
-
-       /* power down */
-       ts->msg_count++;
-       m++;
-       spi_message_init(m);
-       m->context = ts;
-
-       x++;
-       packet->pwrdown_cmd.cmd = PWRDOWN;
-       x->tx_buf = &packet->pwrdown_cmd;
-       x->len = 3;
-
-       CS_CHANGE(*x);
-       spi_message_add_tail(x, m);
+       return 0;
 }
 
 #ifdef CONFIG_OF
index d51cb91..4c2b579 100644 (file)
@@ -56,6 +56,7 @@
 #define QUEUE_HEADER_SINGLE    0x62
 #define QUEUE_HEADER_NORMAL    0X63
 #define QUEUE_HEADER_WAIT      0x64
+#define QUEUE_HEADER_NORMAL2   0x66
 
 /* Command header definition */
 #define CMD_HEADER_WRITE       0x54
@@ -69,6 +70,7 @@
 #define CMD_HEADER_REK         0x66
 
 /* FW position data */
+#define PACKET_SIZE_OLD                40
 #define PACKET_SIZE            55
 #define MAX_CONTACT_NUM                10
 #define FW_POS_HEADER          0
@@ -90,6 +92,8 @@
 /* FW read command, 0x53 0x?? 0x0, 0x01 */
 #define E_ELAN_INFO_FW_VER     0x00
 #define E_ELAN_INFO_BC_VER     0x10
+#define E_ELAN_INFO_X_RES      0x60
+#define E_ELAN_INFO_Y_RES      0x63
 #define E_ELAN_INFO_REK                0xD0
 #define E_ELAN_INFO_TEST_VER   0xE0
 #define E_ELAN_INFO_FW_ID      0xF0
 #define ELAN_POWERON_DELAY_USEC        500
 #define ELAN_RESET_DELAY_MSEC  20
 
+enum elants_chip_id {
+       EKTH3500,
+       EKTF3624,
+};
+
 enum elants_state {
        ELAN_STATE_NORMAL,
        ELAN_WAIT_QUEUE_HEADER,
@@ -143,9 +152,12 @@ struct elants_data {
        unsigned int y_res;
        unsigned int x_max;
        unsigned int y_max;
+       unsigned int phy_x;
+       unsigned int phy_y;
        struct touchscreen_properties prop;
 
        enum elants_state state;
+       enum elants_chip_id chip_id;
        enum elants_iap_mode iap_mode;
 
        /* Guards against concurrent access to the device via sysfs */
@@ -433,7 +445,51 @@ static int elants_i2c_query_bc_version(struct elants_data *ts)
        return 0;
 }
 
-static int elants_i2c_query_ts_info(struct elants_data *ts)
+static int elants_i2c_query_ts_info_ektf(struct elants_data *ts)
+{
+       struct i2c_client *client = ts->client;
+       int error;
+       u8 resp[4];
+       u16 phy_x, phy_y;
+       const u8 get_xres_cmd[] = {
+               CMD_HEADER_READ, E_ELAN_INFO_X_RES, 0x00, 0x00
+       };
+       const u8 get_yres_cmd[] = {
+               CMD_HEADER_READ, E_ELAN_INFO_Y_RES, 0x00, 0x00
+       };
+
+       /* Get X/Y size in mm */
+       error = elants_i2c_execute_command(client, get_xres_cmd,
+                                          sizeof(get_xres_cmd),
+                                          resp, sizeof(resp), 1,
+                                          "get X size");
+       if (error)
+               return error;
+
+       phy_x = resp[2] | ((resp[3] & 0xF0) << 4);
+
+       error = elants_i2c_execute_command(client, get_yres_cmd,
+                                          sizeof(get_yres_cmd),
+                                          resp, sizeof(resp), 1,
+                                          "get Y size");
+       if (error)
+               return error;
+
+       phy_y = resp[2] | ((resp[3] & 0xF0) << 4);
+
+       dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y);
+
+       ts->phy_x = phy_x;
+       ts->phy_y = phy_y;
+
+       /* eKTF doesn't report max size, set it to default values */
+       ts->x_max = 2240 - 1;
+       ts->y_max = 1408 - 1;
+
+       return 0;
+}
+
+static int elants_i2c_query_ts_info_ekth(struct elants_data *ts)
 {
        struct i2c_client *client = ts->client;
        int error;
@@ -508,6 +564,8 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
                ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x);
                ts->y_max = ELAN_TS_RESOLUTION(cols, osr);
                ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y);
+               ts->phy_x = phy_x;
+               ts->phy_y = phy_y;
        }
 
        return 0;
@@ -587,8 +645,19 @@ static int elants_i2c_initialize(struct elants_data *ts)
                error = elants_i2c_query_fw_version(ts);
        if (!error)
                error = elants_i2c_query_test_version(ts);
-       if (!error)
-               error = elants_i2c_query_ts_info(ts);
+
+       switch (ts->chip_id) {
+       case EKTH3500:
+               if (!error)
+                       error = elants_i2c_query_ts_info_ekth(ts);
+               break;
+       case EKTF3624:
+               if (!error)
+                       error = elants_i2c_query_ts_info_ektf(ts);
+               break;
+       default:
+               BUG();
+       }
 
        if (error)
                ts->iap_mode = ELAN_IAP_RECOVERY;
@@ -853,7 +922,8 @@ out:
  * Event reporting.
  */
 
-static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf)
+static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf,
+                               size_t packet_size)
 {
        struct input_dev *input = ts->input;
        unsigned int n_fingers;
@@ -880,8 +950,24 @@ static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf)
                        pos = &buf[FW_POS_XY + i * 3];
                        x = (((u16)pos[0] & 0xf0) << 4) | pos[1];
                        y = (((u16)pos[0] & 0x0f) << 8) | pos[2];
-                       p = buf[FW_POS_PRESSURE + i];
-                       w = buf[FW_POS_WIDTH + i];
+
+                       /*
+                        * eKTF3624 may have use "old" touch-report format,
+                        * depending on a device and TS firmware version.
+                        * For example, ASUS Transformer devices use the "old"
+                        * format, while ASUS Nexus 7 uses the "new" formant.
+                        */
+                       if (packet_size == PACKET_SIZE_OLD &&
+                           ts->chip_id == EKTF3624) {
+                               w = buf[FW_POS_WIDTH + i / 2];
+                               w >>= 4 * (~i & 1);
+                               w |= w << 4;
+                               w |= !w;
+                               p = w;
+                       } else {
+                               p = buf[FW_POS_PRESSURE + i];
+                               w = buf[FW_POS_WIDTH + i];
+                       }
 
                        dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n",
                                i, x, y, p, w);
@@ -913,7 +999,8 @@ static u8 elants_i2c_calculate_checksum(u8 *buf)
        return checksum;
 }
 
-static void elants_i2c_event(struct elants_data *ts, u8 *buf)
+static void elants_i2c_event(struct elants_data *ts, u8 *buf,
+                            size_t packet_size)
 {
        u8 checksum = elants_i2c_calculate_checksum(buf);
 
@@ -927,7 +1014,7 @@ static void elants_i2c_event(struct elants_data *ts, u8 *buf)
                         "%s: unknown packet type: %02x\n",
                         __func__, buf[FW_POS_HEADER]);
        else
-               elants_i2c_mt_event(ts, buf);
+               elants_i2c_mt_event(ts, buf, packet_size);
 }
 
 static irqreturn_t elants_i2c_irq(int irq, void *_dev)
@@ -970,7 +1057,6 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
                switch (ts->buf[FW_HDR_TYPE]) {
                case CMD_HEADER_HELLO:
                case CMD_HEADER_RESP:
-               case CMD_HEADER_REK:
                        break;
 
                case QUEUE_HEADER_WAIT:
@@ -985,9 +1071,24 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
                        break;
 
                case QUEUE_HEADER_SINGLE:
-                       elants_i2c_event(ts, &ts->buf[HEADER_SIZE]);
+                       elants_i2c_event(ts, &ts->buf[HEADER_SIZE],
+                                        ts->buf[FW_HDR_LENGTH]);
                        break;
 
+               case QUEUE_HEADER_NORMAL2: /* CMD_HEADER_REK */
+                       /*
+                        * Depending on firmware version, eKTF3624 touchscreens
+                        * may utilize one of these opcodes for the touch events:
+                        * 0x63 (NORMAL) and 0x66 (NORMAL2).  The 0x63 is used by
+                        * older firmware version and differs from 0x66 such that
+                        * touch pressure value needs to be adjusted.  The 0x66
+                        * opcode of newer firmware is equal to 0x63 of eKTH3500.
+                        */
+                       if (ts->chip_id != EKTF3624)
+                               break;
+
+                       fallthrough;
+
                case QUEUE_HEADER_NORMAL:
                        report_count = ts->buf[FW_HDR_COUNT];
                        if (report_count == 0 || report_count > 3) {
@@ -998,7 +1099,12 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
                        }
 
                        report_len = ts->buf[FW_HDR_LENGTH] / report_count;
-                       if (report_len != PACKET_SIZE) {
+
+                       if (report_len == PACKET_SIZE_OLD &&
+                           ts->chip_id == EKTF3624) {
+                               dev_dbg_once(&client->dev,
+                                            "using old report format\n");
+                       } else if (report_len != PACKET_SIZE) {
                                dev_err(&client->dev,
                                        "mismatching report length: %*ph\n",
                                        HEADER_SIZE, ts->buf);
@@ -1007,8 +1113,8 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
 
                        for (i = 0; i < report_count; i++) {
                                u8 *buf = ts->buf + HEADER_SIZE +
-                                                       i * PACKET_SIZE;
-                               elants_i2c_event(ts, buf);
+                                                       i * report_len;
+                               elants_i2c_event(ts, buf, report_len);
                        }
                        break;
 
@@ -1250,6 +1356,7 @@ static int elants_i2c_probe(struct i2c_client *client,
        init_completion(&ts->cmd_done);
 
        ts->client = client;
+       ts->chip_id = (enum elants_chip_id)id->driver_data;
        i2c_set_clientdata(client, ts);
 
        ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
@@ -1331,13 +1438,20 @@ static int elants_i2c_probe(struct i2c_client *client,
        input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
        input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE,
                             0, MT_TOOL_PALM, 0, 0);
+
+       touchscreen_parse_properties(ts->input, true, &ts->prop);
+
+       if (ts->chip_id == EKTF3624) {
+               /* calculate resolution from size */
+               ts->x_res = DIV_ROUND_CLOSEST(ts->prop.max_x, ts->phy_x);
+               ts->y_res = DIV_ROUND_CLOSEST(ts->prop.max_y, ts->phy_y);
+       }
+
        input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res);
        input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
        if (ts->major_res > 0)
                input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res);
 
-       touchscreen_parse_properties(ts->input, true, &ts->prop);
-
        error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM,
                                    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
        if (error) {
@@ -1466,14 +1580,16 @@ static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
                         elants_i2c_suspend, elants_i2c_resume);
 
 static const struct i2c_device_id elants_i2c_id[] = {
-       { DEVICE_NAME, 0 },
+       { DEVICE_NAME, EKTH3500 },
+       { "ekth3500", EKTH3500 },
+       { "ektf3624", EKTF3624 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, elants_i2c_id);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id elants_acpi_id[] = {
-       { "ELAN0001", 0 },
+       { "ELAN0001", EKTH3500 },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
@@ -1482,6 +1598,7 @@ MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
 #ifdef CONFIG_OF
 static const struct of_device_id elants_of_match[] = {
        { .compatible = "elan,ekth3500" },
+       { .compatible = "elan,ektf3624" },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, elants_of_match);
index e0bacd3..9617323 100644 (file)
@@ -341,8 +341,10 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
        switch (elo->id) {
 
        case 0: /* 10-byte protocol */
-               if (elo_setup_10(elo))
+               if (elo_setup_10(elo)) {
+                       err = -EIO;
                        goto fail3;
+               }
 
                break;
 
index 4fd21bc..54f3003 100644 (file)
@@ -2,8 +2,7 @@
 /*
  * Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
  *
- * Copyright (C) 2018
- * Author: Jeff LaBundy <jeff@labundy.com>
+ * Copyright (C) 2018 Jeff LaBundy <jeff@labundy.com>
  *
  * These devices require firmware exported from a PC-based configuration tool
  * made available by the vendor. Firmware files may be pushed to the device's
@@ -12,6 +11,7 @@
  * Link to PC-based configuration tool and data sheet: http://www.azoteq.com/
  */
 
+#include <linux/bits.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -30,9 +30,9 @@
 
 #define IQS5XX_FW_FILE_LEN     64
 #define IQS5XX_NUM_RETRIES     10
-#define IQS5XX_NUM_POINTS      256
 #define IQS5XX_NUM_CONTACTS    5
 #define IQS5XX_WR_BYTES_MAX    2
+#define IQS5XX_XY_RES_MAX      0xFFFE
 
 #define IQS5XX_PROD_NUM_IQS550 40
 #define IQS5XX_PROD_NUM_IQS572 58
 #define IQS5XX_PROJ_NUM_B000   15
 #define IQS5XX_MAJOR_VER_MIN   2
 
-#define IQS5XX_RESUME          0x00
-#define IQS5XX_SUSPEND         0x01
+#define IQS5XX_SHOW_RESET      BIT(7)
+#define IQS5XX_ACK_RESET       BIT(7)
 
-#define IQS5XX_SW_INPUT_EVENT  0x10
-#define IQS5XX_SETUP_COMPLETE  0x40
-#define IQS5XX_EVENT_MODE      0x01
-#define IQS5XX_TP_EVENT                0x04
+#define IQS5XX_SUSPEND         BIT(0)
+#define IQS5XX_RESUME          0
 
-#define IQS5XX_FLIP_X          0x01
-#define IQS5XX_FLIP_Y          0x02
-#define IQS5XX_SWITCH_XY_AXIS  0x04
+#define IQS5XX_SETUP_COMPLETE  BIT(6)
+#define IQS5XX_WDT             BIT(5)
+#define IQS5XX_ALP_REATI       BIT(3)
+#define IQS5XX_REATI           BIT(2)
+
+#define IQS5XX_TP_EVENT                BIT(2)
+#define IQS5XX_EVENT_MODE      BIT(0)
 
 #define IQS5XX_PROD_NUM                0x0000
-#define IQS5XX_ABS_X           0x0016
-#define IQS5XX_ABS_Y           0x0018
+#define IQS5XX_SYS_INFO0       0x000F
+#define IQS5XX_SYS_INFO1       0x0010
 #define IQS5XX_SYS_CTRL0       0x0431
 #define IQS5XX_SYS_CTRL1       0x0432
 #define IQS5XX_SYS_CFG0                0x058E
 #define IQS5XX_SYS_CFG1                0x058F
-#define IQS5XX_TOTAL_RX                0x063D
-#define IQS5XX_TOTAL_TX                0x063E
-#define IQS5XX_XY_CFG0         0x0669
 #define IQS5XX_X_RES           0x066E
 #define IQS5XX_Y_RES           0x0670
 #define IQS5XX_CHKSM           0x83C0
@@ -99,6 +98,7 @@ struct iqs5xx_private {
        struct i2c_client *client;
        struct input_dev *input;
        struct gpio_desc *reset_gpio;
+       struct touchscreen_properties prop;
        struct mutex lock;
        u8 bl_status;
 };
@@ -126,6 +126,14 @@ struct iqs5xx_touch_data {
        u8 area;
 } __packed;
 
+struct iqs5xx_status {
+       u8 sys_info[2];
+       u8 num_active;
+       __be16 rel_x;
+       __be16 rel_y;
+       struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
+} __packed;
+
 static int iqs5xx_read_burst(struct i2c_client *client,
                             u16 reg, void *val, u16 len)
 {
@@ -182,11 +190,6 @@ static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val)
        return 0;
 }
 
-static int iqs5xx_read_byte(struct i2c_client *client, u16 reg, u8 *val)
-{
-       return iqs5xx_read_burst(client, reg, val, sizeof(*val));
-}
-
 static int iqs5xx_write_burst(struct i2c_client *client,
                              u16 reg, const void *val, u16 len)
 {
@@ -337,11 +340,16 @@ static int iqs5xx_bl_open(struct i2c_client *client)
         */
        for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) {
                iqs5xx_reset(client);
+               usleep_range(350, 400);
 
                for (j = 0; j < IQS5XX_NUM_RETRIES; j++) {
                        error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
-                       if (!error || error == -EINVAL)
-                               return error;
+                       if (!error)
+                               usleep_range(10000, 10100);
+                       else if (error != -EINVAL)
+                               continue;
+
+                       return error;
                }
        }
 
@@ -481,12 +489,10 @@ static void iqs5xx_close(struct input_dev *input)
 static int iqs5xx_axis_init(struct i2c_client *client)
 {
        struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
-       struct touchscreen_properties prop;
+       struct touchscreen_properties *prop = &iqs5xx->prop;
        struct input_dev *input;
+       u16 max_x, max_y;
        int error;
-       u16 max_x, max_x_hw;
-       u16 max_y, max_y_hw;
-       u8 val;
 
        if (!iqs5xx->input) {
                input = devm_input_allocate_device(&client->dev);
@@ -506,89 +512,39 @@ static int iqs5xx_axis_init(struct i2c_client *client)
                iqs5xx->input = input;
        }
 
-       touchscreen_parse_properties(iqs5xx->input, true, &prop);
-
-       error = iqs5xx_read_byte(client, IQS5XX_TOTAL_RX, &val);
-       if (error)
-               return error;
-       max_x_hw = (val - 1) * IQS5XX_NUM_POINTS;
-
-       error = iqs5xx_read_byte(client, IQS5XX_TOTAL_TX, &val);
+       error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
        if (error)
                return error;
-       max_y_hw = (val - 1) * IQS5XX_NUM_POINTS;
 
-       error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val);
+       error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
        if (error)
                return error;
 
-       if (val & IQS5XX_SWITCH_XY_AXIS)
-               swap(max_x_hw, max_y_hw);
+       input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_X, max_x);
+       input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_Y, max_y);
 
-       if (prop.swap_x_y)
-               val ^= IQS5XX_SWITCH_XY_AXIS;
-
-       if (prop.invert_x)
-               val ^= prop.swap_x_y ? IQS5XX_FLIP_Y : IQS5XX_FLIP_X;
-
-       if (prop.invert_y)
-               val ^= prop.swap_x_y ? IQS5XX_FLIP_X : IQS5XX_FLIP_Y;
-
-       error = iqs5xx_write_byte(client, IQS5XX_XY_CFG0, val);
-       if (error)
-               return error;
+       touchscreen_parse_properties(iqs5xx->input, true, prop);
 
-       if (prop.max_x > max_x_hw) {
+       if (prop->max_x > IQS5XX_XY_RES_MAX) {
                dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
-                       prop.max_x, max_x_hw);
+                       prop->max_x, IQS5XX_XY_RES_MAX);
                return -EINVAL;
-       } else if (prop.max_x == 0) {
-               error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
+       } else if (prop->max_x != max_x) {
+               error = iqs5xx_write_word(client, IQS5XX_X_RES, prop->max_x);
                if (error)
                        return error;
-
-               input_abs_set_max(iqs5xx->input,
-                                 prop.swap_x_y ? ABS_MT_POSITION_Y :
-                                                 ABS_MT_POSITION_X,
-                                 max_x);
-       } else {
-               max_x = (u16)prop.max_x;
        }
 
-       if (prop.max_y > max_y_hw) {
+       if (prop->max_y > IQS5XX_XY_RES_MAX) {
                dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
-                       prop.max_y, max_y_hw);
+                       prop->max_y, IQS5XX_XY_RES_MAX);
                return -EINVAL;
-       } else if (prop.max_y == 0) {
-               error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
+       } else if (prop->max_y != max_y) {
+               error = iqs5xx_write_word(client, IQS5XX_Y_RES, prop->max_y);
                if (error)
                        return error;
-
-               input_abs_set_max(iqs5xx->input,
-                                 prop.swap_x_y ? ABS_MT_POSITION_X :
-                                                 ABS_MT_POSITION_Y,
-                                 max_y);
-       } else {
-               max_y = (u16)prop.max_y;
        }
 
-       /*
-        * Write horizontal and vertical resolution to the device in case its
-        * original defaults were overridden or swapped as per the properties
-        * specified in the device tree.
-        */
-       error = iqs5xx_write_word(client,
-                                 prop.swap_x_y ? IQS5XX_Y_RES : IQS5XX_X_RES,
-                                 max_x);
-       if (error)
-               return error;
-
-       error = iqs5xx_write_word(client,
-                                 prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
-                                 max_y);
-       if (error)
-               return error;
-
        error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS,
                                    INPUT_MT_DIRECT);
        if (error)
@@ -603,7 +559,6 @@ static int iqs5xx_dev_init(struct i2c_client *client)
        struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
        struct iqs5xx_dev_id_info *dev_id_info;
        int error;
-       u8 val;
        u8 buf[sizeof(*dev_id_info) + 1];
 
        error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM,
@@ -666,18 +621,18 @@ static int iqs5xx_dev_init(struct i2c_client *client)
        if (error)
                return error;
 
-       error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val);
+       error = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL0, IQS5XX_ACK_RESET);
        if (error)
                return error;
 
-       val |= IQS5XX_SETUP_COMPLETE;
-       val &= ~IQS5XX_SW_INPUT_EVENT;
-       error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, val);
+       error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0,
+                                 IQS5XX_SETUP_COMPLETE | IQS5XX_WDT |
+                                 IQS5XX_ALP_REATI | IQS5XX_REATI);
        if (error)
                return error;
 
-       val = IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE;
-       error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, val);
+       error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1,
+                                 IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE);
        if (error)
                return error;
 
@@ -688,13 +643,12 @@ static int iqs5xx_dev_init(struct i2c_client *client)
        iqs5xx->bl_status = dev_id_info->bl_status;
 
        /*
-        * Closure of the first communication window that appears following the
-        * release of reset appears to kick off an initialization period during
-        * which further communication is met with clock stretching. The return
-        * from this function is delayed so that further communication attempts
-        * avoid this period.
+        * The following delay allows ATI to complete before the open and close
+        * callbacks are free to elicit I2C communication. Any attempts to read
+        * from or write to the device during this time may face extended clock
+        * stretching and prompt the I2C controller to report an error.
         */
-       msleep(100);
+       msleep(250);
 
        return 0;
 }
@@ -702,7 +656,7 @@ static int iqs5xx_dev_init(struct i2c_client *client)
 static irqreturn_t iqs5xx_irq(int irq, void *data)
 {
        struct iqs5xx_private *iqs5xx = data;
-       struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
+       struct iqs5xx_status status;
        struct i2c_client *client = iqs5xx->client;
        struct input_dev *input = iqs5xx->input;
        int error, i;
@@ -715,21 +669,35 @@ static irqreturn_t iqs5xx_irq(int irq, void *data)
        if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
                return IRQ_NONE;
 
-       error = iqs5xx_read_burst(client, IQS5XX_ABS_X,
-                                 touch_data, sizeof(touch_data));
+       error = iqs5xx_read_burst(client, IQS5XX_SYS_INFO0,
+                                 &status, sizeof(status));
        if (error)
                return IRQ_NONE;
 
-       for (i = 0; i < ARRAY_SIZE(touch_data); i++) {
-               u16 pressure = be16_to_cpu(touch_data[i].strength);
+       if (status.sys_info[0] & IQS5XX_SHOW_RESET) {
+               dev_err(&client->dev, "Unexpected device reset\n");
+
+               error = iqs5xx_dev_init(client);
+               if (error) {
+                       dev_err(&client->dev,
+                               "Failed to re-initialize device: %d\n", error);
+                       return IRQ_NONE;
+               }
+
+               return IRQ_HANDLED;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(status.touch_data); i++) {
+               struct iqs5xx_touch_data *touch_data = &status.touch_data[i];
+               u16 pressure = be16_to_cpu(touch_data->strength);
 
                input_mt_slot(input, i);
                if (input_mt_report_slot_state(input, MT_TOOL_FINGER,
                                               pressure != 0)) {
-                       input_report_abs(input, ABS_MT_POSITION_X,
-                                        be16_to_cpu(touch_data[i].abs_x));
-                       input_report_abs(input, ABS_MT_POSITION_Y,
-                                        be16_to_cpu(touch_data[i].abs_y));
+                       touchscreen_report_pos(iqs5xx->input, &iqs5xx->prop,
+                                              be16_to_cpu(touch_data->abs_x),
+                                              be16_to_cpu(touch_data->abs_y),
+                                              true);
                        input_report_abs(input, ABS_MT_PRESSURE, pressure);
                }
        }
@@ -884,7 +852,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
 static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
 {
        struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
-       int error;
+       int error, error_bl = 0;
        u8 *pmap;
 
        if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE)
@@ -938,6 +906,7 @@ err_reset:
                usleep_range(10000, 10100);
        }
 
+       error_bl = error;
        error = iqs5xx_dev_init(client);
        if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
                error = -EINVAL;
@@ -949,11 +918,15 @@ err_reset:
 err_kfree:
        kfree(pmap);
 
+       if (error_bl)
+               return error_bl;
+
        return error;
 }
 
-static ssize_t fw_file_store(struct device *dev, struct device_attribute *attr,
-                               const char *buf, size_t count)
+static ssize_t fw_file_store(struct device *dev,
+                            struct device_attribute *attr, const char *buf,
+                            size_t count)
 {
        struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
        struct i2c_client *client = iqs5xx->client;
@@ -1012,7 +985,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev)
        struct input_dev *input = iqs5xx->input;
        int error = 0;
 
-       if (!input)
+       if (!input || device_may_wakeup(dev))
                return error;
 
        mutex_lock(&input->mutex);
@@ -1031,7 +1004,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev)
        struct input_dev *input = iqs5xx->input;
        int error = 0;
 
-       if (!input)
+       if (!input || device_may_wakeup(dev))
                return error;
 
        mutex_lock(&input->mutex);
index c005004..225796a 100644 (file)
@@ -465,13 +465,13 @@ static void mip4_report_keys(struct mip4_ts *ts, u8 *packet)
 static void mip4_report_touch(struct mip4_ts *ts, u8 *packet)
 {
        int id;
-       bool hover;
-       bool palm;
+       bool __always_unused hover;
+       bool __always_unused palm;
        bool state;
        u16 x, y;
-       u8 pressure_stage = 0;
+       u8 __always_unused pressure_stage = 0;
        u8 pressure;
-       u8 size;
+       u8 __always_unused size;
        u8 touch_major;
        u8 touch_minor;
 
index 603a948..4d2d22a 100644 (file)
@@ -445,6 +445,7 @@ static int raydium_i2c_write_object(struct i2c_client *client,
                                    enum raydium_bl_ack state)
 {
        int error;
+       static const u8 cmd[] = { 0xFF, 0x39 };
 
        error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len);
        if (error) {
@@ -453,7 +454,7 @@ static int raydium_i2c_write_object(struct i2c_client *client,
                return error;
        }
 
-       error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0);
+       error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, cmd, sizeof(cmd));
        if (error) {
                dev_err(&client->dev, "Ack obj command failed: %d\n", error);
                return error;
index b4e7bcb..6abae66 100644 (file)
@@ -94,8 +94,13 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
 
        for (retries = 10; retries; retries--) {
                error = st1232_ts_read_data(ts, REG_STATUS, 1);
-               if (!error && ts->read_buf[0] == (STATUS_NORMAL | ERROR_NONE))
-                       return 0;
+               if (!error) {
+                       switch (ts->read_buf[0]) {
+                       case STATUS_NORMAL | ERROR_NONE:
+                       case STATUS_IDLE | ERROR_NONE:
+                               return 0;
+                       }
+               }
 
                usleep_range(1000, 2000);
        }
index cd74772..25c45c3 100644 (file)
@@ -52,6 +52,7 @@
  * @idev: registered input device
  * @work: a work item used to scan the device
  * @dev: a pointer back to the MFD cell struct device*
+ * @prop: Touchscreen properties
  * @ave_ctrl: Sample average control
  * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
  * @touch_det_delay: Touch detect interrupt delay
index 620cdd7..12f2562 100644 (file)
@@ -787,6 +787,7 @@ static int sur40_probe(struct usb_interface *interface,
                dev_err(&interface->dev,
                        "Unable to register video controls.");
                v4l2_ctrl_handler_free(&sur40->hdl);
+               error = sur40->hdl.error;
                goto err_unreg_v4l2;
        }
 
index 7314545..1da23e5 100644 (file)
@@ -94,9 +94,7 @@ static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
 
 static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
 {
-       u16 timestamp;
        unsigned int i;
-       timestamp = get_unaligned_le16(&data[15]);
 
        for (i = 0; i < 13; i++) {
                struct surface3_ts_data_finger *finger;
index 397cb1d..c847453 100644 (file)
@@ -1044,6 +1044,7 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
 
 static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
 {
+       struct device *dev = &usbtouch->interface->dev;
        struct nexio_touch_packet *packet = (void *) pkt;
        struct nexio_priv *priv = usbtouch->priv;
        unsigned int data_len = be16_to_cpu(packet->data_len);
@@ -1062,6 +1063,8 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
 
        /* send ACK */
        ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
+       if (ret)
+               dev_warn(dev, "Failed to submit ACK URB: %d\n", ret);
 
        if (!usbtouch->type->max_xc) {
                usbtouch->type->max_xc = 2 * x_len;
index a3e3adb..3b636be 100644 (file)
@@ -161,7 +161,7 @@ static int zinitix_read_data(struct i2c_client *client,
 
        ret = i2c_master_recv(client, (u8 *)values, length);
        if (ret != length)
-               return ret < 0 ? ret : -EIO; ;
+               return ret < 0 ? ret : -EIO;
 
        return 0;
 }
@@ -190,7 +190,7 @@ static int zinitix_write_cmd(struct i2c_client *client, u16 reg)
        return 0;
 }
 
-static bool zinitix_init_touch(struct bt541_ts_data *bt541)
+static int zinitix_init_touch(struct bt541_ts_data *bt541)
 {
        struct i2c_client *client = bt541->client;
        int i;
diff --git a/include/dt-bindings/input/cros-ec-keyboard.h b/include/dt-bindings/input/cros-ec-keyboard.h
new file mode 100644 (file)
index 0000000..f0ae036
--- /dev/null
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides the constants of the standard Chrome OS key matrix
+ * for cros-ec keyboard-controller bindings.
+ *
+ * Copyright (c) 2021 Google, Inc
+ */
+
+#ifndef _CROS_EC_KEYBOARD_H
+#define _CROS_EC_KEYBOARD_H
+
+#define CROS_STD_TOP_ROW_KEYMAP        \
+       MATRIX_KEY(0x00, 0x02, KEY_F1)  \
+       MATRIX_KEY(0x03, 0x02, KEY_F2)  \
+       MATRIX_KEY(0x02, 0x02, KEY_F3)  \
+       MATRIX_KEY(0x01, 0x02, KEY_F4)  \
+       MATRIX_KEY(0x03, 0x04, KEY_F5)  \
+       MATRIX_KEY(0x02, 0x04, KEY_F6)  \
+       MATRIX_KEY(0x01, 0x04, KEY_F7)  \
+       MATRIX_KEY(0x02, 0x09, KEY_F8)  \
+       MATRIX_KEY(0x01, 0x09, KEY_F9)  \
+       MATRIX_KEY(0x00, 0x04, KEY_F10)
+
+#define CROS_STD_MAIN_KEYMAP   \
+       MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA)    \
+       MATRIX_KEY(0x00, 0x03, KEY_B)           \
+       MATRIX_KEY(0x00, 0x05, KEY_RO)          \
+       MATRIX_KEY(0x00, 0x06, KEY_N)           \
+       MATRIX_KEY(0x00, 0x08, KEY_EQUAL)       \
+       MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT)    \
+       MATRIX_KEY(0x01, 0x01, KEY_ESC)         \
+       MATRIX_KEY(0x01, 0x03, KEY_G)           \
+       MATRIX_KEY(0x01, 0x06, KEY_H)           \
+       MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE)  \
+       MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE)   \
+       MATRIX_KEY(0x01, 0x0c, KEY_HENKAN)      \
+                                               \
+       MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL)    \
+       MATRIX_KEY(0x02, 0x01, KEY_TAB)         \
+       MATRIX_KEY(0x02, 0x03, KEY_T)           \
+       MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE)  \
+       MATRIX_KEY(0x02, 0x06, KEY_Y)           \
+       MATRIX_KEY(0x02, 0x07, KEY_102ND)       \
+       MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE)   \
+       MATRIX_KEY(0x02, 0x0a, KEY_YEN)         \
+                                               \
+       MATRIX_KEY(0x03, 0x00, KEY_LEFTMETA)    \
+       MATRIX_KEY(0x03, 0x01, KEY_GRAVE)       \
+       MATRIX_KEY(0x03, 0x03, KEY_5)           \
+       MATRIX_KEY(0x03, 0x06, KEY_6)           \
+       MATRIX_KEY(0x03, 0x08, KEY_MINUS)       \
+       MATRIX_KEY(0x03, 0x09, KEY_SLEEP)       \
+       MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH)   \
+       MATRIX_KEY(0x03, 0x0c, KEY_MUHENKAN)    \
+                                               \
+       MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL)   \
+       MATRIX_KEY(0x04, 0x01, KEY_A)           \
+       MATRIX_KEY(0x04, 0x02, KEY_D)           \
+       MATRIX_KEY(0x04, 0x03, KEY_F)           \
+       MATRIX_KEY(0x04, 0x04, KEY_S)           \
+       MATRIX_KEY(0x04, 0x05, KEY_K)           \
+       MATRIX_KEY(0x04, 0x06, KEY_J)           \
+       MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON)   \
+       MATRIX_KEY(0x04, 0x09, KEY_L)           \
+       MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH)   \
+       MATRIX_KEY(0x04, 0x0b, KEY_ENTER)       \
+                                               \
+       MATRIX_KEY(0x05, 0x01, KEY_Z)           \
+       MATRIX_KEY(0x05, 0x02, KEY_C)           \
+       MATRIX_KEY(0x05, 0x03, KEY_V)           \
+       MATRIX_KEY(0x05, 0x04, KEY_X)           \
+       MATRIX_KEY(0x05, 0x05, KEY_COMMA)       \
+       MATRIX_KEY(0x05, 0x06, KEY_M)           \
+       MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT)   \
+       MATRIX_KEY(0x05, 0x08, KEY_SLASH)       \
+       MATRIX_KEY(0x05, 0x09, KEY_DOT)         \
+       MATRIX_KEY(0x05, 0x0b, KEY_SPACE)       \
+                                               \
+       MATRIX_KEY(0x06, 0x01, KEY_1)           \
+       MATRIX_KEY(0x06, 0x02, KEY_3)           \
+       MATRIX_KEY(0x06, 0x03, KEY_4)           \
+       MATRIX_KEY(0x06, 0x04, KEY_2)           \
+       MATRIX_KEY(0x06, 0x05, KEY_8)           \
+       MATRIX_KEY(0x06, 0x06, KEY_7)           \
+       MATRIX_KEY(0x06, 0x08, KEY_0)           \
+       MATRIX_KEY(0x06, 0x09, KEY_9)           \
+       MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT)     \
+       MATRIX_KEY(0x06, 0x0b, KEY_DOWN)        \
+       MATRIX_KEY(0x06, 0x0c, KEY_RIGHT)       \
+                                               \
+       MATRIX_KEY(0x07, 0x01, KEY_Q)           \
+       MATRIX_KEY(0x07, 0x02, KEY_E)           \
+       MATRIX_KEY(0x07, 0x03, KEY_R)           \
+       MATRIX_KEY(0x07, 0x04, KEY_W)           \
+       MATRIX_KEY(0x07, 0x05, KEY_I)           \
+       MATRIX_KEY(0x07, 0x06, KEY_U)           \
+       MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT)  \
+       MATRIX_KEY(0x07, 0x08, KEY_P)           \
+       MATRIX_KEY(0x07, 0x09, KEY_O)           \
+       MATRIX_KEY(0x07, 0x0b, KEY_UP)          \
+       MATRIX_KEY(0x07, 0x0c, KEY_LEFT)
+
+#endif /* _CROS_EC_KEYBOARD_H */