Merge tag 'v5.9' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 18 Nov 2020 02:13:23 +0000 (18:13 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 18 Nov 2020 02:13:23 +0000 (18:13 -0800)
Sync up with mainline to bring in the latest DTS files.

58 files changed:
Documentation/devicetree/bindings/input/adc-joystick.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt
Documentation/devicetree/bindings/input/touchscreen/zinitix.txt [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.yaml
MAINTAINERS
drivers/hid/hid-rmi.c
drivers/input/evdev.c
drivers/input/input-mt.c
drivers/input/joystick/Kconfig
drivers/input/joystick/Makefile
drivers/input/joystick/adc-joystick.c [new file with mode: 0644]
drivers/input/joystick/analog.c
drivers/input/keyboard/cros_ec_keyb.c
drivers/input/keyboard/ep93xx_keypad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/keyboard/pmic8xxx-keypad.c
drivers/input/keyboard/samsung-keypad.c
drivers/input/keyboard/twl4030_keypad.c
drivers/input/misc/ab8500-ponkey.c
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c
drivers/input/misc/drv2667.c
drivers/input/misc/soc_button_array.c
drivers/input/mouse/cyapa.c
drivers/input/mouse/cyapa_gen5.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/elantech.c
drivers/input/mouse/synaptics.c
drivers/input/rmi4/Kconfig
drivers/input/rmi4/Makefile
drivers/input/rmi4/rmi_bus.c
drivers/input/rmi4/rmi_driver.h
drivers/input/rmi4/rmi_f01.c
drivers/input/rmi4/rmi_f11.c
drivers/input/rmi4/rmi_f30.c
drivers/input/rmi4/rmi_f34v7.c
drivers/input/rmi4/rmi_f3a.c [new file with mode: 0644]
drivers/input/rmi4/rmi_f54.c
drivers/input/rmi4/rmi_i2c.c
drivers/input/serio/sun4i-ps2.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/cyttsp4_core.c
drivers/input/touchscreen/cyttsp4_core.h
drivers/input/touchscreen/ektf2127.c
drivers/input/touchscreen/elants_i2c.c
drivers/input/touchscreen/imx6ul_tsc.c
drivers/input/touchscreen/raydium_i2c_ts.c
drivers/input/touchscreen/resistive-adc-touch.c
drivers/input/touchscreen/st1232.c
drivers/input/touchscreen/stmfts.c
drivers/input/touchscreen/zinitix.c [new file with mode: 0644]
drivers/platform/x86/thinkpad_acpi.c
include/linux/rmi.h
include/uapi/linux/input-event-codes.h

diff --git a/Documentation/devicetree/bindings/input/adc-joystick.yaml b/Documentation/devicetree/bindings/input/adc-joystick.yaml
new file mode 100644 (file)
index 0000000..054406b
--- /dev/null
@@ -0,0 +1,121 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019-2020 Artur Rojek
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/input/adc-joystick.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: ADC attached joystick
+
+maintainers:
+  - Artur Rojek <contact@artur-rojek.eu>
+
+description: >
+  Bindings for joystick devices connected to ADC controllers supporting
+  the Industrial I/O subsystem.
+
+properties:
+  compatible:
+    const: adc-joystick
+
+  io-channels:
+    minItems: 1
+    maxItems: 1024
+    description: >
+      List of phandle and IIO specifier pairs.
+      Each pair defines one ADC channel to which a joystick axis is connected.
+      See Documentation/devicetree/bindings/iio/iio-bindings.txt for details.
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+required:
+  - compatible
+  - io-channels
+  - '#address-cells'
+  - '#size-cells'
+
+additionalProperties: false
+
+patternProperties:
+  "^axis@[0-9a-f]+$":
+    type: object
+    description: >
+      Represents a joystick axis bound to the given ADC channel.
+      For each entry in the io-channels list, one axis subnode with a matching
+      reg property must be specified.
+
+    properties:
+      reg:
+        minimum: 0
+        maximum: 1023
+        description: Index of an io-channels list entry bound to this axis.
+
+      linux,code:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: EV_ABS specific event code generated by the axis.
+
+      abs-range:
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-array
+          - items:
+              - description: minimum value
+              - description: maximum value
+        description: >
+          Minimum and maximum values produced by the axis.
+          For an ABS_X axis this will be the left-most and right-most
+          inclination of the joystick. If min > max, it is left to userspace to
+          treat the axis as inverted.
+          This property is interpreted as two signed 32 bit values.
+
+      abs-fuzz:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: >
+          Amount of noise in the input value.
+          Omitting this property indicates the axis is precise.
+
+      abs-flat:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        description: >
+          Axial "deadzone", or area around the center position, where the axis
+          is considered to be at rest.
+          Omitting this property indicates the axis always returns to exactly
+          the center position.
+
+    required:
+      - reg
+      - linux,code
+      - abs-range
+
+    additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/iio/adc/ingenic,adc.h>
+    #include <dt-bindings/input/input.h>
+
+    joystick: adc-joystick {
+      compatible = "adc-joystick";
+      io-channels = <&adc INGENIC_ADC_TOUCH_XP>,
+                    <&adc INGENIC_ADC_TOUCH_YP>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      axis@0 {
+              reg = <0>;
+              linux,code = <ABS_X>;
+              abs-range = <3300 0>;
+              abs-fuzz = <4>;
+              abs-flat = <200>;
+      };
+      axis@1 {
+              reg = <1>;
+              linux,code = <ABS_Y>;
+              abs-range = <0 3300>;
+              abs-fuzz = <4>;
+              abs-flat = <200>;
+      };
+    };
index 94c4fc64494072b7160c836b7feb2fdfe49d5160..5eef5e7d6aae12f4bd0278e92d863eef58ef7fa3 100644 (file)
@@ -1,7 +1,7 @@
 * Elan eKTF2127 I2C touchscreen controller
 
 Required properties:
- - compatible            : "elan,ektf2127"
+ - compatible            : "elan,ektf2127" or "elan,ektf2132"
  - reg                   : I2C slave address of the chip (0x40)
  - interrupts            : interrupt specification for the ektf2127 interrupt
  - power-gpios           : GPIO specification for the pin connected to the
diff --git a/Documentation/devicetree/bindings/input/touchscreen/zinitix.txt b/Documentation/devicetree/bindings/input/touchscreen/zinitix.txt
new file mode 100644 (file)
index 0000000..446efb9
--- /dev/null
@@ -0,0 +1,40 @@
+Device tree bindings for Zinitx BT541 touchscreen controller
+
+Required properties:
+
+ - compatible          : Should be "zinitix,bt541"
+ - reg                 : I2C address of the chip. Should be 0x20
+ - interrupts          : Interrupt to which the chip is connected
+
+Optional properties:
+
+ - vdd-supply          : Analog power supply regulator on VCCA pin
+ - vddo-supply         : Digital power supply regulator on VDD pin
+ - zinitix,mode                : Mode of reporting touch points. Some modes may not work
+                         with a particular ts firmware for unknown reasons. Available
+                         modes are 1 and 2. Mode 2 is the default and preferred.
+
+The touchscreen-* properties are documented in touchscreen.txt in this
+directory.
+
+Example:
+
+       i2c@00000000 {
+               /* ... */
+
+               bt541@20 {
+                       compatible = "zinitix,bt541";
+                       reg = <0x20>;
+                       interrupt-parent = <&msmgpio>;
+                       interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&tsp_default>;
+                       vdd-supply = <&reg_vdd_tsp>;
+                       vddo-supply = <&pm8916_l6>;
+                       touchscreen-size-x = <540>;
+                       touchscreen-size-y = <960>;
+                       zinitix,mode = <2>;
+               };
+
+               /* ... */
+       };
index 63996ab03521741bbfe7ad9a3f2c07f9bd8260b2..2f0d9941ba39779b14ad318ae2a804d021a2af4b 100644 (file)
@@ -1198,6 +1198,8 @@ patternProperties:
     description: Shenzhen Zidoo Technology Co., Ltd.
   "^zii,.*":
     description: Zodiac Inflight Innovations
+  "^zinitix,.*":
+    description: Zinitix Co., Ltd
   "^zte,.*":
     description: ZTE Corp.
   "^zyxel,.*":
index 867157311dc8b59f6c140fb91ffd1b53bbe42e86..d6c8f3016f5745a345c3a0c5f7d1b3b95b159d29 100644 (file)
@@ -15913,6 +15913,13 @@ F:     Documentation/fb/sisfb.rst
 F:     drivers/video/fbdev/sis/
 F:     include/video/sisfb.h
 
+SIS I2C TOUCHSCREEN DRIVER
+M:     Mika Penttilä <mika.penttila@nextfour.com>
+L:     linux-input@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt
+F:     drivers/input/touchscreen/sis_i2c.c
+
 SIS USB2VGA DRIVER
 M:     Thomas Winischhofer <thomas@winischhofer.net>
 S:     Maintained
index 7f41213d5ae3430be88e7ac499c39f68daa9ae52..311eee599ce97e819ba9d2b25a15de70696468bc 100644 (file)
@@ -720,7 +720,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
        }
 
        if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS)
-               rmi_hid_pdata.f30_data.disable = true;
+               rmi_hid_pdata.gpio_data.disable = true;
 
        data->xport.dev = hdev->dev.parent;
        data->xport.pdata = rmi_hid_pdata;
index e494295d1c7b7134cf8a1ba67682a19306b9ca7b..95f90699d2b17b4e42e067bf44b6deac611fdb8b 100644 (file)
@@ -28,7 +28,6 @@
 struct evdev {
        int open;
        struct input_handle handle;
-       wait_queue_head_t wait;
        struct evdev_client __rcu *grab;
        struct list_head client_list;
        spinlock_t client_lock; /* protects client_list */
@@ -43,6 +42,7 @@ struct evdev_client {
        unsigned int tail;
        unsigned int packet_head; /* [future] position of the first element of next packet */
        spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+       wait_queue_head_t wait;
        struct fasync_struct *fasync;
        struct evdev *evdev;
        struct list_head node;
@@ -245,7 +245,6 @@ static void evdev_pass_values(struct evdev_client *client,
                        const struct input_value *vals, unsigned int count,
                        ktime_t *ev_time)
 {
-       struct evdev *evdev = client->evdev;
        const struct input_value *v;
        struct input_event event;
        struct timespec64 ts;
@@ -282,7 +281,7 @@ static void evdev_pass_values(struct evdev_client *client,
        spin_unlock(&client->buffer_lock);
 
        if (wakeup)
-               wake_up_interruptible_poll(&evdev->wait,
+               wake_up_interruptible_poll(&client->wait,
                        EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM);
 }
 
@@ -426,11 +425,11 @@ static void evdev_hangup(struct evdev *evdev)
        struct evdev_client *client;
 
        spin_lock(&evdev->client_lock);
-       list_for_each_entry(client, &evdev->client_list, node)
+       list_for_each_entry(client, &evdev->client_list, node) {
                kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+               wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
+       }
        spin_unlock(&evdev->client_lock);
-
-       wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR);
 }
 
 static int evdev_release(struct inode *inode, struct file *file)
@@ -479,6 +478,7 @@ static int evdev_open(struct inode *inode, struct file *file)
        if (!client)
                return -ENOMEM;
 
+       init_waitqueue_head(&client->wait);
        client->bufsize = bufsize;
        spin_lock_init(&client->buffer_lock);
        client->evdev = evdev;
@@ -595,7 +595,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
                        break;
 
                if (!(file->f_flags & O_NONBLOCK)) {
-                       error = wait_event_interruptible(evdev->wait,
+                       error = wait_event_interruptible(client->wait,
                                        client->packet_head != client->tail ||
                                        !evdev->exist || client->revoked);
                        if (error)
@@ -613,7 +613,7 @@ static __poll_t evdev_poll(struct file *file, poll_table *wait)
        struct evdev *evdev = client->evdev;
        __poll_t mask;
 
-       poll_wait(file, &evdev->wait, wait);
+       poll_wait(file, &client->wait, wait);
 
        if (evdev->exist && !client->revoked)
                mask = EPOLLOUT | EPOLLWRNORM;
@@ -946,7 +946,7 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
        client->revoked = true;
        evdev_ungrab(evdev, client);
        input_flush_device(&evdev->handle, file);
-       wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR);
+       wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
 
        return 0;
 }
@@ -1358,7 +1358,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
        INIT_LIST_HEAD(&evdev->client_list);
        spin_lock_init(&evdev->client_lock);
        mutex_init(&evdev->mutex);
-       init_waitqueue_head(&evdev->wait);
        evdev->exist = true;
 
        dev_no = minor;
index f699538bdac4b5be1f679cab9cf3183950e9376c..44fe6f2f063ce45cc7d6830881e2cdf01d30495b 100644 (file)
@@ -323,11 +323,14 @@ static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
        p = begin + step;
        s = p == end ? f + 1 : *p;
 
-       for (; p != end; p += step)
-               if (*p < f)
-                       s = f, f = *p;
-               else if (*p < s)
+       for (; p != end; p += step) {
+               if (*p < f) {
+                       s = f;
+                       f = *p;
+               } else if (*p < s) {
                        s = *p;
+               }
+       }
 
        c = (f + s + 1) / 2;
        if (c == 0 || (c > mu && (!eq || mu > 0)))
index eb031b7a486632bd698d359bb3fb07dbdaaaa044..b080f0cfb068f0ad3912a72048cd84836ab76182 100644 (file)
@@ -42,6 +42,16 @@ config JOYSTICK_A3D
          To compile this driver as a module, choose M here: the
          module will be called a3d.
 
+config JOYSTICK_ADC
+       tristate "Simple joystick connected over ADC"
+       depends on IIO
+       select IIO_BUFFER_CB
+       help
+         Say Y here if you have a simple joystick connected over ADC.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adc-joystick.
+
 config JOYSTICK_ADI
        tristate "Logitech ADI digital joysticks and gamepads"
        select GAMEPORT
index 8656023f6ef531d0297ce3425c349c6b83186dc1..58232b3057d308fe02269f8b3b3da70aafb08880 100644 (file)
@@ -6,6 +6,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_JOYSTICK_A3D)             += a3d.o
+obj-$(CONFIG_JOYSTICK_ADC)             += adc-joystick.o
 obj-$(CONFIG_JOYSTICK_ADI)             += adi.o
 obj-$(CONFIG_JOYSTICK_AMIGA)           += amijoy.o
 obj-$(CONFIG_JOYSTICK_AS5011)          += as5011.o
diff --git a/drivers/input/joystick/adc-joystick.c b/drivers/input/joystick/adc-joystick.c
new file mode 100644 (file)
index 0000000..78ebca7
--- /dev/null
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Input driver for joysticks connected over ADC.
+ * Copyright (c) 2019-2020 Artur Rojek <contact@artur-rojek.eu>
+ */
+#include <linux/ctype.h>
+#include <linux/input.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/consumer.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#include <asm/unaligned.h>
+
+struct adc_joystick_axis {
+       u32 code;
+       s32 range[2];
+       s32 fuzz;
+       s32 flat;
+};
+
+struct adc_joystick {
+       struct input_dev *input;
+       struct iio_cb_buffer *buffer;
+       struct adc_joystick_axis *axes;
+       struct iio_channel *chans;
+       int num_chans;
+};
+
+static int adc_joystick_handle(const void *data, void *private)
+{
+       struct adc_joystick *joy = private;
+       enum iio_endian endianness;
+       int bytes, msb, val, idx, i;
+       const u16 *data_u16;
+       bool sign;
+
+       bytes = joy->chans[0].channel->scan_type.storagebits >> 3;
+
+       for (i = 0; i < joy->num_chans; ++i) {
+               idx = joy->chans[i].channel->scan_index;
+               endianness = joy->chans[i].channel->scan_type.endianness;
+               msb = joy->chans[i].channel->scan_type.realbits - 1;
+               sign = tolower(joy->chans[i].channel->scan_type.sign) == 's';
+
+               switch (bytes) {
+               case 1:
+                       val = ((const u8 *)data)[idx];
+                       break;
+               case 2:
+                       data_u16 = (const u16 *)data + idx;
+
+                       /*
+                        * Data is aligned to the sample size by IIO core.
+                        * Call `get_unaligned_xe16` to hide type casting.
+                        */
+                       if (endianness == IIO_BE)
+                               val = get_unaligned_be16(data_u16);
+                       else if (endianness == IIO_LE)
+                               val = get_unaligned_le16(data_u16);
+                       else /* IIO_CPU */
+                               val = *data_u16;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               val >>= joy->chans[i].channel->scan_type.shift;
+               if (sign)
+                       val = sign_extend32(val, msb);
+               else
+                       val &= GENMASK(msb, 0);
+               input_report_abs(joy->input, joy->axes[i].code, val);
+       }
+
+       input_sync(joy->input);
+
+       return 0;
+}
+
+static int adc_joystick_open(struct input_dev *dev)
+{
+       struct adc_joystick *joy = input_get_drvdata(dev);
+       struct device *devp = &dev->dev;
+       int ret;
+
+       ret = iio_channel_start_all_cb(joy->buffer);
+       if (ret)
+               dev_err(devp, "Unable to start callback buffer: %d\n", ret);
+
+       return ret;
+}
+
+static void adc_joystick_close(struct input_dev *dev)
+{
+       struct adc_joystick *joy = input_get_drvdata(dev);
+
+       iio_channel_stop_all_cb(joy->buffer);
+}
+
+static void adc_joystick_cleanup(void *data)
+{
+       iio_channel_release_all_cb(data);
+}
+
+static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
+{
+       struct adc_joystick_axis *axes;
+       struct fwnode_handle *child;
+       int num_axes, error, i;
+
+       num_axes = device_get_child_node_count(dev);
+       if (!num_axes) {
+               dev_err(dev, "Unable to find child nodes\n");
+               return -EINVAL;
+       }
+
+       if (num_axes != joy->num_chans) {
+               dev_err(dev, "Got %d child nodes for %d channels\n",
+                       num_axes, joy->num_chans);
+               return -EINVAL;
+       }
+
+       axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL);
+       if (!axes)
+               return -ENOMEM;
+
+       device_for_each_child_node(dev, child) {
+               error = fwnode_property_read_u32(child, "reg", &i);
+               if (error) {
+                       dev_err(dev, "reg invalid or missing\n");
+                       goto err_fwnode_put;
+               }
+
+               if (i >= num_axes) {
+                       error = -EINVAL;
+                       dev_err(dev, "No matching axis for reg %d\n", i);
+                       goto err_fwnode_put;
+               }
+
+               error = fwnode_property_read_u32(child, "linux,code",
+                                                &axes[i].code);
+               if (error) {
+                       dev_err(dev, "linux,code invalid or missing\n");
+                       goto err_fwnode_put;
+               }
+
+               error = fwnode_property_read_u32_array(child, "abs-range",
+                                                      axes[i].range, 2);
+               if (error) {
+                       dev_err(dev, "abs-range invalid or missing\n");
+                       goto err_fwnode_put;
+               }
+
+               fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz);
+               fwnode_property_read_u32(child, "abs-flat", &axes[i].flat);
+
+               input_set_abs_params(joy->input, axes[i].code,
+                                    axes[i].range[0], axes[i].range[1],
+                                    axes[i].fuzz, axes[i].flat);
+               input_set_capability(joy->input, EV_ABS, axes[i].code);
+       }
+
+       joy->axes = axes;
+
+       return 0;
+
+err_fwnode_put:
+       fwnode_handle_put(child);
+       return error;
+}
+
+static int adc_joystick_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct adc_joystick *joy;
+       struct input_dev *input;
+       int error;
+       int bits;
+       int i;
+
+       joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL);
+       if (!joy)
+               return -ENOMEM;
+
+       joy->chans = devm_iio_channel_get_all(dev);
+       if (IS_ERR(joy->chans)) {
+               error = PTR_ERR(joy->chans);
+               if (error != -EPROBE_DEFER)
+                       dev_err(dev, "Unable to get IIO channels");
+               return error;
+       }
+
+       /* Count how many channels we got. NULL terminated. */
+       for (i = 0; joy->chans[i].indio_dev; i++) {
+               bits = joy->chans[i].channel->scan_type.storagebits;
+               if (!bits || bits > 16) {
+                       dev_err(dev, "Unsupported channel storage size\n");
+                       return -EINVAL;
+               }
+               if (bits != joy->chans[0].channel->scan_type.storagebits) {
+                       dev_err(dev, "Channels must have equal storage size\n");
+                       return -EINVAL;
+               }
+       }
+       joy->num_chans = i;
+
+       input = devm_input_allocate_device(dev);
+       if (!input) {
+               dev_err(dev, "Unable to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       joy->input = input;
+       input->name = pdev->name;
+       input->id.bustype = BUS_HOST;
+       input->open = adc_joystick_open;
+       input->close = adc_joystick_close;
+
+       error = adc_joystick_set_axes(dev, joy);
+       if (error)
+               return error;
+
+       input_set_drvdata(input, joy);
+       error = input_register_device(input);
+       if (error) {
+               dev_err(dev, "Unable to register input device\n");
+               return error;
+       }
+
+       joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle, joy);
+       if (IS_ERR(joy->buffer)) {
+               dev_err(dev, "Unable to allocate callback buffer\n");
+               return PTR_ERR(joy->buffer);
+       }
+
+       error = devm_add_action_or_reset(dev, adc_joystick_cleanup, joy->buffer);
+       if (error)  {
+               dev_err(dev, "Unable to add action\n");
+               return error;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id adc_joystick_of_match[] = {
+       { .compatible = "adc-joystick", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, adc_joystick_of_match);
+
+static struct platform_driver adc_joystick_driver = {
+       .driver = {
+               .name = "adc-joystick",
+               .of_match_table = adc_joystick_of_match,
+       },
+       .probe = adc_joystick_probe,
+};
+module_platform_driver(adc_joystick_driver);
+
+MODULE_DESCRIPTION("Input driver for joysticks connected over ADC");
+MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
+MODULE_LICENSE("GPL");
index 2b625ebef914d13772ce40aaaa6b14dc9c3e50a7..f798922a4598c15c40a2da2aeb1dc0f7b82698b7 100644 (file)
@@ -665,7 +665,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv
        int err;
 
        if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL)))
-               return - ENOMEM;
+               return -ENOMEM;
 
        err = analog_init_port(gameport, drv, port);
        if (err)
index fc1793ca2f1747511c04d40b79e2e3790fe39221..023f083dadd3ba79cccdb8c34dd22b3ac021e6ef 100644 (file)
@@ -27,7 +27,9 @@
 
 #include <asm/unaligned.h>
 
-/*
+/**
+ * struct cros_ec_keyb - Structure representing EC keyboard device
+ *
  * @rows: Number of rows in the keypad
  * @cols: Number of columns in the keypad
  * @row_shift: log2 or number of rows, rounded up
@@ -58,10 +60,9 @@ struct cros_ec_keyb {
        struct notifier_block notifier;
 };
 
-
 /**
- * cros_ec_bs_map - Struct mapping Linux keycodes to EC button/switch bitmap
- * #defines
+ * struct cros_ec_bs_map - Mapping between Linux keycodes and EC button/switch
+ *     bitmap #defines
  *
  * @ev_type: The type of the input event to generate (e.g., EV_KEY).
  * @code: A linux keycode
index 7c70492d9d6b5b7c53911b2cc6f376a988890c12..f831f01501d58c991fba95fa3fe354c6207b2aaa 100644 (file)
@@ -250,8 +250,8 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
        }
 
        keypad->irq = platform_get_irq(pdev, 0);
-       if (!keypad->irq) {
-               err = -ENXIO;
+       if (keypad->irq < 0) {
+               err = keypad->irq;
                goto failed_free;
        }
 
index f2d4e4daa818f2e3e602b9f87811de8062df98c5..a079504e98e82f45d3bc7ae231678e8368f2555b 100644 (file)
@@ -108,7 +108,7 @@ static int get_n_events_by_type(int type)
 
 /**
  * get_bm_events_by_type() - returns bitmap of supported events per @type
- * @input: input device from which bitmap is retrieved
+ * @dev: input device from which bitmap is retrieved
  * @type: type of button (%EV_KEY, %EV_SW)
  *
  * Return value of this function can be used to allocate bitmap
index 608446e14614d85937b1de4294bd0537dcae4da3..0d55a95347f1652e441f7d316365fe500dd098c9 100644 (file)
@@ -58,6 +58,8 @@
  * @board:     keypad platform device
  * @keymap:    matrix scan code table for keycodes
  * @clk:       clock structure pointer
+ * @pclk:      clock structure pointer
+ * @ske_keypad_lock: spinlock protecting the keypad read/writes
  */
 struct ske_keypad {
        int irq;
index 94c94d7f5155f7f84b3cee1e4691ebeda0c15261..d6c924032aaa813d3bda854b48cd6abb8e5b16b2 100644 (file)
@@ -240,10 +240,8 @@ static int omap4_keypad_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (!irq) {
-               dev_err(&pdev->dev, "no keyboard irq assigned\n");
-               return -EINVAL;
-       }
+       if (irq < 0)
+               return irq;
 
        keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
        if (!keypad_data) {
index 91d5811d6f0e1f716e0e6399c0fdc0ad41bb3ed9..36bee6f5a8af08efefeca0e924465dfd808f25b9 100644 (file)
 
 /**
  * struct pmic8xxx_kp - internal keypad data structure
- * @num_cols - number of columns of keypad
- * @num_rows - number of row of keypad
- * @input - input device pointer for keypad
- * @regmap - regmap handle
- * @key_sense_irq - key press/release irq number
- * @key_stuck_irq - key stuck notification irq number
- * @keycodes - array to hold the key codes
- * @dev - parent device pointer
- * @keystate - present key press/release state
- * @stuckstate - present state when key stuck irq
- * @ctrl_reg - control register value
+ * @num_cols: number of columns of keypad
+ * @num_rows: number of row of keypad
+ * @input: input device pointer for keypad
+ * @regmap: regmap handle
+ * @key_sense_irq: key press/release irq number
+ * @key_stuck_irq: key stuck notification irq number
+ * @keycodes: array to hold the key codes
+ * @dev: parent device pointer
+ * @keystate: present key press/release state
+ * @stuckstate: present state when key stuck irq
+ * @ctrl_reg: control register value
  */
 struct pmic8xxx_kp {
        unsigned int num_rows;
index 70c1d086bdd2a782400112953a1a43378fe8920c..1ed939d9798cf222e0317d50db40f0784bee488c 100644 (file)
@@ -146,13 +146,12 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
 {
        struct samsung_keypad *keypad = dev_id;
        unsigned int row_state[SAMSUNG_MAX_COLS];
-       unsigned int val;
        bool key_down;
 
        pm_runtime_get_sync(&keypad->pdev->dev);
 
        do {
-               val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
+               readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
                /* Clear interrupt. */
                writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
 
index af3a6824f1a4d25b6b78ffe5d9b2f4dd2c89bc83..77e0743a3cf855152fa082dfe18c610a71c105a5 100644 (file)
@@ -50,7 +50,7 @@ struct twl4030_keypad {
        bool            autorepeat;
        unsigned int    n_rows;
        unsigned int    n_cols;
-       unsigned int    irq;
+       int             irq;
 
        struct device *dbg_dev;
        struct input_dev *input;
@@ -376,10 +376,8 @@ static int twl4030_kp_probe(struct platform_device *pdev)
        }
 
        kp->irq = platform_get_irq(pdev, 0);
-       if (!kp->irq) {
-               dev_err(&pdev->dev, "no keyboard irq assigned\n");
-               return -EINVAL;
-       }
+       if (kp->irq < 0)
+               return kp->irq;
 
        error = matrix_keypad_build_keymap(keymap_data, NULL,
                                           TWL4030_MAX_ROWS,
index ea3b8292acdd52ee5341b9ff0330468fe34fe839..a9b9013680d623710093ac19d249efef8525dcee 100644 (file)
@@ -19,7 +19,7 @@
 
 /**
  * struct ab8500_ponkey - ab8500 ponkey information
- * @input_dev: pointer to input device
+ * @idev: pointer to input device
  * @ab8500: ab8500 parent
  * @irq_dbf: irq number for falling transition
  * @irq_dbr: irq number for rising transition
index 79d7fa710a71453fed404b449e573f98ece6f2d3..cc51de7759a00b3ac75dd644b3474123ad9524c0 100644 (file)
 
 /**
  * struct drv260x_data -
- * @input_dev - Pointer to the input device
- * @client - Pointer to the I2C client
- * @regmap - Register map of the device
- * @work - Work item used to off load the enable/disable of the vibration
- * @enable_gpio - Pointer to the gpio used for enable/disabling
- * @regulator - Pointer to the regulator for the IC
- * @magnitude - Magnitude of the vibration event
- * @mode - The operating mode of the IC (LRA_NO_CAL, ERM or LRA)
- * @library - The vibration library to be used
- * @rated_voltage - The rated_voltage of the actuator
- * @overdriver_voltage - The over drive voltage of the actuator
+ * @input_dev: Pointer to the input device
+ * @client: Pointer to the I2C client
+ * @regmap: Register map of the device
+ * @work: Work item used to off load the enable/disable of the vibration
+ * @enable_gpio: Pointer to the gpio used for enable/disabling
+ * @regulator: Pointer to the regulator for the IC
+ * @magnitude: Magnitude of the vibration event
+ * @mode: The operating mode of the IC (LRA_NO_CAL, ERM or LRA)
+ * @library: The vibration library to be used
+ * @rated_voltage: The rated_voltage of the actuator
+ * @overdrive_voltage: The over drive voltage of the actuator
 **/
 struct drv260x_data {
        struct input_dev *input_dev;
@@ -234,12 +234,12 @@ static const struct reg_default drv260x_reg_defs[] = {
 #define DRV260X_DEF_RATED_VOLT         0x90
 #define DRV260X_DEF_OD_CLAMP_VOLT      0x90
 
-/**
+/*
  * Rated and Overdriver Voltages:
  * Calculated using the formula r = v * 255 / 5.6
  * where r is what will be written to the register
  * and v is the rated or overdriver voltage of the actuator
- **/
+ */
 static int drv260x_calculate_voltage(unsigned int voltage)
 {
        return (voltage * 255 / 5600);
index 918ad9c3fa81208d0911e83a98119e2faf1a9e2b..0e65ab180f499934b6b91875aec1bc44fc33ab4d 100644 (file)
 
 /**
  * struct drv2665_data -
- * @input_dev - Pointer to the input device
- * @client - Pointer to the I2C client
- * @regmap - Register map of the device
- * @work - Work item used to off load the enable/disable of the vibration
- * @regulator - Pointer to the regulator for the IC
+ * @input_dev: Pointer to the input device
+ * @client: Pointer to the I2C client
+ * @regmap: Register map of the device
+ * @work: Work item used to off load the enable/disable of the vibration
+ * @regulator: Pointer to the regulator for the IC
  */
 struct drv2665_data {
        struct input_dev *input_dev;
index bb9d5784df17db7c082f00ddf800b1fe8121d0be..dc19eb6a8713f37ea78e692d5a6166ccc3ea3bda 100644 (file)
 
 /**
  * struct drv2667_data -
- * @input_dev - Pointer to the input device
- * @client - Pointer to the I2C client
- * @regmap - Register map of the device
- * @work - Work item used to off load the enable/disable of the vibration
- * @regulator - Pointer to the regulator for the IC
- * @magnitude - Magnitude of the vibration event
+ * @input_dev: Pointer to the input device
+ * @client: Pointer to the I2C client
+ * @regmap: Register map of the device
+ * @work: Work item used to off load the enable/disable of the vibration
+ * @regulator: Pointer to the regulator for the IC
+ * @page: Page number
+ * @magnitude: Magnitude of the vibration event
+ * @frequency: Frequency of the vibration event
 **/
 struct drv2667_data {
        struct input_dev *input_dev;
index 08520b3a18b88d3e463e9ea7dd84c07f3567ed8a..cae1a3fae83a4db6a88c7ad64bec134874122787 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio.h>
@@ -23,6 +24,7 @@ struct soc_button_info {
        unsigned int event_code;
        bool autorepeat;
        bool wakeup;
+       bool active_low;
 };
 
 struct soc_device_data {
@@ -41,23 +43,66 @@ struct soc_button_data {
        struct platform_device *children[BUTTON_TYPES];
 };
 
+/*
+ * Some 2-in-1s which use the soc_button_array driver have this ugly issue in
+ * their DSDT where the _LID method modifies the irq-type settings of the GPIOs
+ * used for the power and home buttons. The intend of this AML code is to
+ * disable these buttons when the lid is closed.
+ * The AML does this by directly poking the GPIO controllers registers. This is
+ * problematic because when re-enabling the irq, which happens whenever _LID
+ * gets called with the lid open (e.g. on boot and on resume), it sets the
+ * irq-type to IRQ_TYPE_LEVEL_LOW. Where as the gpio-keys driver programs the
+ * type to, and expects it to be, IRQ_TYPE_EDGE_BOTH.
+ * To work around this we don't set gpio_keys_button.gpio on these 2-in-1s,
+ * instead we get the irq for the GPIO ourselves, configure it as
+ * IRQ_TYPE_LEVEL_LOW (to match how the _LID AML code configures it) and pass
+ * the irq in gpio_keys_button.irq. Below is a list of affected devices.
+ */
+static const struct dmi_system_id dmi_use_low_level_irq[] = {
+       {
+               /*
+                * Acer Switch 10 SW5-012. _LID method messes with home- and
+                * power-button GPIO IRQ settings. When (re-)enabling the irq
+                * it ors in its own flags without clearing the previous set
+                * ones, leading to an irq-type of IRQ_TYPE_LEVEL_LOW |
+                * IRQ_TYPE_LEVEL_HIGH causing a continuous interrupt storm.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+               },
+       },
+       {
+               /*
+                * Acer One S1003. _LID method messes with power-button GPIO
+                * IRQ settings, leading to a non working power-button.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "One S1003"),
+               },
+       },
+       {} /* Terminating entry */
+};
+
 /*
  * Get the Nth GPIO number from the ACPI object.
  */
-static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
+static int soc_button_lookup_gpio(struct device *dev, int acpi_index,
+                                 int *gpio_ret, int *irq_ret)
 {
        struct gpio_desc *desc;
-       int gpio;
 
        desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
 
-       gpio = desc_to_gpio(desc);
+       *gpio_ret = desc_to_gpio(desc);
+       *irq_ret = gpiod_to_irq(desc);
 
        gpiod_put(desc);
 
-       return gpio;
+       return 0;
 }
 
 static struct platform_device *
@@ -69,9 +114,8 @@ soc_button_device_create(struct platform_device *pdev,
        struct platform_device *pd;
        struct gpio_keys_button *gpio_keys;
        struct gpio_keys_platform_data *gpio_keys_pdata;
+       int error, gpio, irq;
        int n_buttons = 0;
-       int gpio;
-       int error;
 
        for (info = button_info; info->name; info++)
                if (info->autorepeat == autorepeat)
@@ -91,8 +135,8 @@ soc_button_device_create(struct platform_device *pdev,
                if (info->autorepeat != autorepeat)
                        continue;
 
-               gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
-               if (!gpio_is_valid(gpio)) {
+               error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
+               if (error || irq < 0) {
                        /*
                         * Skip GPIO if not present. Note we deliberately
                         * ignore -EPROBE_DEFER errors here. On some devices
@@ -107,10 +151,18 @@ soc_button_device_create(struct platform_device *pdev,
                        continue;
                }
 
+               /* See dmi_use_low_level_irq[] comment */
+               if (!autorepeat && dmi_check_system(dmi_use_low_level_irq)) {
+                       irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+                       gpio_keys[n_buttons].irq = irq;
+                       gpio_keys[n_buttons].gpio = -ENOENT;
+               } else {
+                       gpio_keys[n_buttons].gpio = gpio;
+               }
+
                gpio_keys[n_buttons].type = info->event_type;
                gpio_keys[n_buttons].code = info->event_code;
-               gpio_keys[n_buttons].gpio = gpio;
-               gpio_keys[n_buttons].active_low = 1;
+               gpio_keys[n_buttons].active_low = info->active_low;
                gpio_keys[n_buttons].desc = info->name;
                gpio_keys[n_buttons].wakeup = info->wakeup;
                /* These devices often use cheap buttons, use 50 ms debounce */
@@ -173,6 +225,7 @@ static int soc_button_parse_btn_desc(struct device *dev,
        }
 
        info->event_type = EV_KEY;
+       info->active_low = true;
        info->acpi_index =
                soc_button_get_acpi_object_int(&desc->package.elements[1]);
        upage = soc_button_get_acpi_object_int(&desc->package.elements[3]);
@@ -383,11 +436,11 @@ static int soc_button_probe(struct platform_device *pdev)
  * Platforms"
  */
 static const struct soc_button_info soc_button_PNP0C40[] = {
-       { "power", 0, EV_KEY, KEY_POWER, false, true },
-       { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
-       { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
-       { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
-       { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false },
+       { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+       { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
+       { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+       { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
+       { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false, true },
        { }
 };
 
@@ -395,6 +448,15 @@ static const struct soc_device_data soc_device_PNP0C40 = {
        .button_info = soc_button_PNP0C40,
 };
 
+static const struct soc_button_info soc_button_INT33D3[] = {
+       { "tablet_mode", 0, EV_SW, SW_TABLET_MODE, false, false, false },
+       { }
+};
+
+static const struct soc_device_data soc_device_INT33D3 = {
+       .button_info = soc_button_INT33D3,
+};
+
 /*
  * Special device check for Surface Book 2 and Surface Pro (2017).
  * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
@@ -444,9 +506,9 @@ static int soc_device_check_MSHW0040(struct device *dev)
  * Obtained from DSDT/testing.
  */
 static const struct soc_button_info soc_button_MSHW0040[] = {
-       { "power", 0, EV_KEY, KEY_POWER, false, true },
-       { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
-       { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
+       { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+       { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+       { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
        { }
 };
 
@@ -457,6 +519,8 @@ static const struct soc_device_data soc_device_MSHW0040 = {
 
 static const struct acpi_device_id soc_button_acpi_match[] = {
        { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
+       { "INT33D3", (unsigned long)&soc_device_INT33D3 },
+       { "ID9001", (unsigned long)&soc_device_INT33D3 },
        { "ACPI0011", 0 },
 
        /* Microsoft Surface Devices (5th and 6th generation) */
index c675f156948b5178ce9a7d3deb4f0ea4316d7b2a..dacf7c0e43f98b7340b3a9e789171fe9e441e53a 100644 (file)
@@ -119,7 +119,7 @@ static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len,
 /**
  * cyapa_i2c_write - Execute i2c block data write operation
  * @cyapa: Handle to this driver
- * @ret: Offset of the data to written in the register map
+ * @reg: Offset of the data to written in the register map
  * @len: number of bytes to write
  * @values: Data to be written
  *
index bb3a63d1268d109652330bf2a18f3135f9ce1316..5c37af994b5b55341b247f4b5aacccdd7b31f7d5 100644 (file)
@@ -385,7 +385,7 @@ ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
        return size;
 }
 
-/**
+/*
  * Return a negative errno code else zero on success.
  */
 ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
@@ -435,7 +435,7 @@ static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa)
        return pm_stage;
 }
 
-/**
+/*
  * This function is aimed to dump all not read data in Gen5 trackpad
  * before send any command, otherwise, the interrupt line will be blocked.
  */
index c599e21a8478439f218531cedf1d54d24703f542..65d21a050cea04ed48088d2029cb5c7d33fae00b 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/completion.h>
 #include <linux/of.h>
 #include <linux/property.h>
-#include <linux/input/elan-i2c-ids.h>
 #include <linux/regulator/consumer.h>
 #include <asm/unaligned.h>
 
@@ -1413,6 +1412,7 @@ static const struct i2c_device_id elan_id[] = {
 MODULE_DEVICE_TABLE(i2c, elan_id);
 
 #ifdef CONFIG_ACPI
+#include <linux/input/elan-i2c-ids.h>
 MODULE_DEVICE_TABLE(acpi, elan_acpi_id);
 #endif
 
index 90f8765f9efc89a9d5d386cb814d7566910607e7..47cd0e7f79bd16a965a4e72423b45f95d58a6265 100644 (file)
@@ -1827,7 +1827,7 @@ static int elantech_create_smbus(struct psmouse *psmouse,
                                  leave_breadcrumbs);
 }
 
-/**
+/*
  * elantech_setup_smbus - called once the PS/2 devices are enumerated
  * and decides to instantiate a SMBus InterTouch device.
  */
index 4b81b2d0fe067af3a97da105b529d573ace25c1a..82577095e175efd1969cdfbc40f9b2af8b6340f4 100644 (file)
@@ -179,12 +179,14 @@ static const char * const smbus_pnp_ids[] = {
        "LEN0093", /* T480 */
        "LEN0096", /* X280 */
        "LEN0097", /* X280 -> ALPS trackpoint */
-       "LEN0099", /* X1 Extreme 1st */
+       "LEN0099", /* X1 Extreme Gen 1 / P1 Gen 1 */
        "LEN009b", /* T580 */
+       "LEN0402", /* X1 Extreme Gen 2 / P1 Gen 2 */
        "LEN200f", /* T450s */
        "LEN2044", /* L470  */
        "LEN2054", /* E480 */
        "LEN2055", /* E580 */
+       "LEN2068", /* T14 Gen 1 */
        "SYN3052", /* HP EliteBook 840 G4 */
        "SYN3221", /* HP 15-ay000 */
        "SYN323d", /* HP Spectre X360 13-w013dx */
@@ -1752,7 +1754,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse,
                        .kernel_tracking = false,
                        .topbuttonpad = topbuttonpad,
                },
-               .f30_data = {
+               .gpio_data = {
                        .buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c),
                        .trackstick_buttons =
                                !!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10),
index a212ff706f7477e67d91cd3eb477295f50073779..16119f760d11f835bf26f87724ca4c10c5a5b24a 100644 (file)
@@ -100,6 +100,14 @@ config RMI4_F34
          device via the firmware loader interface. This is triggered using a
          sysfs attribute.
 
+config RMI4_F3A
+       bool "RMI4 Function 3A (GPIO)"
+       help
+         Say Y here if you want to add support for RMI4 function 3A.
+
+         Function 3A provides GPIO support for RMI4 devices. This includes
+         support for buttons on TouchPads and ClickPads.
+
 config RMI4_F54
        bool "RMI4 Function 54 (Analog diagnostics)"
        depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
index f17631656987c875ad6068f0acfbfbc434faaa44..02f14c84686189b45d6adbbc06e266f64efaa036 100644 (file)
@@ -10,6 +10,7 @@ rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
 rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
 rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
 rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
+rmi_core-$(CONFIG_RMI4_F3A) += rmi_f3a.o
 rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
 rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
 
index af706a583656efa4c4026b991f2705891a10572a..24f31a5c0e04af588a268187c7a875f4eb0f6f93 100644 (file)
@@ -286,7 +286,7 @@ void rmi_unregister_function(struct rmi_function *fn)
 /**
  * rmi_register_function_handler - register a handler for an RMI function
  * @handler: RMI handler that should be registered.
- * @module: pointer to module that implements the handler
+ * @owner: pointer to module that implements the handler
  * @mod_name: name of the module implementing the handler
  *
  * This function performs additional setup of RMI function handler and
@@ -365,6 +365,9 @@ static struct rmi_function_handler *fn_handlers[] = {
 #ifdef CONFIG_RMI4_F34
        &rmi_f34_handler,
 #endif
+#ifdef CONFIG_RMI4_F3A
+       &rmi_f3a_handler,
+#endif
 #ifdef CONFIG_RMI4_F54
        &rmi_f54_handler,
 #endif
index 65bfaa95e193a09b29e3881f68f6ebf81c6729ed..1c6c6086c0e5ab39169e9f36982aca7dddc8cc44 100644 (file)
@@ -135,6 +135,7 @@ extern struct rmi_function_handler rmi_f11_handler;
 extern struct rmi_function_handler rmi_f12_handler;
 extern struct rmi_function_handler rmi_f30_handler;
 extern struct rmi_function_handler rmi_f34_handler;
+extern struct rmi_function_handler rmi_f3a_handler;
 extern struct rmi_function_handler rmi_f54_handler;
 extern struct rmi_function_handler rmi_f55_handler;
 #endif
index e623c956376e32285742a4c7c430515806ac9729..d7603c50f864b329e1ef4dc9c75df885113e8cbb 100644 (file)
@@ -103,13 +103,15 @@ struct f01_basic_properties {
 #define RMI_F01_CTRL0_CONFIGURED_BIT   BIT(7)
 
 /**
- * @ctrl0 - see the bit definitions above.
- * @doze_interval - controls the interval between checks for finger presence
- * when the touch sensor is in doze mode, in units of 10ms.
- * @wakeup_threshold - controls the capacitance threshold at which the touch
- * sensor will decide to wake up from that low power state.
- * @doze_holdoff - controls how long the touch sensor waits after the last
- * finger lifts before entering the doze state, in units of 100ms.
+ * struct f01_device_control - controls basic sensor functions
+ *
+ * @ctrl0: see the bit definitions above.
+ * @doze_interval: controls the interval between checks for finger presence
+ *     when the touch sensor is in doze mode, in units of 10ms.
+ * @wakeup_threshold: controls the capacitance threshold at which the touch
+ *     sensor will decide to wake up from that low power state.
+ * @doze_holdoff: controls how long the touch sensor waits after the last
+ *     finger lifts before entering the doze state, in units of 100ms.
  */
 struct f01_device_control {
        u8 ctrl0;
index ffa39ab153f2a3ab870ecc65158af64caa5189c7..49ca9168685a028c51d351aa0c7dc79a5267b928 100644 (file)
 #define DEFAULT_MIN_ABS_MT_TRACKING_ID 1
 #define DEFAULT_MAX_ABS_MT_TRACKING_ID 10
 
-/** A note about RMI4 F11 register structure.
+/*
+ * A note about RMI4 F11 register structure.
  *
- * The properties for
- * a given sensor are described by its query registers.  The number of query
- * registers and the layout of their contents are described by the F11 device
- * queries as well as the sensor query information.
+ * The properties for a given sensor are described by its query registers.  The
+ * number of query registers and the layout of their contents are described by
+ * the F11 device queries as well as the sensor query information.
  *
  * Similarly, each sensor has control registers that govern its behavior.  The
  * size and layout of the control registers for a given sensor can be determined
@@ -62,8 +62,8 @@
 /* maximum ABS_MT_POSITION displacement (in mm) */
 #define DMAX 10
 
-/**
- * @rezero - writing this to the F11 command register will cause the sensor to
+/*
+ * Writing this to the F11 command register will cause the sensor to
  * calibrate to the current capacitive state.
  */
 #define RMI_F11_REZERO  0x01
 #define F11_UNIFORM_CLICKPAD 0x02
 
 /**
+ * struct f11_2d_sensor_queries - describes sensor capabilities
+ *
  * Query registers 1 through 4 are always present.
  *
- * @nr_fingers - describes the maximum number of fingers the 2-D sensor
- * supports.
- * @has_rel - the sensor supports relative motion reporting.
- * @has_abs - the sensor supports absolute poition reporting.
- * @has_gestures - the sensor supports gesture reporting.
- * @has_sensitivity_adjust - the sensor supports a global sensitivity
- * adjustment.
- * @configurable - the sensor supports various configuration options.
- * @num_of_x_electrodes -  the maximum number of electrodes the 2-D sensor
- * supports on the X axis.
- * @num_of_y_electrodes -  the maximum number of electrodes the 2-D sensor
- * supports on the Y axis.
- * @max_electrodes - the total number of X and Y electrodes that may be
- * configured.
+ * @nr_fingers: describes the maximum number of fingers the 2-D sensor
+ *     supports.
+ * @has_rel: the sensor supports relative motion reporting.
+ * @has_abs: the sensor supports absolute poition reporting.
+ * @has_gestures: the sensor supports gesture reporting.
+ * @has_sensitivity_adjust: the sensor supports a global sensitivity
+ *     adjustment.
+ * @configurable: the sensor supports various configuration options.
+ * @nr_x_electrodes:  the maximum number of electrodes the 2-D sensor
+ *     supports on the X axis.
+ * @nr_y_electrodes:  the maximum number of electrodes the 2-D sensor
+ *     supports on the Y axis.
+ * @max_electrodes: the total number of X and Y electrodes that may be
+ *     configured.
  *
  * Query 5 is present if the has_abs bit is set.
  *
- * @abs_data_size - describes the format of data reported by the absolute
- * data source.  Only one format (the kind used here) is supported at this
- * time.
- * @has_anchored_finger - then the sensor supports the high-precision second
- * finger tracking provided by the manual tracking and motion sensitivity
- * options.
- * @has_adjust_hyst - the difference between the finger release threshold and
- * the touch threshold.
- * @has_dribble - the sensor supports the generation of dribble interrupts,
- * which may be enabled or disabled with the dribble control bit.
- * @has_bending_correction - Bending related data registers 28 and 36, and
- * control register 52..57 are present.
- * @has_large_object_suppression - control register 58 and data register 28
- * exist.
- * @has_jitter_filter - query 13 and control 73..76 exist.
+ * @abs_data_size: describes the format of data reported by the absolute
+ *     data source.  Only one format (the kind used here) is supported at this
+ *     time.
+ * @has_anchored_finger: then the sensor supports the high-precision second
+ *     finger tracking provided by the manual tracking and motion sensitivity
+ *     options.
+ * @has_adj_hyst: the difference between the finger release threshold and
+ *     the touch threshold.
+ * @has_dribble: the sensor supports the generation of dribble interrupts,
+ *     which may be enabled or disabled with the dribble control bit.
+ * @has_bending_correction: Bending related data registers 28 and 36, and
+ *     control register 52..57 are present.
+ * @has_large_object_suppression: control register 58 and data register 28
+ *     exist.
+ * @has_jitter_filter: query 13 and control 73..76 exist.
+ *
+ * Query 6 is present if the has_rel it is set.
+ *
+ * @f11_2d_query6: this register is reserved.
  *
  * Gesture information queries 7 and 8 are present if has_gestures bit is set.
  *
- * @has_single_tap - a basic single-tap gesture is supported.
- * @has_tap_n_hold - tap-and-hold gesture is supported.
- * @has_double_tap - double-tap gesture is supported.
- * @has_early_tap - early tap is supported and reported as soon as the finger
- * lifts for any tap event that could be interpreted as either a single tap
- * or as the first tap of a double-tap or tap-and-hold gesture.
- * @has_flick - flick detection is supported.
- * @has_press - press gesture reporting is supported.
- * @has_pinch - pinch gesture detection is supported.
- * @has_palm_det - the 2-D sensor notifies the host whenever a large conductive
- * object such as a palm or a cheek touches the 2-D sensor.
- * @has_rotate - rotation gesture detection is supported.
- * @has_touch_shapes - TouchShapes are supported.  A TouchShape is a fixed
- * rectangular area on the sensor that behaves like a capacitive button.
- * @has_scroll_zones - scrolling areas near the sensor edges are supported.
- * @has_individual_scroll_zones - if 1, then 4 scroll zones are supported;
- * if 0, then only two are supported.
- * @has_mf_scroll - the multifinger_scrolling bit will be set when
- * more than one finger is involved in a scrolling action.
+ * @has_single_tap: a basic single-tap gesture is supported.
+ * @has_tap_n_hold: tap-and-hold gesture is supported.
+ * @has_double_tap: double-tap gesture is supported.
+ * @has_early_tap: early tap is supported and reported as soon as the finger
+ *     lifts for any tap event that could be interpreted as either a single
+ *     tap or as the first tap of a double-tap or tap-and-hold gesture.
+ * @has_flick: flick detection is supported.
+ * @has_press: press gesture reporting is supported.
+ * @has_pinch: pinch gesture detection is supported.
+ * @has_chiral: chiral (circular) scrolling  gesture detection is supported.
+ * @has_palm_det: the 2-D sensor notifies the host whenever a large conductive
+ *     object such as a palm or a cheek touches the 2-D sensor.
+ * @has_rotate: rotation gesture detection is supported.
+ * @has_touch_shapes: TouchShapes are supported.  A TouchShape is a fixed
+ *     rectangular area on the sensor that behaves like a capacitive button.
+ * @has_scroll_zones: scrolling areas near the sensor edges are supported.
+ * @has_individual_scroll_zones: if 1, then 4 scroll zones are supported;
+ *     if 0, then only two are supported.
+ * @has_mf_scroll: the multifinger_scrolling bit will be set when
+ *     more than one finger is involved in a scrolling action.
+ * @has_mf_edge_motion: indicates whether multi-finger edge motion gesture
+ *     is supported.
+ * @has_mf_scroll_inertia: indicates whether multi-finger scroll inertia
+ *     feature is supported.
  *
  * Convenience for checking bytes in the gesture info registers.  This is done
  * often enough that we put it here to declutter the conditionals
  *
- * @query7_nonzero - true if none of the query 7 bits are set
- * @query8_nonzero - true if none of the query 8 bits are set
+ * @query7_nonzero: true if none of the query 7 bits are set
+ * @query8_nonzero: true if none of the query 8 bits are set
  *
  * Query 9 is present if the has_query9 is set.
  *
- * @has_pen - detection of a stylus is supported and registers F11_2D_Ctrl20
- * and F11_2D_Ctrl21 exist.
- * @has_proximity - detection of fingers near the sensor is supported and
- * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist.
- * @has_palm_det_sensitivity -  the sensor supports the palm detect sensitivity
- * feature and register F11_2D_Ctrl27 exists.
- * @has_two_pen_thresholds - is has_pen is also set, then F11_2D_Ctrl35 exists.
- * @has_contact_geometry - the sensor supports the use of contact geometry to
- * map absolute X and Y target positions and registers F11_2D_Data18
- * through F11_2D_Data27 exist.
+ * @has_pen: detection of a stylus is supported and registers F11_2D_Ctrl20
+ *     and F11_2D_Ctrl21 exist.
+ * @has_proximity: detection of fingers near the sensor is supported and
+ *     registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist.
+ * @has_palm_det_sensitivity:  the sensor supports the palm detect sensitivity
+ *     feature and register F11_2D_Ctrl27 exists.
+ * @has_suppress_on_palm_detect: the device supports the large object detect
+ *     suppression feature and register F11_2D_Ctrl27 exists.
+ * @has_two_pen_thresholds: if has_pen is also set, then F11_2D_Ctrl35 exists.
+ * @has_contact_geometry: the sensor supports the use of contact geometry to
+ *     map absolute X and Y target positions and registers F11_2D_Data18
+ *     through F11_2D_Data27 exist.
+ * @has_pen_hover_discrimination: if has_pen is also set, then registers
+ *     F11_2D_Data29 through F11_2D_Data31, F11_2D_Ctrl68.*, F11_2D_Ctrl69
+ *     and F11_2D_Ctrl72 exist.
+ * @has_pen_filters: if has_pen is also set, then registers F11_2D_Ctrl70 and
+ *     F11_2D_Ctrl71 exist.
  *
  * Touch shape info (query 10) is present if has_touch_shapes is set.
  *
- * @nr_touch_shapes - the total number of touch shapes supported.
+ * @nr_touch_shapes: the total number of touch shapes supported.
  *
  * Query 11 is present if the has_query11 bit is set in query 0.
  *
- * @has_z_tuning - if set, the sensor supports Z tuning and registers
- * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist.
- * @has_algorithm_selection - controls choice of noise suppression algorithm
- * @has_w_tuning - the sensor supports Wx and Wy scaling and registers
- * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist.
- * @has_pitch_info - the X and Y pitches of the sensor electrodes can be
- * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist.
- * @has_finger_size -  the default finger width settings for the
- * sensor can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44
- * exist.
- * @has_segmentation_aggressiveness - the sensor’s ability to distinguish
- * multiple objects close together can be configured and register F11_2D_Ctrl45
- * exists.
- * @has_XY_clip -  the inactive outside borders of the sensor can be
- * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist.
- * @has_drumming_filter - the sensor can be configured to distinguish
- * between a fast flick and a quick drumming movement and registers
- * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist.
+ * @has_z_tuning: if set, the sensor supports Z tuning and registers
+ *     F11_2D_Ctrl29 through F11_2D_Ctrl33 exist.
+ * @has_algorithm_selection: controls choice of noise suppression algorithm
+ * @has_w_tuning: the sensor supports Wx and Wy scaling and registers
+ *     F11_2D_Ctrl36 through F11_2D_Ctrl39 exist.
+ * @has_pitch_info: the X and Y pitches of the sensor electrodes can be
+ *     configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist.
+ * @has_finger_size: the default finger width settings for the sensor
+ *     can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44
+ *     exist.
+ * @has_segmentation_aggressiveness: the sensor’s ability to distinguish
+ *     multiple objects close together can be configured and register
+ *     F11_2D_Ctrl45 exists.
+ * @has_XY_clip: the inactive outside borders of the sensor can be
+ *     configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist.
+ * @has_drumming_filter: the sensor can be configured to distinguish
+ *     between a fast flick and a quick drumming movement and registers
+ *     F11_2D_Ctrl50 and F11_2D_Ctrl51 exist.
  *
  * Query 12 is present if hasQuery12 bit is set.
  *
- * @has_gapless_finger - control registers relating to gapless finger are
- * present.
- * @has_gapless_finger_tuning - additional control and data registers relating
- * to gapless finger are present.
- * @has_8bit_w - larger W value reporting is supported.
- * @has_adjustable_mapping - TBD
- * @has_info2 - the general info query14 is present
- * @has_physical_props - additional queries describing the physical properties
- * of the sensor are present.
- * @has_finger_limit - indicates that F11 Ctrl 80 exists.
- * @has_linear_coeff - indicates that F11 Ctrl 81 exists.
+ * @has_gapless_finger: control registers relating to gapless finger are
+ *     present.
+ * @has_gapless_finger_tuning: additional control and data registers relating
+ *     to gapless finger are present.
+ * @has_8bit_w: larger W value reporting is supported.
+ * @has_adjustable_mapping: TBD
+ * @has_info2: the general info query14 is present
+ * @has_physical_props: additional queries describing the physical properties
+ *     of the sensor are present.
+ * @has_finger_limit: indicates that F11 Ctrl 80 exists.
+ * @has_linear_coeff_2: indicates that F11 Ctrl 81 exists.
  *
  * Query 13 is present if Query 5's has_jitter_filter bit is set.
- * @jitter_window_size - used by Design Studio 4.
- * @jitter_filter_type - used by Design Studio 4.
+ *
+ * @jitter_window_size: used by Design Studio 4.
+ * @jitter_filter_type: used by Design Studio 4.
  *
  * Query 14 is present if query 12's has_general_info2 flag is set.
  *
- * @light_control - Indicates what light/led control features are present, if
- * any.
- * @is_clear - if set, this is a clear sensor (indicating direct pointing
- * application), otherwise it's opaque (indicating indirect pointing).
- * @clickpad_props - specifies if this is a clickpad, and if so what sort of
- * mechanism it uses
- * @mouse_buttons - specifies the number of mouse buttons present (if any).
- * @has_advanced_gestures - advanced driver gestures are supported.
+ * @light_control: Indicates what light/led control features are present,
+ *     if any.
+ * @is_clear: if set, this is a clear sensor (indicating direct pointing
+ *     application), otherwise it's opaque (indicating indirect pointing).
+ * @clickpad_props: specifies if this is a clickpad, and if so what sort of
+ *     mechanism it uses
+ * @mouse_buttons: specifies the number of mouse buttons present (if any).
+ * @has_advanced_gestures: advanced driver gestures are supported.
+ *
+ * @x_sensor_size_mm: size of the sensor in millimeters on the X axis.
+ * @y_sensor_size_mm: size of the sensor in millimeters on the Y axis.
  */
 struct f11_2d_sensor_queries {
        /* query1 */
index a90dad1d9ac785b5e3573cd349c95917869ef45d..35045f161dc2f9ade1bc822a9c4045873a74cafb 100644 (file)
@@ -168,17 +168,17 @@ static int rmi_f30_config(struct rmi_function *fn)
                                rmi_get_platform_data(fn->rmi_dev);
        int error;
 
-       /* can happen if f30_data.disable is set */
+       /* can happen if gpio_data.disable is set */
        if (!f30)
                return 0;
 
-       if (pdata->f30_data.trackstick_buttons) {
+       if (pdata->gpio_data.trackstick_buttons) {
                /* Try [re-]establish link to F03. */
                f30->f03 = rmi_find_function(fn->rmi_dev, 0x03);
                f30->trackstick_buttons = f30->f03 != NULL;
        }
 
-       if (pdata->f30_data.disable) {
+       if (pdata->gpio_data.disable) {
                drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
        } else {
                /* Write Control Register values back to device */
@@ -245,10 +245,10 @@ static int rmi_f30_map_gpios(struct rmi_function *fn,
                if (!rmi_f30_is_valid_button(i, f30->ctrl))
                        continue;
 
-               if (pdata->f30_data.trackstick_buttons &&
+               if (pdata->gpio_data.trackstick_buttons &&
                    i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) {
                        f30->gpioled_key_map[i] = trackstick_button++;
-               } else if (!pdata->f30_data.buttonpad || !button_mapped) {
+               } else if (!pdata->gpio_data.buttonpad || !button_mapped) {
                        f30->gpioled_key_map[i] = button;
                        input_set_capability(input, EV_KEY, button++);
                        button_mapped = true;
@@ -264,7 +264,7 @@ static int rmi_f30_map_gpios(struct rmi_function *fn,
         * but I am not sure, so use only the pdata info and the number of
         * mapped buttons.
         */
-       if (pdata->f30_data.buttonpad || (button - BTN_LEFT == 1))
+       if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1))
                __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 
        return 0;
@@ -372,7 +372,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
        struct f30_data *f30;
        int error;
 
-       if (pdata->f30_data.disable)
+       if (pdata->gpio_data.disable)
                return 0;
 
        if (!drv_data->input) {
index 74f7c6f214ff5414af7c738e29e87acc2539fafa..8d7ec9d89b185be069e81d9d90ad472fb8547966 100644 (file)
@@ -1364,9 +1364,14 @@ int rmi_f34v7_probe(struct f34_data *f34)
                f34->bl_version = 6;
        } else if (f34->bootloader_id[1] == 7) {
                f34->bl_version = 7;
+       } else if (f34->bootloader_id[1] == 8) {
+               f34->bl_version = 8;
        } else {
-               dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n",
-                               __func__);
+               dev_err(&f34->fn->dev,
+                       "%s: Unrecognized bootloader version: %d (%c) %d (%c)\n",
+                       __func__,
+                       f34->bootloader_id[0], f34->bootloader_id[0],
+                       f34->bootloader_id[1], f34->bootloader_id[1]);
                return -EINVAL;
        }
 
diff --git a/drivers/input/rmi4/rmi_f3a.c b/drivers/input/rmi4/rmi_f3a.c
new file mode 100644 (file)
index 0000000..0e8baed
--- /dev/null
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2020 Synaptics Incorporated
+ */
+
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define RMI_F3A_MAX_GPIO_COUNT         128
+#define RMI_F3A_MAX_REG_SIZE           DIV_ROUND_UP(RMI_F3A_MAX_GPIO_COUNT, 8)
+
+/* Defs for Query 0 */
+#define RMI_F3A_GPIO_COUNT             0x7F
+
+#define RMI_F3A_DATA_REGS_MAX_SIZE     RMI_F3A_MAX_REG_SIZE
+
+#define TRACKSTICK_RANGE_START         3
+#define TRACKSTICK_RANGE_END           6
+
+struct f3a_data {
+       /* Query Data */
+       u8 gpio_count;
+
+       u8 register_count;
+
+       u8 data_regs[RMI_F3A_DATA_REGS_MAX_SIZE];
+       u16 *gpio_key_map;
+
+       struct input_dev *input;
+
+       struct rmi_function *f03;
+       bool trackstick_buttons;
+};
+
+static void rmi_f3a_report_button(struct rmi_function *fn,
+                                 struct f3a_data *f3a, unsigned int button)
+{
+       u16 key_code = f3a->gpio_key_map[button];
+       bool key_down = !(f3a->data_regs[0] & BIT(button));
+
+       if (f3a->trackstick_buttons &&
+               button >= TRACKSTICK_RANGE_START &&
+               button <= TRACKSTICK_RANGE_END) {
+               rmi_f03_overwrite_button(f3a->f03, key_code, key_down);
+       } else {
+               rmi_dbg(RMI_DEBUG_FN, &fn->dev,
+                       "%s: call input report key (0x%04x) value (0x%02x)",
+                       __func__, key_code, key_down);
+               input_report_key(f3a->input, key_code, key_down);
+       }
+}
+
+static irqreturn_t rmi_f3a_attention(int irq, void *ctx)
+{
+       struct rmi_function *fn = ctx;
+       struct f3a_data *f3a = dev_get_drvdata(&fn->dev);
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
+       int error;
+       int i;
+
+       if (drvdata->attn_data.data) {
+               if (drvdata->attn_data.size < f3a->register_count) {
+                       dev_warn(&fn->dev,
+                                "F3A interrupted, but data is missing\n");
+                       return IRQ_HANDLED;
+               }
+               memcpy(f3a->data_regs, drvdata->attn_data.data,
+                       f3a->register_count);
+               drvdata->attn_data.data += f3a->register_count;
+               drvdata->attn_data.size -= f3a->register_count;
+       } else {
+               error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
+                                       f3a->data_regs, f3a->register_count);
+               if (error) {
+                       dev_err(&fn->dev,
+                               "%s: Failed to read F3a data registers: %d\n",
+                               __func__, error);
+                       return IRQ_RETVAL(error);
+               }
+       }
+
+       for (i = 0; i < f3a->gpio_count; i++)
+               if (f3a->gpio_key_map[i] != KEY_RESERVED)
+                       rmi_f3a_report_button(fn, f3a, i);
+       if (f3a->trackstick_buttons)
+               rmi_f03_commit_buttons(f3a->f03);
+
+       return IRQ_HANDLED;
+}
+
+static int rmi_f3a_config(struct rmi_function *fn)
+{
+       struct f3a_data *f3a = dev_get_drvdata(&fn->dev);
+       struct rmi_driver *drv = fn->rmi_dev->driver;
+       const struct rmi_device_platform_data *pdata =
+                       rmi_get_platform_data(fn->rmi_dev);
+
+       if (!f3a)
+               return 0;
+
+       if (pdata->gpio_data.trackstick_buttons) {
+               /* Try [re-]establish link to F03. */
+               f3a->f03 = rmi_find_function(fn->rmi_dev, 0x03);
+               f3a->trackstick_buttons = f3a->f03 != NULL;
+       }
+
+       drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+       return 0;
+}
+
+static bool rmi_f3a_is_valid_button(int button, struct f3a_data *f3a,
+                                       u8 *query1_regs, u8 *ctrl1_regs)
+{
+       /* gpio exist && direction input */
+       return (query1_regs[0] & BIT(button)) && !(ctrl1_regs[0] & BIT(button));
+}
+
+static int rmi_f3a_map_gpios(struct rmi_function *fn, struct f3a_data *f3a,
+                               u8 *query1_regs, u8 *ctrl1_regs)
+{
+       const struct rmi_device_platform_data *pdata =
+                       rmi_get_platform_data(fn->rmi_dev);
+       struct input_dev *input = f3a->input;
+       unsigned int button = BTN_LEFT;
+       unsigned int trackstick_button = BTN_LEFT;
+       bool button_mapped = false;
+       int i;
+       int button_count = min_t(u8, f3a->gpio_count, TRACKSTICK_RANGE_END);
+
+       f3a->gpio_key_map = devm_kcalloc(&fn->dev,
+                                               button_count,
+                                               sizeof(f3a->gpio_key_map[0]),
+                                               GFP_KERNEL);
+       if (!f3a->gpio_key_map) {
+               dev_err(&fn->dev, "Failed to allocate gpio map memory.\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < button_count; i++) {
+               if (!rmi_f3a_is_valid_button(i, f3a, query1_regs, ctrl1_regs))
+                       continue;
+
+               if (pdata->gpio_data.trackstick_buttons &&
+                       i >= TRACKSTICK_RANGE_START &&
+                       i < TRACKSTICK_RANGE_END) {
+                       f3a->gpio_key_map[i] = trackstick_button++;
+               } else if (!pdata->gpio_data.buttonpad || !button_mapped) {
+                       f3a->gpio_key_map[i] = button;
+                       input_set_capability(input, EV_KEY, button++);
+                       button_mapped = true;
+               }
+       }
+       input->keycode = f3a->gpio_key_map;
+       input->keycodesize = sizeof(f3a->gpio_key_map[0]);
+       input->keycodemax = f3a->gpio_count;
+
+       if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1))
+               __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+
+       return 0;
+}
+
+static int rmi_f3a_initialize(struct rmi_function *fn, struct f3a_data *f3a)
+{
+       u8 query1[RMI_F3A_MAX_REG_SIZE];
+       u8 ctrl1[RMI_F3A_MAX_REG_SIZE];
+       u8 buf;
+       int error;
+
+       error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &buf);
+       if (error < 0) {
+               dev_err(&fn->dev, "Failed to read general info register: %d\n",
+                       error);
+               return -ENODEV;
+       }
+
+       f3a->gpio_count = buf & RMI_F3A_GPIO_COUNT;
+       f3a->register_count = DIV_ROUND_UP(f3a->gpio_count, 8);
+
+       /* Query1 -> gpio exist */
+       error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
+                               query1, f3a->register_count);
+       if (error) {
+               dev_err(&fn->dev, "Failed to read query1 register\n");
+               return error;
+       }
+
+       /* Ctrl1 -> gpio direction */
+       error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr + 1,
+                               ctrl1, f3a->register_count);
+       if (error) {
+               dev_err(&fn->dev, "Failed to read control1 register\n");
+               return error;
+       }
+
+       error = rmi_f3a_map_gpios(fn, f3a, query1, ctrl1);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int rmi_f3a_probe(struct rmi_function *fn)
+{
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+       struct f3a_data *f3a;
+       int error;
+
+       if (!drv_data->input) {
+               dev_info(&fn->dev, "F3A: no input device found, ignoring\n");
+               return -ENXIO;
+       }
+
+       f3a = devm_kzalloc(&fn->dev, sizeof(*f3a), GFP_KERNEL);
+       if (!f3a)
+               return -ENOMEM;
+
+       f3a->input = drv_data->input;
+
+       error = rmi_f3a_initialize(fn, f3a);
+       if (error)
+               return error;
+
+       dev_set_drvdata(&fn->dev, f3a);
+       return 0;
+}
+
+struct rmi_function_handler rmi_f3a_handler = {
+       .driver = {
+               .name = "rmi4_f3a",
+       },
+       .func = 0x3a,
+       .probe = rmi_f3a_probe,
+       .config = rmi_f3a_config,
+       .attention = rmi_f3a_attention,
+};
index 6b23e679606eeb9ba3412ba75abd47a90465b1ea..93b328c796c643006b3589673dd79813b3d6067d 100644 (file)
@@ -42,6 +42,8 @@
 /**
  * enum rmi_f54_report_type - RMI4 F54 report types
  *
+ * @F54_REPORT_NONE:   No Image Report.
+ *
  * @F54_8BIT_IMAGE:    Normalized 8-Bit Image Report. The capacitance variance
  *                     from baseline for each pixel.
  *
  *                     Report. Set Low reference to its minimum value and high
  *                     references to its maximum value, then report the raw
  *                     capacitance for each pixel.
+ *
+ * @F54_MAX_REPORT_TYPE:
+ *                     Maximum number of Report Types.  Used for sanity
+ *                     checking.
  */
 enum rmi_f54_report_type {
        F54_REPORT_NONE = 0,
index a95c2c9bcab4ca8ebe142f2e2a0b373463af9504..50305fcfbef59e4d4b054b89c7c9f32b837c953e 100644 (file)
  * struct rmi_i2c_xport - stores information for i2c communication
  *
  * @xport: The transport interface structure
+ * @client: The I2C client device structure
  *
  * @page_mutex: Locks current page to avoid changing pages in unexpected ways.
  * @page: Keeps track of the current virtual page
  *
  * @tx_buf: Buffer used for transmitting data to the sensor over i2c.
  * @tx_buf_size: Size of the buffer
+ *
+ * @supplies: Array of voltage regulators
+ * @startup_delay: Milliseconds to pause after powering up the regulators
  */
 struct rmi_i2c_xport {
        struct rmi_transport_dev xport;
index a681a2c04e399f07566df355558605316e5e3ec2..f15ed3dcdb9b2074f29a300497008377cf435d78 100644 (file)
@@ -211,7 +211,6 @@ static int sun4i_ps2_probe(struct platform_device *pdev)
        struct sun4i_ps2data *drvdata;
        struct serio *serio;
        struct device *dev = &pdev->dev;
-       unsigned int irq;
        int error;
 
        drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL);
@@ -264,14 +263,12 @@ static int sun4i_ps2_probe(struct platform_device *pdev)
        writel(0, drvdata->reg_base + PS2_REG_GCTL);
 
        /* Get IRQ for the device */
-       irq = platform_get_irq(pdev, 0);
-       if (!irq) {
-               dev_err(dev, "no IRQ found\n");
-               error = -ENXIO;
+       drvdata->irq = platform_get_irq(pdev, 0);
+       if (drvdata->irq < 0) {
+               error = drvdata->irq;
                goto err_disable_clk;
        }
 
-       drvdata->irq = irq;
        drvdata->serio = serio;
        drvdata->dev = dev;
 
index 35c867b2d9a77b1012c8c06cfc8cc68302f4297a..f012fe746df01ebd3cdb430437638c882b64c5c0 100644 (file)
@@ -1322,4 +1322,16 @@ config TOUCHSCREEN_IQS5XX
          To compile this driver as a module, choose M here: the
          module will be called iqs5xx.
 
+config TOUCHSCREEN_ZINITIX
+       tristate "Zinitix touchscreen support"
+       depends on I2C
+       help
+         Say Y here if you have a touchscreen using Zinitix bt541,
+         or something similar enough.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called zinitix.
+
 endif
index 30d1e1b42492924496602252b451accb867a81bd..6233541e917329dc854a70b235583372e079bab7 100644 (file)
@@ -111,3 +111,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50)      += colibri-vf50-ts.o
 obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
 obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW)       += raspberrypi-ts.o
 obj-$(CONFIG_TOUCHSCREEN_IQS5XX)       += iqs5xx.o
+obj-$(CONFIG_TOUCHSCREEN_ZINITIX)      += zinitix.o
index 8fd7fc39c4fd7bf48f13197806b579922c9406e6..de058644ef8ad6a75512102fccac4d7ffed1aec8 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/spi/ads7846.h>
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
-#include <asm/irq.h>
+#include <asm/unaligned.h>
 
 /*
  * This code has been heavily tested on a Nokia 770, and lightly
 /* this driver doesn't aim at the peak continuous sample rate */
 #define        SAMPLE_BITS     (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
 
-struct ts_event {
+struct ads7846_buf {
+       u8 cmd;
        /*
-        * For portability, we can't read 12 bit values using SPI (which
-        * would make the controller deliver them as native byte order u16
-        * with msbs zeroed).  Instead, we read them as two 8-bit values,
-        * *** WHICH NEED BYTESWAPPING *** and range adjustment.
+        * This union is a temporary hack. The driver does an in-place
+        * endianness conversion. This will be cleaned up in the next
+        * patch.
         */
-       u16     x;
-       u16     y;
-       u16     z1, z2;
-       bool    ignore;
-       u8      x_buf[3];
-       u8      y_buf[3];
+       union {
+               __be16 data_be16;
+               u16 data;
+       };
+} __packed;
+
+
+struct ts_event {
+       bool ignore;
+       struct ads7846_buf x;
+       struct ads7846_buf y;
+       struct ads7846_buf z1;
+       struct ads7846_buf z2;
 };
 
 /*
@@ -83,11 +90,12 @@ struct ts_event {
  * systems where main memory is not DMA-coherent (most non-x86 boards).
  */
 struct ads7846_packet {
-       u8                      read_x, read_y, read_z1, read_z2, pwrdown;
-       u16                     dummy;          /* for the pwrdown read */
-       struct ts_event         tc;
-       /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
-       u8                      read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
+       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;
+       struct ads7846_buf pwrdown_cmd;
 };
 
 struct ads7846 {
@@ -199,6 +207,26 @@ struct ads7846 {
 #define        REF_ON  (READ_12BIT_DFR(x, 1, 1))
 #define        REF_OFF (READ_12BIT_DFR(y, 0, 0))
 
+static int get_pendown_state(struct ads7846 *ts)
+{
+       if (ts->get_pendown_state)
+               return ts->get_pendown_state();
+
+       return !gpio_get_value(ts->gpio_pendown);
+}
+
+static void ads7846_report_pen_up(struct ads7846 *ts)
+{
+       struct input_dev *input = ts->input;
+
+       input_report_key(input, BTN_TOUCH, 0);
+       input_report_abs(input, ABS_PRESSURE, 0);
+       input_sync(input);
+
+       ts->pendown = false;
+       dev_vdbg(&ts->spi->dev, "UP\n");
+}
+
 /* Must be called with ts->lock held */
 static void ads7846_stop(struct ads7846 *ts)
 {
@@ -215,6 +243,10 @@ static void ads7846_stop(struct ads7846 *ts)
 static void ads7846_restart(struct ads7846 *ts)
 {
        if (!ts->disabled && !ts->suspended) {
+               /* Check if pen was released since last stop */
+               if (ts->pendown && !get_pendown_state(ts))
+                       ads7846_report_pen_up(ts);
+
                /* Tell IRQ thread that it may poll the device. */
                ts->stopped = false;
                mb();
@@ -411,7 +443,7 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
 
        if (status == 0) {
                /* BE12 value, then padding */
-               status = be16_to_cpu(*((u16 *)&req->sample[1]));
+               status = get_unaligned_be16(&req->sample[1]);
                status = status >> 3;
                status &= 0x0fff;
        }
@@ -481,7 +513,7 @@ SHOW(in1_input, vbatt, vbatt_adjust)
 static umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr,
                                  int index)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct ads7846 *ts = dev_get_drvdata(dev);
 
        if (ts->model == 7843 && index < 2)     /* in0, in1 */
@@ -606,14 +638,6 @@ static const struct attribute_group ads784x_attr_group = {
 
 /*--------------------------------------------------------------------------*/
 
-static int get_pendown_state(struct ads7846 *ts)
-{
-       if (ts->get_pendown_state)
-               return ts->get_pendown_state();
-
-       return !gpio_get_value(ts->gpio_pendown);
-}
-
 static void null_wait_for_sync(void)
 {
 }
@@ -670,16 +694,9 @@ static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
        int value;
        struct spi_transfer *t =
                list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+       struct ads7846_buf *buf = t->rx_buf;
 
-       if (ts->model == 7845) {
-               value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1]));
-       } else {
-               /*
-                * adjust:  on-wire is a must-ignore bit, a BE12 value, then
-                * padding; built from two 8 bit values written msb-first.
-                */
-               value = be16_to_cpup((__be16 *)t->rx_buf);
-       }
+       value = be16_to_cpup(&buf->data_be16);
 
        /* enforce ADC output is 12 bits width */
        return (value >> 3) & 0xfff;
@@ -689,8 +706,9 @@ static void ads7846_update_value(struct spi_message *m, int val)
 {
        struct spi_transfer *t =
                list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+       struct ads7846_buf *buf = t->rx_buf;
 
-       *(u16 *)t->rx_buf = val;
+       buf->data = val;
 }
 
 static void ads7846_read_state(struct ads7846 *ts)
@@ -758,16 +776,14 @@ static void ads7846_report_state(struct ads7846 *ts)
         * from on-the-wire format as part of debouncing to get stable
         * readings.
         */
+       x = packet->tc.x.data;
+       y = packet->tc.y.data;
        if (ts->model == 7845) {
-               x = *(u16 *)packet->tc.x_buf;
-               y = *(u16 *)packet->tc.y_buf;
                z1 = 0;
                z2 = 0;
        } else {
-               x = packet->tc.x;
-               y = packet->tc.y;
-               z1 = packet->tc.z1;
-               z2 = packet->tc.z2;
+               z1 = packet->tc.z1.data;
+               z2 = packet->tc.z2.data;
        }
 
        /* range filtering */
@@ -786,10 +802,11 @@ static void ads7846_report_state(struct ads7846 *ts)
                /* compute touch pressure resistance using equation #2 */
                Rt = z2;
                Rt -= z1;
-               Rt *= x;
                Rt *= ts->x_plate_ohms;
+               Rt = DIV_ROUND_CLOSEST(Rt, 16);
+               Rt *= x;
                Rt /= z1;
-               Rt = (Rt + 2047) >> 12;
+               Rt = DIV_ROUND_CLOSEST(Rt, 256);
        } else {
                Rt = 0;
        }
@@ -868,16 +885,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
                                   msecs_to_jiffies(TS_POLL_PERIOD));
        }
 
-       if (ts->pendown && !ts->stopped) {
-               struct input_dev *input = ts->input;
-
-               input_report_key(input, BTN_TOUCH, 0);
-               input_report_abs(input, ABS_PRESSURE, 0);
-               input_sync(input);
-
-               ts->pendown = false;
-               dev_vdbg(&ts->spi->dev, "UP\n");
-       }
+       if (ts->pendown && !ts->stopped)
+               ads7846_report_pen_up(ts);
 
        return IRQ_HANDLED;
 }
@@ -992,26 +1001,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
        spi_message_init(m);
        m->context = ts;
 
-       if (ts->model == 7845) {
-               packet->read_y_cmd[0] = READ_Y(vref);
-               packet->read_y_cmd[1] = 0;
-               packet->read_y_cmd[2] = 0;
-               x->tx_buf = &packet->read_y_cmd[0];
-               x->rx_buf = &packet->tc.y_buf[0];
-               x->len = 3;
-               spi_message_add_tail(x, m);
-       } else {
-               /* y- still on; turn on only y+ (and ADC) */
-               packet->read_y = READ_Y(vref);
-               x->tx_buf = &packet->read_y;
-               x->len = 1;
-               spi_message_add_tail(x, m);
-
-               x++;
-               x->rx_buf = &packet->tc.y;
-               x->len = 2;
-               spi_message_add_tail(x, m);
-       }
+       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);
 
        /*
         * The first sample after switching drivers can be low quality;
@@ -1021,15 +1015,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
        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;
-               x->len = 1;
-               spi_message_add_tail(x, m);
 
-               x++;
+               x->tx_buf = &packet->read_y_cmd;
                x->rx_buf = &packet->tc.y;
-               x->len = 2;
+               x->len = 3;
                spi_message_add_tail(x, m);
        }
 
@@ -1038,28 +1028,13 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
        spi_message_init(m);
        m->context = ts;
 
-       if (ts->model == 7845) {
-               x++;
-               packet->read_x_cmd[0] = READ_X(vref);
-               packet->read_x_cmd[1] = 0;
-               packet->read_x_cmd[2] = 0;
-               x->tx_buf = &packet->read_x_cmd[0];
-               x->rx_buf = &packet->tc.x_buf[0];
-               x->len = 3;
-               spi_message_add_tail(x, m);
-       } else {
-               /* turn y- off, x+ on, then leave in lowpower */
-               x++;
-               packet->read_x = READ_X(vref);
-               x->tx_buf = &packet->read_x;
-               x->len = 1;
-               spi_message_add_tail(x, m);
-
-               x++;
-               x->rx_buf = &packet->tc.x;
-               x->len = 2;
-               spi_message_add_tail(x, m);
-       }
+       /* 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;
+       spi_message_add_tail(x, m);
 
        /* ... maybe discard first sample ... */
        if (pdata->settle_delay_usecs) {
@@ -1067,13 +1042,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
                x->delay.unit = SPI_DELAY_UNIT_USECS;
 
                x++;
-               x->tx_buf = &packet->read_x;
-               x->len = 1;
-               spi_message_add_tail(x, m);
-
-               x++;
+               x->tx_buf = &packet->read_x_cmd;
                x->rx_buf = &packet->tc.x;
-               x->len = 2;
+               x->len = 3;
                spi_message_add_tail(x, m);
        }
 
@@ -1085,14 +1056,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
                m->context = ts;
 
                x++;
-               packet->read_z1 = READ_Z1(vref);
-               x->tx_buf = &packet->read_z1;
-               x->len = 1;
-               spi_message_add_tail(x, m);
-
-               x++;
+               packet->read_z1_cmd.cmd = READ_Z1(vref);
+               x->tx_buf = &packet->read_z1_cmd;
                x->rx_buf = &packet->tc.z1;
-               x->len = 2;
+               x->len = 3;
                spi_message_add_tail(x, m);
 
                /* ... maybe discard first sample ... */
@@ -1101,13 +1068,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
                        x->delay.unit = SPI_DELAY_UNIT_USECS;
 
                        x++;
-                       x->tx_buf = &packet->read_z1;
-                       x->len = 1;
-                       spi_message_add_tail(x, m);
-
-                       x++;
+                       x->tx_buf = &packet->read_z1_cmd;
                        x->rx_buf = &packet->tc.z1;
-                       x->len = 2;
+                       x->len = 3;
                        spi_message_add_tail(x, m);
                }
 
@@ -1117,14 +1080,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
                m->context = ts;
 
                x++;
-               packet->read_z2 = READ_Z2(vref);
-               x->tx_buf = &packet->read_z2;
-               x->len = 1;
-               spi_message_add_tail(x, m);
-
-               x++;
+               packet->read_z2_cmd.cmd = READ_Z2(vref);
+               x->tx_buf = &packet->read_z2_cmd;
                x->rx_buf = &packet->tc.z2;
-               x->len = 2;
+               x->len = 3;
                spi_message_add_tail(x, m);
 
                /* ... maybe discard first sample ... */
@@ -1133,13 +1092,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
                        x->delay.unit = SPI_DELAY_UNIT_USECS;
 
                        x++;
-                       x->tx_buf = &packet->read_z2;
-                       x->len = 1;
-                       spi_message_add_tail(x, m);
-
-                       x++;
+                       x->tx_buf = &packet->read_z2_cmd;
                        x->rx_buf = &packet->tc.z2;
-                       x->len = 2;
+                       x->len = 3;
                        spi_message_add_tail(x, m);
                }
        }
@@ -1150,24 +1105,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
        spi_message_init(m);
        m->context = ts;
 
-       if (ts->model == 7845) {
-               x++;
-               packet->pwrdown_cmd[0] = PWRDOWN;
-               packet->pwrdown_cmd[1] = 0;
-               packet->pwrdown_cmd[2] = 0;
-               x->tx_buf = &packet->pwrdown_cmd[0];
-               x->len = 3;
-       } else {
-               x++;
-               packet->pwrdown = PWRDOWN;
-               x->tx_buf = &packet->pwrdown;
-               x->len = 1;
-               spi_message_add_tail(x, m);
-
-               x++;
-               x->rx_buf = &packet->dummy;
-               x->len = 2;
-       }
+       x++;
+       packet->pwrdown_cmd.cmd = PWRDOWN;
+       x->tx_buf = &packet->pwrdown_cmd;
+       x->len = 3;
 
        CS_CHANGE(*x);
        spi_message_add_tail(x, m);
index 02a73d9a4defed6b066913c88cc40ebbfd1dd77f..dccbcb942fe59affc47488e83343a9b9cec576e7 100644 (file)
 
 #define CY_CORE_STARTUP_RETRY_COUNT            3
 
+static const char * const cyttsp4_tch_abs_string[] = {
+       [CY_TCH_X]      = "X",
+       [CY_TCH_Y]      = "Y",
+       [CY_TCH_P]      = "P",
+       [CY_TCH_T]      = "T",
+       [CY_TCH_E]      = "E",
+       [CY_TCH_O]      = "O",
+       [CY_TCH_W]      = "W",
+       [CY_TCH_MAJ]    = "MAJ",
+       [CY_TCH_MIN]    = "MIN",
+       [CY_TCH_OR]     = "OR",
+       [CY_TCH_NUM_ABS] = "INVALID"
+};
+
 static const u8 ldr_exit[] = {
        0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17
 };
index f3e44435944040b409e2904abdaca6d1df5da8b6..6262f6e45075196c441779c25d68e75a2050a0b9 100644 (file)
@@ -233,20 +233,6 @@ enum cyttsp4_tch_abs {     /* for ordering within the extracted touch data array */
        CY_TCH_NUM_ABS
 };
 
-static const char * const cyttsp4_tch_abs_string[] = {
-       [CY_TCH_X]      = "X",
-       [CY_TCH_Y]      = "Y",
-       [CY_TCH_P]      = "P",
-       [CY_TCH_T]      = "T",
-       [CY_TCH_E]      = "E",
-       [CY_TCH_O]      = "O",
-       [CY_TCH_W]      = "W",
-       [CY_TCH_MAJ]    = "MAJ",
-       [CY_TCH_MIN]    = "MIN",
-       [CY_TCH_OR]     = "OR",
-       [CY_TCH_NUM_ABS] = "INVALID"
-};
-
 struct cyttsp4_touch {
        int abs[CY_TCH_NUM_ABS];
 };
index eadd389cf81feea800a24da33374c62f0030fccf..491de67ddbcd7eb4cd2fcc48c8aed568595300d9 100644 (file)
@@ -28,6 +28,7 @@
 #define EKTF2127_RESPONSE              0x52
 #define EKTF2127_REQUEST               0x53
 #define EKTF2127_HELLO                 0x55
+#define EKTF2127_REPORT2               0x5a
 #define EKTF2127_REPORT                        0x5d
 #define EKTF2127_CALIB_DONE            0x66
 
@@ -95,6 +96,29 @@ static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf)
        input_sync(ts->input);
 }
 
+static void ektf2127_report2_contact(struct ektf2127_ts *ts, int slot,
+                                    const u8 *buf, bool active)
+{
+       input_mt_slot(ts->input, slot);
+       input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, active);
+
+       if (active) {
+               int x = (buf[0] & 0xf0) << 4 | buf[1];
+               int y = (buf[0] & 0x0f) << 8 | buf[2];
+
+               touchscreen_report_pos(ts->input, &ts->prop, x, y, true);
+       }
+}
+
+static void ektf2127_report2_event(struct ektf2127_ts *ts, const u8 *buf)
+{
+       ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & 2));
+       ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & 4));
+
+       input_mt_sync_frame(ts->input);
+       input_sync(ts->input);
+}
+
 static irqreturn_t ektf2127_irq(int irq, void *dev_id)
 {
        struct ektf2127_ts *ts = dev_id;
@@ -113,6 +137,10 @@ static irqreturn_t ektf2127_irq(int irq, void *dev_id)
                ektf2127_report_event(ts, buf);
                break;
 
+       case EKTF2127_REPORT2:
+               ektf2127_report2_event(ts, buf);
+               break;
+
        case EKTF2127_NOISE:
                if (buf[1] == EKTF2127_ENV_NOISY)
                        dev_dbg(dev, "Environment is electrically noisy\n");
@@ -305,6 +333,7 @@ static int ektf2127_probe(struct i2c_client *client,
 #ifdef CONFIG_OF
 static const struct of_device_id ektf2127_of_match[] = {
        { .compatible = "elan,ektf2127" },
+       { .compatible = "elan,ektf2132" },
        {}
 };
 MODULE_DEVICE_TABLE(of, ektf2127_of_match);
@@ -312,6 +341,7 @@ MODULE_DEVICE_TABLE(of, ektf2127_of_match);
 
 static const struct i2c_device_id ektf2127_i2c_id[] = {
        { "ektf2127", 0 },
+       { "ektf2132", 0 },
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id);
@@ -327,6 +357,6 @@ static struct i2c_driver ektf2127_driver = {
 };
 module_i2c_driver(ektf2127_driver);
 
-MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver");
+MODULE_DESCRIPTION("ELAN eKTF2127/eKTF2132 I2C Touchscreen Driver");
 MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij");
 MODULE_LICENSE("GPL");
index b0bd5bb079bec69cfb012caa6b0f86e1088cca6d..50c348297e383ec14b1839df63a4a0e79b9aee3a 100644 (file)
@@ -90,7 +90,7 @@
 /* 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_REK                0xE0
+#define E_ELAN_INFO_REK                0xD0
 #define E_ELAN_INFO_TEST_VER   0xE0
 #define E_ELAN_INFO_FW_ID      0xF0
 #define E_INFO_OSR             0xD6
@@ -134,6 +134,7 @@ struct elants_data {
        u8 bc_version;
        u8 iap_version;
        u16 hw_version;
+       u8 major_res;
        unsigned int x_res;     /* resolution in units/mm */
        unsigned int y_res;
        unsigned int x_max;
@@ -459,6 +460,9 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
        rows = resp[2] + resp[6] + resp[10];
        cols = resp[3] + resp[7] + resp[11];
 
+       /* Get report resolution value of ABS_MT_TOUCH_MAJOR */
+       ts->major_res = resp[16];
+
        /* Process mm_to_pixel information */
        error = elants_i2c_execute_command(client,
                                           get_osr_cmd, sizeof(get_osr_cmd),
@@ -1325,6 +1329,8 @@ static int elants_i2c_probe(struct i2c_client *client,
                             0, MT_TOOL_PALM, 0, 0);
        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);
 
index 9ed258854349bf541a0df83c21e7fbffbe459b36..e1852f7d4d31e4c7c886f8c36c2dfb0aee6d4220 100644 (file)
@@ -304,20 +304,18 @@ static irqreturn_t adc_irq_fn(int irq, void *dev_id)
 {
        struct imx6ul_tsc *tsc = dev_id;
        u32 coco;
-       u32 value;
 
        coco = readl(tsc->adc_regs + REG_ADC_HS);
        if (coco & 0x01) {
-               value = readl(tsc->adc_regs + REG_ADC_R0);
+               readl(tsc->adc_regs + REG_ADC_R0);
                complete(&tsc->completion);
        }
 
        return IRQ_HANDLED;
 }
 
-static int imx6ul_tsc_open(struct input_dev *input_dev)
+static int imx6ul_tsc_start(struct imx6ul_tsc *tsc)
 {
-       struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
        int err;
 
        err = clk_prepare_enable(tsc->adc_clk);
@@ -349,16 +347,29 @@ disable_adc_clk:
        return err;
 }
 
-static void imx6ul_tsc_close(struct input_dev *input_dev)
+static void imx6ul_tsc_stop(struct imx6ul_tsc *tsc)
 {
-       struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
-
        imx6ul_tsc_disable(tsc);
 
        clk_disable_unprepare(tsc->tsc_clk);
        clk_disable_unprepare(tsc->adc_clk);
 }
 
+
+static int imx6ul_tsc_open(struct input_dev *input_dev)
+{
+       struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
+
+       return imx6ul_tsc_start(tsc);
+}
+
+static void imx6ul_tsc_close(struct input_dev *input_dev)
+{
+       struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
+
+       imx6ul_tsc_stop(tsc);
+}
+
 static int imx6ul_tsc_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -509,12 +520,8 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
 
        mutex_lock(&input_dev->mutex);
 
-       if (input_dev->users) {
-               imx6ul_tsc_disable(tsc);
-
-               clk_disable_unprepare(tsc->tsc_clk);
-               clk_disable_unprepare(tsc->adc_clk);
-       }
+       if (input_dev->users)
+               imx6ul_tsc_stop(tsc);
 
        mutex_unlock(&input_dev->mutex);
 
@@ -530,22 +537,11 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
 
        mutex_lock(&input_dev->mutex);
 
-       if (input_dev->users) {
-               retval = clk_prepare_enable(tsc->adc_clk);
-               if (retval)
-                       goto out;
-
-               retval = clk_prepare_enable(tsc->tsc_clk);
-               if (retval) {
-                       clk_disable_unprepare(tsc->adc_clk);
-                       goto out;
-               }
-
-               retval = imx6ul_tsc_init(tsc);
-       }
+       if (input_dev->users)
+               retval = imx6ul_tsc_start(tsc);
 
-out:
        mutex_unlock(&input_dev->mutex);
+
        return retval;
 }
 
index fe245439adee065c17c79bb4b8e615fffe2f4e96..e694a9b2b1e5fa6e2302905f0db94c5fb0520b3c 100644 (file)
@@ -51,6 +51,7 @@
 
 /* Touch relative info */
 #define RM_MAX_RETRIES         3
+#define RM_RETRY_DELAY_MS      20
 #define RM_MAX_TOUCH_NUM       10
 #define RM_BOOT_DELAY_MS       100
 
@@ -136,83 +137,82 @@ struct raydium_data {
        bool wake_irq_enabled;
 };
 
-static int raydium_i2c_send(struct i2c_client *client,
-                           u8 addr, const void *data, size_t len)
+static int raydium_i2c_xfer(struct i2c_client *client,
+                           u32 addr, void *data, size_t len, bool is_read)
 {
-       u8 *buf;
-       int tries = 0;
-       int ret;
-
-       buf = kmalloc(len + 1, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       buf[0] = addr;
-       memcpy(buf + 1, data, len);
-
-       do {
-               ret = i2c_master_send(client, buf, len + 1);
-               if (likely(ret == len + 1))
-                       break;
-
-               msleep(20);
-       } while (++tries < RM_MAX_RETRIES);
-
-       kfree(buf);
-
-       if (unlikely(ret != len + 1)) {
-               if (ret >= 0)
-                       ret = -EIO;
-               dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
-               return ret;
-       }
+       struct raydium_bank_switch_header {
+               u8 cmd;
+               __be32 be_addr;
+       } __packed header = {
+               .cmd = RM_CMD_BANK_SWITCH,
+               .be_addr = cpu_to_be32(addr),
+       };
 
-       return 0;
-}
+       u8 reg_addr = addr & 0xff;
 
-static int raydium_i2c_read(struct i2c_client *client,
-                           u8 addr, void *data, size_t len)
-{
        struct i2c_msg xfer[] = {
+               {
+                       .addr = client->addr,
+                       .len = sizeof(header),
+                       .buf = (u8 *)&header,
+               },
                {
                        .addr = client->addr,
                        .len = 1,
-                       .buf = &addr,
+                       .buf = &reg_addr,
                },
                {
                        .addr = client->addr,
-                       .flags = I2C_M_RD,
                        .len = len,
                        .buf = data,
+                       .flags = is_read ? I2C_M_RD : 0,
                }
        };
+
+       /*
+        * If address is greater than 255, then RM_CMD_BANK_SWITCH needs to be
+        * sent first. Else, skip the header i.e. xfer[0].
+        */
+       int xfer_start_idx = (addr > 0xff) ? 0 : 1;
+       size_t xfer_count = ARRAY_SIZE(xfer) - xfer_start_idx;
        int ret;
 
-       ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer));
-       if (unlikely(ret != ARRAY_SIZE(xfer)))
-               return ret < 0 ? ret : -EIO;
+       ret = i2c_transfer(client->adapter, &xfer[xfer_start_idx], xfer_count);
+       if (likely(ret == xfer_count))
+               return 0;
+
+       return ret < 0 ? ret : -EIO;
+}
 
-       return 0;
+static int raydium_i2c_send(struct i2c_client *client,
+                           u32 addr, const void *data, size_t len)
+{
+       int tries = 0;
+       int error;
+
+       do {
+               error = raydium_i2c_xfer(client, addr, (void *)data, len,
+                                        false);
+               if (likely(!error))
+                       return 0;
+
+               msleep(RM_RETRY_DELAY_MS);
+       } while (++tries < RM_MAX_RETRIES);
+
+       dev_err(&client->dev, "%s failed: %d\n", __func__, error);
+       return error;
 }
 
-static int raydium_i2c_read_message(struct i2c_client *client,
-                                   u32 addr, void *data, size_t len)
+static int raydium_i2c_read(struct i2c_client *client,
+                           u32 addr, void *data, size_t len)
 {
-       __be32 be_addr;
        size_t xfer_len;
        int error;
 
        while (len) {
                xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE);
-
-               be_addr = cpu_to_be32(addr);
-
-               error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
-                                        &be_addr, sizeof(be_addr));
-               if (!error)
-                       error = raydium_i2c_read(client, addr & 0xff,
-                                                data, xfer_len);
-               if (error)
+               error = raydium_i2c_xfer(client, addr, data, xfer_len, true);
+               if (unlikely(error))
                        return error;
 
                len -= xfer_len;
@@ -223,27 +223,13 @@ static int raydium_i2c_read_message(struct i2c_client *client,
        return 0;
 }
 
-static int raydium_i2c_send_message(struct i2c_client *client,
-                                   u32 addr, const void *data, size_t len)
-{
-       __be32 be_addr = cpu_to_be32(addr);
-       int error;
-
-       error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
-                                &be_addr, sizeof(be_addr));
-       if (!error)
-               error = raydium_i2c_send(client, addr & 0xff, data, len);
-
-       return error;
-}
-
 static int raydium_i2c_sw_reset(struct i2c_client *client)
 {
        const u8 soft_rst_cmd = 0x01;
        int error;
 
-       error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR,
-                                        &soft_rst_cmd, sizeof(soft_rst_cmd));
+       error = raydium_i2c_send(client, RM_RESET_MSG_ADDR, &soft_rst_cmd,
+                                sizeof(soft_rst_cmd));
        if (error) {
                dev_err(&client->dev, "software reset failed: %d\n", error);
                return error;
@@ -295,9 +281,8 @@ static int raydium_i2c_query_ts_info(struct raydium_data *ts)
                if (error)
                        continue;
 
-               error = raydium_i2c_read_message(client,
-                                                le32_to_cpu(query_bank_addr),
-                                                &ts->info, sizeof(ts->info));
+               error = raydium_i2c_read(client, le32_to_cpu(query_bank_addr),
+                                        &ts->info, sizeof(ts->info));
                if (error)
                        continue;
 
@@ -834,8 +819,8 @@ static irqreturn_t raydium_i2c_irq(int irq, void *_dev)
        if (ts->boot_mode != RAYDIUM_TS_MAIN)
                goto out;
 
-       error = raydium_i2c_read_message(ts->client, ts->data_bank_addr,
-                                        ts->report_data, ts->pkg_size);
+       error = raydium_i2c_read(ts->client, ts->data_bank_addr,
+                                ts->report_data, ts->pkg_size);
        if (error)
                goto out;
 
index cfc8bb4553f78fe3de549ec68ae0697d7bdaf397..e50af30183f4e6ebbbc2a0d40323d47e974fbaec 100644 (file)
@@ -23,7 +23,7 @@
 #define GRTS_MAX_POS_MASK                              GENMASK(11, 0)
 
 /**
- * grts_state - generic resistive touch screen information struct
+ * struct grts_state - generic resistive touch screen information struct
  * @pressure_min:      number representing the minimum for the pressure
  * @pressure:          are we getting pressure info or not
  * @iio_chans:         list of channels acquired
index 63b29c7279e29a240d583fe21db825f01ee6f0bc..bda96762744e6da3e9c3d9a1549a5fc54c9c35b8 100644 (file)
 #define ST1232_TS_NAME "st1232-ts"
 #define ST1633_TS_NAME "st1633-ts"
 
+#define REG_XY_RESOLUTION      0x04
+#define REG_XY_COORDINATES     0x12
 #define ST_TS_MAX_FINGERS      10
 
 struct st_chip_info {
        bool    have_z;
-       u16     max_x;
-       u16     max_y;
        u16     max_area;
        u16     max_fingers;
-       u8      start_reg;
 };
 
 struct st1232_ts_data {
@@ -48,15 +47,14 @@ struct st1232_ts_data {
        u8 *read_buf;
 };
 
-static int st1232_ts_read_data(struct st1232_ts_data *ts)
+static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg)
 {
        struct i2c_client *client = ts->client;
-       u8 start_reg = ts->chip_info->start_reg;
        struct i2c_msg msg[] = {
                {
                        .addr   = client->addr,
-                       .len    = sizeof(start_reg),
-                       .buf    = &start_reg,
+                       .len    = sizeof(reg),
+                       .buf    = &reg,
                },
                {
                        .addr   = client->addr,
@@ -74,6 +72,25 @@ static int st1232_ts_read_data(struct st1232_ts_data *ts)
        return 0;
 }
 
+static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x,
+                                    u16 *max_y)
+{
+       u8 *buf;
+       int error;
+
+       /* select resolution register */
+       error = st1232_ts_read_data(ts, REG_XY_RESOLUTION);
+       if (error)
+               return error;
+
+       buf = ts->read_buf;
+
+       *max_x = ((buf[0] & 0x0070) << 4) | buf[1];
+       *max_y = ((buf[0] & 0x0007) << 8) | buf[2];
+
+       return 0;
+}
+
 static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
 {
        struct input_dev *input = ts->input_dev;
@@ -123,7 +140,7 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
        int count;
        int error;
 
-       error = st1232_ts_read_data(ts);
+       error = st1232_ts_read_data(ts, REG_XY_COORDINATES);
        if (error)
                goto out;
 
@@ -157,20 +174,14 @@ static void st1232_ts_power_off(void *data)
 
 static const struct st_chip_info st1232_chip_info = {
        .have_z         = true,
-       .max_x          = 0x31f, /* 800 - 1 */
-       .max_y          = 0x1df, /* 480 -1 */
        .max_area       = 0xff,
        .max_fingers    = 2,
-       .start_reg      = 0x12,
 };
 
 static const struct st_chip_info st1633_chip_info = {
        .have_z         = false,
-       .max_x          = 0x13f, /* 320 - 1 */
-       .max_y          = 0x1df, /* 480 -1 */
        .max_area       = 0x00,
        .max_fingers    = 5,
-       .start_reg      = 0x12,
 };
 
 static int st1232_ts_probe(struct i2c_client *client,
@@ -179,6 +190,7 @@ static int st1232_ts_probe(struct i2c_client *client,
        const struct st_chip_info *match;
        struct st1232_ts_data *ts;
        struct input_dev *input_dev;
+       u16 max_x, max_y;
        int error;
 
        match = device_get_match_data(&client->dev);
@@ -239,14 +251,22 @@ static int st1232_ts_probe(struct i2c_client *client,
        input_dev->name = "st1232-touchscreen";
        input_dev->id.bustype = BUS_I2C;
 
+       /* Read resolution from the chip */
+       error = st1232_ts_read_resolution(ts, &max_x, &max_y);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to read resolution: %d\n", error);
+               return error;
+       }
+
        if (ts->chip_info->have_z)
                input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
                                     ts->chip_info->max_area, 0, 0);
 
        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-                            0, ts->chip_info->max_x, 0, 0);
+                            0, max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-                            0, ts->chip_info->max_y, 0, 0);
+                            0, max_y, 0, 0);
 
        touchscreen_parse_properties(input_dev, true, &ts->prop);
 
index df946869d4cd1fa2789bbadd511290b667c4d8cf..9a64e1dbc04ad6836b99c2e50d20c17483370519 100644 (file)
@@ -479,7 +479,7 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
 
        mutex_lock(&sdata->mutex);
 
-       if (value & sdata->hover_enabled)
+       if (value && sdata->hover_enabled)
                goto out;
 
        if (sdata->running)
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
new file mode 100644 (file)
index 0000000..1acc2eb
--- /dev/null
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+/* Register Map */
+
+#define BT541_SWRESET_CMD                      0x0000
+#define BT541_WAKEUP_CMD                       0x0001
+
+#define BT541_IDLE_CMD                         0x0004
+#define BT541_SLEEP_CMD                                0x0005
+
+#define BT541_CLEAR_INT_STATUS_CMD             0x0003
+#define BT541_CALIBRATE_CMD                    0x0006
+#define BT541_SAVE_STATUS_CMD                  0x0007
+#define BT541_SAVE_CALIBRATION_CMD             0x0008
+#define BT541_RECALL_FACTORY_CMD               0x000f
+
+#define BT541_THRESHOLD                                0x0020
+
+#define BT541_LARGE_PALM_REJECT_AREA_TH                0x003F
+
+#define BT541_DEBUG_REG                                0x0115 /* 0~7 */
+
+#define BT541_TOUCH_MODE                       0x0010
+#define BT541_CHIP_REVISION                    0x0011
+#define BT541_FIRMWARE_VERSION                 0x0012
+
+#define ZINITIX_USB_DETECT                     0x116
+
+#define BT541_MINOR_FW_VERSION                 0x0121
+
+#define BT541_VENDOR_ID                                0x001C
+#define BT541_HW_ID                            0x0014
+
+#define BT541_DATA_VERSION_REG                 0x0013
+#define BT541_SUPPORTED_FINGER_NUM             0x0015
+#define BT541_EEPROM_INFO                      0x0018
+#define BT541_INITIAL_TOUCH_MODE               0x0019
+
+#define BT541_TOTAL_NUMBER_OF_X                        0x0060
+#define BT541_TOTAL_NUMBER_OF_Y                        0x0061
+
+#define BT541_DELAY_RAW_FOR_HOST               0x007f
+
+#define BT541_BUTTON_SUPPORTED_NUM             0x00B0
+#define BT541_BUTTON_SENSITIVITY               0x00B2
+#define BT541_DUMMY_BUTTON_SENSITIVITY         0X00C8
+
+#define BT541_X_RESOLUTION                     0x00C0
+#define BT541_Y_RESOLUTION                     0x00C1
+
+#define BT541_POINT_STATUS_REG                 0x0080
+#define BT541_ICON_STATUS_REG                  0x00AA
+
+#define BT541_POINT_COORD_REG                  (BT541_POINT_STATUS_REG + 2)
+
+#define BT541_AFE_FREQUENCY                    0x0100
+#define BT541_DND_N_COUNT                      0x0122
+#define BT541_DND_U_COUNT                      0x0135
+
+#define BT541_RAWDATA_REG                      0x0200
+
+#define BT541_EEPROM_INFO_REG                  0x0018
+
+#define BT541_INT_ENABLE_FLAG                  0x00f0
+#define BT541_PERIODICAL_INTERRUPT_INTERVAL    0x00f1
+
+#define BT541_BTN_WIDTH                                0x016d
+
+#define BT541_CHECKSUM_RESULT                  0x012c
+
+#define BT541_INIT_FLASH                       0x01d0
+#define BT541_WRITE_FLASH                      0x01d1
+#define BT541_READ_FLASH                       0x01d2
+
+#define ZINITIX_INTERNAL_FLAG_02               0x011e
+#define ZINITIX_INTERNAL_FLAG_03               0x011f
+
+#define ZINITIX_I2C_CHECKSUM_WCNT              0x016a
+#define ZINITIX_I2C_CHECKSUM_RESULT            0x016c
+
+/* Interrupt & status register flags */
+
+#define BIT_PT_CNT_CHANGE                      BIT(0)
+#define BIT_DOWN                               BIT(1)
+#define BIT_MOVE                               BIT(2)
+#define BIT_UP                                 BIT(3)
+#define BIT_PALM                               BIT(4)
+#define BIT_PALM_REJECT                                BIT(5)
+#define BIT_RESERVED_0                         BIT(6)
+#define BIT_RESERVED_1                         BIT(7)
+#define BIT_WEIGHT_CHANGE                      BIT(8)
+#define BIT_PT_NO_CHANGE                       BIT(9)
+#define BIT_REJECT                             BIT(10)
+#define BIT_PT_EXIST                           BIT(11)
+#define BIT_RESERVED_2                         BIT(12)
+#define BIT_ERROR                              BIT(13)
+#define BIT_DEBUG                              BIT(14)
+#define BIT_ICON_EVENT                         BIT(15)
+
+#define SUB_BIT_EXIST                          BIT(0)
+#define SUB_BIT_DOWN                           BIT(1)
+#define SUB_BIT_MOVE                           BIT(2)
+#define SUB_BIT_UP                             BIT(3)
+#define SUB_BIT_UPDATE                         BIT(4)
+#define SUB_BIT_WAIT                           BIT(5)
+
+#define DEFAULT_TOUCH_POINT_MODE               2
+#define MAX_SUPPORTED_FINGER_NUM               5
+
+#define CHIP_ON_DELAY                          15 // ms
+#define FIRMWARE_ON_DELAY                      40 // ms
+
+struct point_coord {
+       __le16  x;
+       __le16  y;
+       u8      width;
+       u8      sub_status;
+       // currently unused, but needed as padding:
+       u8      minor_width;
+       u8      angle;
+};
+
+struct touch_event {
+       __le16  status;
+       u8      finger_cnt;
+       u8      time_stamp;
+       struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct bt541_ts_data {
+       struct i2c_client *client;
+       struct input_dev *input_dev;
+       struct touchscreen_properties prop;
+       struct regulator_bulk_data supplies[2];
+       u32 zinitix_mode;
+};
+
+static int zinitix_read_data(struct i2c_client *client,
+                            u16 reg, void *values, size_t length)
+{
+       __le16 reg_le = cpu_to_le16(reg);
+       int ret;
+
+       /* A single i2c_transfer() transaction does not work here. */
+       ret = i2c_master_send(client, (u8 *)&reg_le, sizeof(reg_le));
+       if (ret != sizeof(reg_le))
+               return ret < 0 ? ret : -EIO;
+
+       ret = i2c_master_recv(client, (u8 *)values, length);
+       if (ret != length)
+               return ret < 0 ? ret : -EIO; ;
+
+       return 0;
+}
+
+static int zinitix_write_u16(struct i2c_client *client, u16 reg, u16 value)
+{
+       __le16 packet[2] = {cpu_to_le16(reg), cpu_to_le16(value)};
+       int ret;
+
+       ret = i2c_master_send(client, (u8 *)packet, sizeof(packet));
+       if (ret != sizeof(packet))
+               return ret < 0 ? ret : -EIO;
+
+       return 0;
+}
+
+static int zinitix_write_cmd(struct i2c_client *client, u16 reg)
+{
+       __le16 reg_le = cpu_to_le16(reg);
+       int ret;
+
+       ret = i2c_master_send(client, (u8 *)&reg_le, sizeof(reg_le));
+       if (ret != sizeof(reg_le))
+               return ret < 0 ? ret : -EIO;
+
+       return 0;
+}
+
+static bool zinitix_init_touch(struct bt541_ts_data *bt541)
+{
+       struct i2c_client *client = bt541->client;
+       int i;
+       int error;
+
+       error = zinitix_write_cmd(client, BT541_SWRESET_CMD);
+       if (error) {
+               dev_err(&client->dev, "Failed to write reset command\n");
+               return error;
+       }
+
+       error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG, 0x0);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to reset interrupt enable flag\n");
+               return error;
+       }
+
+       /* initialize */
+       error = zinitix_write_u16(client, BT541_X_RESOLUTION,
+                                 bt541->prop.max_x);
+       if (error)
+               return error;
+
+       error = zinitix_write_u16(client, BT541_Y_RESOLUTION,
+                                 bt541->prop.max_y);
+       if (error)
+               return error;
+
+       error = zinitix_write_u16(client, BT541_SUPPORTED_FINGER_NUM,
+                                 MAX_SUPPORTED_FINGER_NUM);
+       if (error)
+               return error;
+
+       error = zinitix_write_u16(client, BT541_INITIAL_TOUCH_MODE,
+                                 bt541->zinitix_mode);
+       if (error)
+               return error;
+
+       error = zinitix_write_u16(client, BT541_TOUCH_MODE,
+                                 bt541->zinitix_mode);
+       if (error)
+               return error;
+
+       error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG,
+                                 BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE |
+                                       BIT_UP);
+       if (error)
+               return error;
+
+       /* clear queue */
+       for (i = 0; i < 10; i++) {
+               zinitix_write_cmd(client, BT541_CLEAR_INT_STATUS_CMD);
+               udelay(10);
+       }
+
+       return 0;
+}
+
+static int zinitix_init_regulators(struct bt541_ts_data *bt541)
+{
+       struct i2c_client *client = bt541->client;
+       int error;
+
+       bt541->supplies[0].supply = "vdd";
+       bt541->supplies[1].supply = "vddo";
+       error = devm_regulator_bulk_get(&client->dev,
+                                       ARRAY_SIZE(bt541->supplies),
+                                       bt541->supplies);
+       if (error < 0) {
+               dev_err(&client->dev, "Failed to get regulators: %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541)
+{
+       int error;
+       struct i2c_client *client = bt541->client;
+
+       error = zinitix_write_u16(client, 0xc000, 0x0001);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to send power sequence(vendor cmd enable)\n");
+               return error;
+       }
+       udelay(10);
+
+       error = zinitix_write_cmd(client, 0xc004);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to send power sequence (intn clear)\n");
+               return error;
+       }
+       udelay(10);
+
+       error = zinitix_write_u16(client, 0xc002, 0x0001);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to send power sequence (nvm init)\n");
+               return error;
+       }
+       mdelay(2);
+
+       error = zinitix_write_u16(client, 0xc001, 0x0001);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to send power sequence (program start)\n");
+               return error;
+       }
+       msleep(FIRMWARE_ON_DELAY);
+
+       return 0;
+}
+
+static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
+                                 const struct point_coord *p)
+{
+       input_mt_slot(bt541->input_dev, slot);
+       input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true);
+       touchscreen_report_pos(bt541->input_dev, &bt541->prop,
+                              le16_to_cpu(p->x), le16_to_cpu(p->y), true);
+       input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width);
+}
+
+static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
+{
+       struct bt541_ts_data *bt541 = bt541_handler;
+       struct i2c_client *client = bt541->client;
+       struct touch_event touch_event;
+       int error;
+       int i;
+
+       memset(&touch_event, 0, sizeof(struct touch_event));
+
+       error = zinitix_read_data(bt541->client, BT541_POINT_STATUS_REG,
+                                 &touch_event, sizeof(struct touch_event));
+       if (error) {
+               dev_err(&client->dev, "Failed to read in touchpoint struct\n");
+               goto out;
+       }
+
+       for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++)
+               if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST)
+                       zinitix_report_finger(bt541, i,
+                                             &touch_event.point_coord[i]);
+
+       input_mt_sync_frame(bt541->input_dev);
+       input_sync(bt541->input_dev);
+
+out:
+       zinitix_write_cmd(bt541->client, BT541_CLEAR_INT_STATUS_CMD);
+       return IRQ_HANDLED;
+}
+
+static int zinitix_start(struct bt541_ts_data *bt541)
+{
+       int error;
+
+       error = regulator_bulk_enable(ARRAY_SIZE(bt541->supplies),
+                                     bt541->supplies);
+       if (error) {
+               dev_err(&bt541->client->dev,
+                       "Failed to enable regulators: %d\n", error);
+               return error;
+       }
+
+       msleep(CHIP_ON_DELAY);
+
+       error = zinitix_send_power_on_sequence(bt541);
+       if (error) {
+               dev_err(&bt541->client->dev,
+                       "Error while sending power-on sequence: %d\n", error);
+               return error;
+       }
+
+       error = zinitix_init_touch(bt541);
+       if (error) {
+               dev_err(&bt541->client->dev,
+                       "Error while configuring touch IC\n");
+               return error;
+       }
+
+       enable_irq(bt541->client->irq);
+
+       return 0;
+}
+
+static int zinitix_stop(struct bt541_ts_data *bt541)
+{
+       int error;
+
+       disable_irq(bt541->client->irq);
+
+       error = regulator_bulk_disable(ARRAY_SIZE(bt541->supplies),
+                                      bt541->supplies);
+       if (error) {
+               dev_err(&bt541->client->dev,
+                       "Failed to disable regulators: %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int zinitix_input_open(struct input_dev *dev)
+{
+       struct bt541_ts_data *bt541 = input_get_drvdata(dev);
+
+       return zinitix_start(bt541);
+}
+
+static void zinitix_input_close(struct input_dev *dev)
+{
+       struct bt541_ts_data *bt541 = input_get_drvdata(dev);
+
+       zinitix_stop(bt541);
+}
+
+static int zinitix_init_input_dev(struct bt541_ts_data *bt541)
+{
+       struct input_dev *input_dev;
+       int error;
+
+       input_dev = devm_input_allocate_device(&bt541->client->dev);
+       if (!input_dev) {
+               dev_err(&bt541->client->dev,
+                       "Failed to allocate input device.");
+               return -ENOMEM;
+       }
+
+       input_set_drvdata(input_dev, bt541);
+       bt541->input_dev = input_dev;
+
+       input_dev->name = "Zinitix Capacitive TouchScreen";
+       input_dev->phys = "input/ts";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->open = zinitix_input_open;
+       input_dev->close = zinitix_input_close;
+
+       input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
+       input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
+       input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+
+       touchscreen_parse_properties(input_dev, true, &bt541->prop);
+       if (!bt541->prop.max_x || !bt541->prop.max_y) {
+               dev_err(&bt541->client->dev,
+                       "Touchscreen-size-x and/or touchscreen-size-y not set in dts\n");
+               return -EINVAL;
+       }
+
+       error = input_mt_init_slots(input_dev, MAX_SUPPORTED_FINGER_NUM,
+                                   INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+       if (error) {
+               dev_err(&bt541->client->dev,
+                       "Failed to initialize MT slots: %d", error);
+               return error;
+       }
+
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&bt541->client->dev,
+                       "Failed to register input device: %d", error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int zinitix_ts_probe(struct i2c_client *client)
+{
+       struct bt541_ts_data *bt541;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev,
+                       "Failed to assert adapter's support for plain I2C.\n");
+               return -ENXIO;
+       }
+
+       bt541 = devm_kzalloc(&client->dev, sizeof(*bt541), GFP_KERNEL);
+       if (!bt541)
+               return -ENOMEM;
+
+       bt541->client = client;
+       i2c_set_clientdata(client, bt541);
+
+       error = zinitix_init_regulators(bt541);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to initialize regulators: %d\n", error);
+               return error;
+       }
+
+       error = zinitix_init_input_dev(bt541);
+       if (error) {
+               dev_err(&client->dev,
+                       "Failed to initialize input device: %d\n", error);
+               return error;
+       }
+
+       error = device_property_read_u32(&client->dev, "zinitix,mode",
+                                        &bt541->zinitix_mode);
+       if (error < 0) {
+               /* fall back to mode 2 */
+               bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
+       }
+
+       if (bt541->zinitix_mode != 2) {
+               /*
+                * If there are devices that don't support mode 2, support
+                * for other modes (0, 1) will be needed.
+                */
+               dev_err(&client->dev,
+                       "Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
+                       bt541->zinitix_mode);
+               return -EINVAL;
+       }
+
+       irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
+       error = devm_request_threaded_irq(&client->dev, client->irq,
+                                         NULL, zinitix_ts_irq_handler,
+                                         IRQF_ONESHOT, client->name, bt541);
+       if (error) {
+               dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int __maybe_unused zinitix_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
+
+       mutex_lock(&bt541->input_dev->mutex);
+
+       if (bt541->input_dev->users)
+               zinitix_stop(bt541);
+
+       mutex_unlock(&bt541->input_dev->mutex);
+
+       return 0;
+}
+
+static int __maybe_unused zinitix_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
+       int ret = 0;
+
+       mutex_lock(&bt541->input_dev->mutex);
+
+       if (bt541->input_dev->users)
+               ret = zinitix_start(bt541);
+
+       mutex_unlock(&bt541->input_dev->mutex);
+
+       return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id zinitix_of_match[] = {
+       { .compatible = "zinitix,bt541" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, zinitix_of_match);
+#endif
+
+static struct i2c_driver zinitix_ts_driver = {
+       .probe_new = zinitix_ts_probe,
+       .driver = {
+               .name = "Zinitix-TS",
+               .pm = &zinitix_pm_ops,
+               .of_match_table = of_match_ptr(zinitix_of_match),
+       },
+};
+module_i2c_driver(zinitix_ts_driver);
+
+MODULE_AUTHOR("Michael Srba <Michael.Srba@seznam.cz>");
+MODULE_DESCRIPTION("Zinitix touchscreen driver");
+MODULE_LICENSE("GPL v2");
index eae3579f106f3d8d4519c3e80b78edd7265d1783..e3810675090ac93f205a0d2025ec4389cc94cf52 100644 (file)
@@ -1913,6 +1913,10 @@ enum {   /* hot key scan codes (derived from ACPI DSDT) */
        TP_ACPI_HOTKEYSCAN_CALCULATOR,
        TP_ACPI_HOTKEYSCAN_BLUETOOTH,
        TP_ACPI_HOTKEYSCAN_KEYBOARD,
+       TP_ACPI_HOTKEYSCAN_FN_RIGHT_SHIFT, /* Used by "Lenovo Quick Clean" */
+       TP_ACPI_HOTKEYSCAN_NOTIFICATION_CENTER,
+       TP_ACPI_HOTKEYSCAN_PICKUP_PHONE,
+       TP_ACPI_HOTKEYSCAN_HANGUP_PHONE,
 
        /* Hotkey keymap size */
        TPACPI_HOTKEY_MAP_LEN
@@ -3429,11 +3433,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
                KEY_UNKNOWN,
 
-               KEY_BOOKMARKS,       /* Favorite app, 0x311 */
-               KEY_RESERVED,        /* Clipping tool */
-               KEY_CALC,            /* Calculator (above numpad, P52) */
-               KEY_BLUETOOTH,       /* Bluetooth */
-               KEY_KEYBOARD         /* Keyboard, 0x315 */
+               KEY_BOOKMARKS,                  /* Favorite app, 0x311 */
+               KEY_SELECTIVE_SCREENSHOT,       /* Clipping tool */
+               KEY_CALC,                       /* Calculator (above numpad, P52) */
+               KEY_BLUETOOTH,                  /* Bluetooth */
+               KEY_KEYBOARD,                   /* Keyboard, 0x315 */
+               KEY_FN_RIGHT_SHIFT,             /* Fn + right Shift */
+               KEY_NOTIFICATION_CENTER,        /* Notification Center */
+               KEY_PICKUP_PHONE,               /* Answer incoming call */
+               KEY_HANGUP_PHONE,               /* Decline incoming call */
                },
        };
 
index 8ed37f93f3c829349693b6ee0de6076e8f425597..ab7eea01ab4274bfc9efcefcdb0cced6ec34966f 100644 (file)
@@ -102,15 +102,16 @@ struct rmi_2d_sensor_platform_data {
 };
 
 /**
- * struct rmi_f30_data - overrides defaults for a single F30 GPIOs/LED chip.
+ * struct rmi_gpio_data - overrides defaults for a single F30/F3A GPIOs/LED
+ * chip.
  * @buttonpad - the touchpad is a buttonpad, so enable only the first actual
  * button that is found.
- * @trackstick_buttons - Set when the function 30 is handling the physical
+ * @trackstick_buttons - Set when the function 30 or 3a is handling the physical
  * buttons of the trackstick (as a PS/2 passthrough device).
- * @disable - the touchpad incorrectly reports F30 and it should be ignored.
+ * @disable - the touchpad incorrectly reports F30/F3A and it should be ignored.
  * This is a special case which is due to misconfigured firmware.
  */
-struct rmi_f30_data {
+struct rmi_gpio_data {
        bool buttonpad;
        bool trackstick_buttons;
        bool disable;
@@ -218,7 +219,7 @@ struct rmi_device_platform_data {
        /* function handler pdata */
        struct rmi_2d_sensor_platform_data sensor_pdata;
        struct rmi_f01_power_management power_management;
-       struct rmi_f30_data f30_data;
+       struct rmi_gpio_data gpio_data;
 };
 
 /**
index 0c2e27d28e0acdf825bab42cbffb452275f065ed..ee93428ced9a1723824413b69bdd88980170bca4 100644 (file)
 #define KEY_10CHANNELSUP       0x1b8   /* 10 channels up (10+) */
 #define KEY_10CHANNELSDOWN     0x1b9   /* 10 channels down (10-) */
 #define KEY_IMAGES             0x1ba   /* AL Image Browser */
+#define KEY_NOTIFICATION_CENTER        0x1bc   /* Show/hide the notification center */
+#define KEY_PICKUP_PHONE       0x1bd   /* Answer incoming call */
+#define KEY_HANGUP_PHONE       0x1be   /* Decline incoming call */
 
 #define KEY_DEL_EOL            0x1c0
 #define KEY_DEL_EOS            0x1c1
 #define KEY_FN_F               0x1e2
 #define KEY_FN_S               0x1e3
 #define KEY_FN_B               0x1e4
+#define KEY_FN_RIGHT_SHIFT     0x1e5
 
 #define KEY_BRL_DOT1           0x1f1
 #define KEY_BRL_DOT2           0x1f2