summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/input/gpio-vibrator.yaml37
-rw-r--r--Documentation/devicetree/bindings/input/lpc32xx-key.txt5
-rw-r--r--Documentation/devicetree/bindings/input/microchip,qt1050.txt78
-rw-r--r--Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt6
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/goodix.txt3
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/iqs5xx.txt80
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt1
-rw-r--r--drivers/hid/hid-input.c2
-rw-r--r--drivers/input/evdev.c7
-rw-r--r--drivers/input/keyboard/Kconfig11
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/keyboard/qt1050.c598
-rw-r--r--drivers/input/keyboard/snvs_pwrkey.c30
-rw-r--r--drivers/input/keyboard/sun4i-lradc-keys.c38
-rw-r--r--drivers/input/misc/Kconfig12
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/gpio-vibra.c207
-rw-r--r--drivers/input/mouse/psmouse-base.c2
-rw-r--r--drivers/input/rmi4/rmi_f54.c21
-rw-r--r--drivers/input/serio/Kconfig1
-rw-r--r--drivers/input/serio/hyperv-keyboard.c2
-rw-r--r--drivers/input/serio/i8042.c3
-rw-r--r--drivers/input/serio/libps2.c1
-rw-r--r--drivers/input/touchscreen/Kconfig10
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c23
-rw-r--r--drivers/input/touchscreen/goodix.c54
-rw-r--r--drivers/input/touchscreen/iqs5xx.c1133
-rw-r--r--include/uapi/linux/input-event-codes.h1
30 files changed, 2297 insertions, 74 deletions
diff --git a/Documentation/devicetree/bindings/input/gpio-vibrator.yaml b/Documentation/devicetree/bindings/input/gpio-vibrator.yaml
new file mode 100644
index 000000000000..903475f52dbd
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-vibrator.yaml
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/input/gpio-vibrator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GPIO vibrator
+
+maintainers:
+  - Luca Weiss <luca@z3ntu.xyz>
+
+description: |+
+  Registers a GPIO device as vibrator, where the on/off capability is controlled by a GPIO.
+
+properties:
+  compatible:
+    const: gpio-vibrator
+
+  enable-gpios:
+    maxItems: 1
+
+  vcc-supply:
+    description: Regulator that provides power
+
+required:
+  - compatible
+  - enable-gpios
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    vibrator {
+        compatible = "gpio-vibrator";
+        enable-gpios = <&msmgpio 86 GPIO_ACTIVE_HIGH>;
+        vcc-supply = <&pm8941_l18>;
+    };
diff --git a/Documentation/devicetree/bindings/input/lpc32xx-key.txt b/Documentation/devicetree/bindings/input/lpc32xx-key.txt
index bcf62f856358..2b075a080d30 100644
--- a/Documentation/devicetree/bindings/input/lpc32xx-key.txt
+++ b/Documentation/devicetree/bindings/input/lpc32xx-key.txt
@@ -8,6 +8,7 @@ Required Properties:
 - reg: Physical base address of the controller and length of memory mapped
   region.
 - interrupts: The interrupt number to the cpu.
+- clocks: phandle to clock controller plus clock-specifier pair
 - nxp,debounce-delay-ms: Debounce delay in ms
 - nxp,scan-delay-ms: Repeated scan period in ms
 - linux,keymap: the key-code to be reported when the key is pressed
@@ -22,7 +23,9 @@ Example:
 	key@40050000 {
 		compatible = "nxp,lpc3220-key";
 		reg = <0x40050000 0x1000>;
-		interrupts = <54 0>;
+		clocks = <&clk LPC32XX_CLK_KEY>;
+		interrupt-parent = <&sic1>;
+		interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
 		keypad,num-rows = <1>;
 		keypad,num-columns = <1>;
 		nxp,debounce-delay-ms = <3>;
diff --git a/Documentation/devicetree/bindings/input/microchip,qt1050.txt b/Documentation/devicetree/bindings/input/microchip,qt1050.txt
new file mode 100644
index 000000000000..80e75f96252b
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/microchip,qt1050.txt
@@ -0,0 +1,78 @@
+Microchip AT42QT1050 Five-channel Touch Sensor IC
+
+The AT42QT1050 (QT1050) is a QTouchADC sensor device. The device can sense from
+one to five keys, dependent on mode. The QT1050 includes all signal processing
+functions necessary to provide stable sensing under a wide variety of changing
+conditions, and the outputs are fully debounced.
+
+The touchkey device node should be placed inside an I2C bus node.
+
+Required properties:
+- compatible: Must be "microchip,qt1050"
+- reg: The I2C address of the device
+- interrupts: The sink for the touchpad's IRQ output,
+  see ../interrupt-controller/interrupts.txt
+
+Optional properties:
+- wakeup-source: touch keys can be used as a wakeup source
+
+Each button (key) is represented as a sub-node:
+
+Each not specified key or key with linux,code set to KEY_RESERVED gets disabled
+in HW.
+
+Subnode properties:
+- linux,code: Keycode to emit.
+- reg: The key number. Valid values: 0, 1, 2, 3, 4.
+
+Optional subnode-properties:
+
+If a optional property is missing or has a invalid value the default value is
+taken.
+
+- microchip,pre-charge-time-ns:
+  Each touchpad need some time to precharge. The value depends on the mechanical
+  layout.
+  Valid value range: 0 - 637500; values must be a multiple of 2500;
+  default is 0.
+- microchip,average-samples:
+  Number of data samples which are averaged for each read.
+  Valid values: 1, 4, 16, 64, 256, 1024, 4096, 16384; default is 1.
+- microchip,average-scaling:
+  The scaling factor which is used to scale the average-samples.
+  Valid values: 1, 2, 4, 8, 16, 32, 64, 128; default is 1.
+- microchip,threshold:
+  Number of counts to register a touch detection.
+  Valid value range: 0 - 255; default is 20.
+
+Example:
+QT1050 with 3 non continuous keys, key2 and key4 are disabled.
+
+touchkeys@41 {
+	compatible = "microchip,qt1050";
+	reg = <0x41>;
+	interrupt-parent = <&gpio0>;
+	interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
+
+	up@0 {
+		reg = <0>;
+		linux,code = <KEY_UP>;
+		microchip,average-samples = <64>;
+		microchip,average-scaling = <16>;
+		microchip,pre-charge-time-ns = <10000>;
+	};
+
+	right@1 {
+		reg = <1>;
+		linux,code = <KEY_RIGHT>;
+		microchip,average-samples = <64>;
+		microchip,average-scaling = <8>;
+	};
+
+	down@3 {
+		reg = <3>;
+		linux,code = <KEY_DOWN>;
+		microchip,average-samples = <256>;
+		microchip,average-scaling = <16>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
index 1458c3179a63..496125c6bfb7 100644
--- a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
+++ b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
@@ -2,12 +2,14 @@ Allwinner sun4i low res adc attached tablet keys
 ------------------------------------------------
 
 Required properties:
- - compatible: "allwinner,sun4i-a10-lradc-keys"
+ - compatible: should be one of the following string:
+		"allwinner,sun4i-a10-lradc-keys"
+		"allwinner,sun8i-a83t-r-lradc"
  - reg: mmio address range of the chip
  - interrupts: interrupt to which the chip is connected
  - vref-supply: powersupply for the lradc reference voltage
 
-Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys":
+Each key is represented as a sub-node of the compatible mentioned above:
 
 Required subnode-properties:
 	- label: Descriptive name of the key.
diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
index 8cf0b4d38a7e..fc03ea4cf5ab 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt
@@ -3,6 +3,7 @@ Device tree bindings for Goodix GT9xx series touchscreen controller
 Required properties:
 
  - compatible		: Should be "goodix,gt1151"
+				 or "goodix,gt5663"
 				 or "goodix,gt5688"
 				 or "goodix,gt911"
 				 or "goodix,gt9110"
@@ -19,6 +20,8 @@ Optional properties:
  - irq-gpios		: GPIO pin used for IRQ. The driver uses the
 			  interrupt gpio pin as output to reset the device.
  - reset-gpios		: GPIO pin used for reset
+ - AVDD28-supply	: Analog power supply regulator on AVDD28 pin
+ - VDDIO-supply		: GPIO power supply regulator on VDDIO pin
  - touchscreen-inverted-x
  - touchscreen-inverted-y
  - touchscreen-size-x
diff --git a/Documentation/devicetree/bindings/input/touchscreen/iqs5xx.txt b/Documentation/devicetree/bindings/input/touchscreen/iqs5xx.txt
new file mode 100644
index 000000000000..efa0820e2469
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/iqs5xx.txt
@@ -0,0 +1,80 @@
+Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
+
+Required properties:
+
+- compatible			: Must be equal to one of the following:
+				  "azoteq,iqs550"
+				  "azoteq,iqs572"
+				  "azoteq,iqs525"
+
+- reg				: I2C slave address for the device.
+
+- interrupts			: GPIO to which the device's active-high RDY
+				  output is connected (see [0]).
+
+- reset-gpios			: GPIO to which the device's active-low NRST
+				  input is connected (see [1]).
+
+Optional properties:
+
+- touchscreen-min-x		: See [2].
+
+- touchscreen-min-y		: See [2].
+
+- touchscreen-size-x		: See [2]. If this property is omitted, the
+				  maximum x-coordinate is specified by the
+				  device's "X Resolution" register.
+
+- touchscreen-size-y		: See [2]. If this property is omitted, the
+				  maximum y-coordinate is specified by the
+				  device's "Y Resolution" register.
+
+- touchscreen-max-pressure	: See [2]. Pressure is expressed as the sum of
+				  the deltas across all channels impacted by a
+				  touch event. A channel's delta is calculated
+				  as its count value minus a reference, where
+				  the count value is inversely proportional to
+				  the channel's capacitance.
+
+- touchscreen-fuzz-x		: See [2].
+
+- touchscreen-fuzz-y		: See [2].
+
+- touchscreen-fuzz-pressure	: See [2].
+
+- touchscreen-inverted-x	: See [2]. Inversion is applied relative to that
+				  which may already be specified by the device's
+				  FLIP_X and FLIP_Y register fields.
+
+- touchscreen-inverted-y	: See [2]. Inversion is applied relative to that
+				  which may already be specified by the device's
+				  FLIP_X and FLIP_Y register fields.
+
+- touchscreen-swapped-x-y	: See [2]. Swapping is applied relative to that
+				  which may already be specified by the device's
+				  SWITCH_XY_AXIS register field.
+
+[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+[1]: Documentation/devicetree/bindings/gpio/gpio.txt
+[2]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
+
+Example:
+
+	&i2c1 {
+		/* ... */
+
+		touchscreen@74 {
+			compatible = "azoteq,iqs550";
+			reg = <0x74>;
+			interrupt-parent = <&gpio>;
+			interrupts = <17 4>;
+			reset-gpios = <&gpio 27 1>;
+
+			touchscreen-size-x = <640>;
+			touchscreen-size-y = <480>;
+
+			touchscreen-max-pressure = <16000>;
+		};
+
+		/* ... */
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 4b1a2a8fcc16..51f99549161e 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -53,6 +53,7 @@ avic	Shanghai AVIC Optoelectronics Co., Ltd.
 avnet	Avnet, Inc.
 axentia	Axentia Technologies AB
 axis	Axis Communications AB
+azoteq	Azoteq (Pty) Ltd
 bananapi BIPAI KEJI LIMITED
 bhf	Beckhoff Automation GmbH & Co. KG
 bitmain	Bitmain Technologies
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index da76358cde06..89d00c34a184 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1036,6 +1036,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 		case 0x28b: map_key_clear(KEY_FORWARDMAIL);	break;
 		case 0x28c: map_key_clear(KEY_SEND);		break;
 
+		case 0x29d: map_key_clear(KEY_KBD_LAYOUT_NEXT);	break;
+
 		case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV);		break;
 		case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT);		break;
 		case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP);		break;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index f48369d6f3a0..ee8dd8b1b09e 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -503,14 +503,13 @@ static int evdev_open(struct inode *inode, struct file *file)
 {
 	struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
 	unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
-	unsigned int size = sizeof(struct evdev_client) +
-					bufsize * sizeof(struct input_event);
 	struct evdev_client *client;
 	int error;
 
-	client = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+	client = kzalloc(struct_size(client, buffer, bufsize),
+			 GFP_KERNEL | __GFP_NOWARN);
 	if (!client)
-		client = vzalloc(size);
+		client = vzalloc(struct_size(client, buffer, bufsize));
 	if (!client)
 		return -ENOMEM;
 
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 52d7f55fca32..1fe039d7326b 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -137,6 +137,17 @@ config KEYBOARD_ATKBD_RDI_KEYCODES
 	  right-hand column will be interpreted as the key shown in the
 	  left-hand column.
 
+config KEYBOARD_QT1050
+	tristate "Microchip AT42QT1050 Touch Sensor Chip"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Say Y here if you want to use Microchip AT42QT1050 QTouch
+	  Sensor chip as input device.
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called qt1050
+
 config KEYBOARD_QT1070
        tristate "Atmel AT42QT1070 Touch Sensor Chip"
        depends on I2C
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 182e92985dbf..f0291ca39f62 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PMIC8XXX)		+= pmic8xxx-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
+obj-$(CONFIG_KEYBOARD_QT1050)           += qt1050.o
 obj-$(CONFIG_KEYBOARD_QT1070)           += qt1070.o
 obj-$(CONFIG_KEYBOARD_QT2160)		+= qt2160.o
 obj-$(CONFIG_KEYBOARD_SAMSUNG)		+= samsung-keypad.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 850bb259c20e..3ad93e3e2f4c 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -401,6 +401,8 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
 		if  (ps2_handle_response(&atkbd->ps2dev, data))
 			goto out;
 
+	pm_wakeup_event(&serio->dev, 0);
+
 	if (!atkbd->enabled)
 		goto out;
 
diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c
new file mode 100644
index 000000000000..403060d05c3b
--- /dev/null
+++ b/drivers/input/keyboard/qt1050.c
@@ -0,0 +1,598 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Microchip AT42QT1050 QTouch Sensor Controller
+ *
+ *  Copyright (C) 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ *
+ *  Base on AT42QT1070 driver by:
+ *  Bo Shen <voice.shen@atmel.com>
+ *  Copyright (C) 2011 Atmel
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+/* Chip ID */
+#define QT1050_CHIP_ID		0x00
+#define QT1050_CHIP_ID_VER	0x46
+
+/* Firmware version */
+#define QT1050_FW_VERSION	0x01
+
+/* Detection status */
+#define QT1050_DET_STATUS	0x02
+
+/* Key status */
+#define QT1050_KEY_STATUS	0x03
+
+/* Key Signals */
+#define QT1050_KEY_SIGNAL_0_MSB	0x06
+#define QT1050_KEY_SIGNAL_0_LSB	0x07
+#define QT1050_KEY_SIGNAL_1_MSB	0x08
+#define QT1050_KEY_SIGNAL_1_LSB	0x09
+#define QT1050_KEY_SIGNAL_2_MSB	0x0c
+#define QT1050_KEY_SIGNAL_2_LSB	0x0d
+#define QT1050_KEY_SIGNAL_3_MSB	0x0e
+#define QT1050_KEY_SIGNAL_3_LSB	0x0f
+#define QT1050_KEY_SIGNAL_4_MSB	0x10
+#define QT1050_KEY_SIGNAL_4_LSB	0x11
+
+/* Reference data */
+#define QT1050_REF_DATA_0_MSB	0x14
+#define QT1050_REF_DATA_0_LSB	0x15
+#define QT1050_REF_DATA_1_MSB	0x16
+#define QT1050_REF_DATA_1_LSB	0x17
+#define QT1050_REF_DATA_2_MSB	0x1a
+#define QT1050_REF_DATA_2_LSB	0x1b
+#define QT1050_REF_DATA_3_MSB	0x1c
+#define QT1050_REF_DATA_3_LSB	0x1d
+#define QT1050_REF_DATA_4_MSB	0x1e
+#define QT1050_REF_DATA_4_LSB	0x1f
+
+/* Negative threshold level */
+#define QT1050_NTHR_0		0x21
+#define QT1050_NTHR_1		0x22
+#define QT1050_NTHR_2		0x24
+#define QT1050_NTHR_3		0x25
+#define QT1050_NTHR_4		0x26
+
+/* Pulse / Scale  */
+#define QT1050_PULSE_SCALE_0	0x28
+#define QT1050_PULSE_SCALE_1	0x29
+#define QT1050_PULSE_SCALE_2	0x2b
+#define QT1050_PULSE_SCALE_3	0x2c
+#define QT1050_PULSE_SCALE_4	0x2d
+
+/* Detection integrator counter / AKS */
+#define QT1050_DI_AKS_0		0x2f
+#define QT1050_DI_AKS_1		0x30
+#define QT1050_DI_AKS_2		0x32
+#define QT1050_DI_AKS_3		0x33
+#define QT1050_DI_AKS_4		0x34
+
+/* Charge Share Delay */
+#define QT1050_CSD_0		0x36
+#define QT1050_CSD_1		0x37
+#define QT1050_CSD_2		0x39
+#define QT1050_CSD_3		0x3a
+#define QT1050_CSD_4		0x3b
+
+/* Low Power Mode */
+#define QT1050_LPMODE		0x3d
+
+/* Calibration and Reset */
+#define QT1050_RES_CAL		0x3f
+#define QT1050_RES_CAL_RESET		BIT(7)
+#define QT1050_RES_CAL_CALIBRATE	BIT(1)
+
+#define QT1050_MAX_KEYS		5
+#define QT1050_RESET_TIME	255
+
+struct qt1050_key_regs {
+	unsigned int nthr;
+	unsigned int pulse_scale;
+	unsigned int di_aks;
+	unsigned int csd;
+};
+
+struct qt1050_key {
+	u32 num;
+	u32 charge_delay;
+	u32 thr_cnt;
+	u32 samples;
+	u32 scale;
+	u32 keycode;
+};
+
+struct qt1050_priv {
+	struct i2c_client	*client;
+	struct input_dev	*input;
+	struct regmap		*regmap;
+	struct qt1050_key	keys[QT1050_MAX_KEYS];
+	unsigned short		keycodes[QT1050_MAX_KEYS];
+	u8			reg_keys;
+	u8			last_keys;
+};
+
+static const struct qt1050_key_regs qt1050_key_regs_data[] = {
+	{
+		.nthr = QT1050_NTHR_0,
+		.pulse_scale = QT1050_PULSE_SCALE_0,
+		.di_aks = QT1050_DI_AKS_0,
+		.csd = QT1050_CSD_0,
+	}, {
+		.nthr = QT1050_NTHR_1,
+		.pulse_scale = QT1050_PULSE_SCALE_1,
+		.di_aks = QT1050_DI_AKS_1,
+		.csd = QT1050_CSD_1,
+	}, {
+		.nthr = QT1050_NTHR_2,
+		.pulse_scale = QT1050_PULSE_SCALE_2,
+		.di_aks = QT1050_DI_AKS_2,
+		.csd = QT1050_CSD_2,
+	}, {
+		.nthr = QT1050_NTHR_3,
+		.pulse_scale = QT1050_PULSE_SCALE_3,
+		.di_aks = QT1050_DI_AKS_3,
+		.csd = QT1050_CSD_3,
+	}, {
+		.nthr = QT1050_NTHR_4,
+		.pulse_scale = QT1050_PULSE_SCALE_4,
+		.di_aks = QT1050_DI_AKS_4,
+		.csd = QT1050_CSD_4,
+	}
+};
+
+static bool qt1050_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case QT1050_DET_STATUS:
+	case QT1050_KEY_STATUS:
+	case QT1050_KEY_SIGNAL_0_MSB:
+	case QT1050_KEY_SIGNAL_0_LSB:
+	case QT1050_KEY_SIGNAL_1_MSB:
+	case QT1050_KEY_SIGNAL_1_LSB:
+	case QT1050_KEY_SIGNAL_2_MSB:
+	case QT1050_KEY_SIGNAL_2_LSB:
+	case QT1050_KEY_SIGNAL_3_MSB:
+	case QT1050_KEY_SIGNAL_3_LSB:
+	case QT1050_KEY_SIGNAL_4_MSB:
+	case QT1050_KEY_SIGNAL_4_LSB:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_range qt1050_readable_ranges[] = {
+	regmap_reg_range(QT1050_CHIP_ID, QT1050_KEY_STATUS),
+	regmap_reg_range(QT1050_KEY_SIGNAL_0_MSB, QT1050_KEY_SIGNAL_1_LSB),
+	regmap_reg_range(QT1050_KEY_SIGNAL_2_MSB, QT1050_KEY_SIGNAL_4_LSB),
+	regmap_reg_range(QT1050_REF_DATA_0_MSB, QT1050_REF_DATA_1_LSB),
+	regmap_reg_range(QT1050_REF_DATA_2_MSB, QT1050_REF_DATA_4_LSB),
+	regmap_reg_range(QT1050_NTHR_0, QT1050_NTHR_1),
+	regmap_reg_range(QT1050_NTHR_2, QT1050_NTHR_4),
+	regmap_reg_range(QT1050_PULSE_SCALE_0, QT1050_PULSE_SCALE_1),
+	regmap_reg_range(QT1050_PULSE_SCALE_2, QT1050_PULSE_SCALE_4),
+	regmap_reg_range(QT1050_DI_AKS_0, QT1050_DI_AKS_1),
+	regmap_reg_range(QT1050_DI_AKS_2, QT1050_DI_AKS_4),
+	regmap_reg_range(QT1050_CSD_0, QT1050_CSD_1),
+	regmap_reg_range(QT1050_CSD_2, QT1050_RES_CAL),
+};
+
+static const struct regmap_access_table qt1050_readable_table = {
+	.yes_ranges = qt1050_readable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(qt1050_readable_ranges),
+};
+
+static const struct regmap_range qt1050_writeable_ranges[] = {
+	regmap_reg_range(QT1050_NTHR_0, QT1050_NTHR_1),
+	regmap_reg_range(QT1050_NTHR_2, QT1050_NTHR_4),
+	regmap_reg_range(QT1050_PULSE_SCALE_0, QT1050_PULSE_SCALE_1),
+	regmap_reg_range(QT1050_PULSE_SCALE_2, QT1050_PULSE_SCALE_4),
+	regmap_reg_range(QT1050_DI_AKS_0, QT1050_DI_AKS_1),
+	regmap_reg_range(QT1050_DI_AKS_2, QT1050_DI_AKS_4),
+	regmap_reg_range(QT1050_CSD_0, QT1050_CSD_1),
+	regmap_reg_range(QT1050_CSD_2, QT1050_RES_CAL),
+};
+
+static const struct regmap_access_table qt1050_writeable_table = {
+	.yes_ranges = qt1050_writeable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(qt1050_writeable_ranges),
+};
+
+static struct regmap_config qt1050_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = QT1050_RES_CAL,
+
+	.cache_type = REGCACHE_RBTREE,
+
+	.wr_table = &qt1050_writeable_table,
+	.rd_table = &qt1050_readable_table,
+	.volatile_reg = qt1050_volatile_reg,
+};
+
+static bool qt1050_identify(struct qt1050_priv *ts)
+{
+	unsigned int val;
+	int err;
+
+	/* Read Chip ID */
+	regmap_read(ts->regmap, QT1050_CHIP_ID, &val);
+	if (val != QT1050_CHIP_ID_VER) {
+		dev_err(&ts->client->dev, "ID %d not supported\n", val);
+		return false;
+	}
+
+	/* Read firmware version */
+	err = regmap_read(ts->regmap, QT1050_FW_VERSION, &val);
+	if (err) {
+		dev_err(&ts->client->dev, "could not read the firmware version\n");
+		return false;
+	}
+
+	dev_info(&ts->client->dev, "AT42QT1050 firmware version %1d.%1d\n",
+		 val >> 4, val & 0xf);
+
+	return true;
+}
+
+static irqreturn_t qt1050_irq_threaded(int irq, void *dev_id)
+{
+	struct qt1050_priv *ts = dev_id;
+	struct input_dev *input = ts->input;
+	unsigned long new_keys, changed;
+	unsigned int val;
+	int i, err;
+
+	/* Read the detected status register, thus clearing interrupt */
+	err = regmap_read(ts->regmap, QT1050_DET_STATUS, &val);
+	if (err) {
+		dev_err(&ts->client->dev, "Fail to read detection status: %d\n",
+			err);
+		return IRQ_NONE;
+	}
+
+	/* Read which key changed, keys are not continuous */
+	err = regmap_read(ts->regmap, QT1050_KEY_STATUS, &val);
+	if (err) {
+		dev_err(&ts->client->dev,
+			"Fail to determine the key status: %d\n", err);
+		return IRQ_NONE;
+	}
+	new_keys = (val & 0x70) >> 2 | (val & 0x6) >> 1;
+	changed = ts->last_keys ^ new_keys;
+	/* Report registered keys only */
+	changed &= ts->reg_keys;
+
+	for_each_set_bit(i, &changed, QT1050_MAX_KEYS)
+		input_report_key(input, ts->keys[i].keycode,
+				 test_bit(i, &new_keys));
+
+	ts->last_keys = new_keys;
+	input_sync(input);
+
+	return IRQ_HANDLED;
+}
+
+static const struct qt1050_key_regs *qt1050_get_key_regs(int key_num)
+{
+	return &qt1050_key_regs_data[key_num];
+}
+
+static int qt1050_set_key(struct regmap *map, int number, int on)
+{
+	const struct qt1050_key_regs *key_regs;
+
+	key_regs = qt1050_get_key_regs(number);
+
+	return regmap_update_bits(map, key_regs->di_aks, 0xfc,
+				  on ? BIT(4) : 0x00);
+}
+
+static int qt1050_apply_fw_data(struct qt1050_priv *ts)
+{
+	struct regmap *map = ts->regmap;
+	struct qt1050_key *button = &ts->keys[0];
+	const struct qt1050_key_regs *key_regs;
+	int i, err;
+
+	/* Disable all keys and enable only the specified ones */
+	for (i = 0; i < QT1050_MAX_KEYS; i++) {
+		err = qt1050_set_key(map, i, 0);
+		if (err)
+			return err;
+	}
+
+	for (i = 0; i < QT1050_MAX_KEYS; i++, button++) {
+		/* Keep KEY_RESERVED keys off */
+		if (button->keycode == KEY_RESERVED)
+			continue;
+
+		err = qt1050_set_key(map, button->num, 1);
+		if (err)
+			return err;
+
+		key_regs = qt1050_get_key_regs(button->num);
+
+		err = regmap_write(map, key_regs->pulse_scale,
+				   (button->samples << 4) | (button->scale));
+		if (err)
+			return err;
+		err = regmap_write(map, key_regs->csd, button->charge_delay);
+		if (err)
+			return err;
+		err = regmap_write(map, key_regs->nthr, button->thr_cnt);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int qt1050_parse_fw(struct qt1050_priv *ts)
+{
+	struct device *dev = &ts->client->dev;
+	struct fwnode_handle *child;
+	int nbuttons;
+
+	nbuttons = device_get_child_node_count(dev);
+	if (nbuttons == 0 || nbuttons > QT1050_MAX_KEYS)
+		return -ENODEV;
+
+	device_for_each_child_node(dev, child) {
+		struct qt1050_key button;
+
+		/* Required properties */
+		if (fwnode_property_read_u32(child, "linux,code",
+					     &button.keycode)) {
+			dev_err(dev, "Button without keycode\n");
+			goto err;
+		}
+		if (button.keycode >= KEY_MAX) {
+			dev_err(dev, "Invalid keycode 0x%x\n",
+				button.keycode);
+			goto err;
+		}
+
+		if (fwnode_property_read_u32(child, "reg",
+					     &button.num)) {
+			dev_err(dev, "Button without pad number\n");
+			goto err;
+		}
+		if (button.num < 0 || button.num > QT1050_MAX_KEYS - 1)
+			goto err;
+
+		ts->reg_keys |= BIT(button.num);
+
+		/* Optional properties */
+		if (fwnode_property_read_u32(child,
+					     "microchip,pre-charge-time-ns",
+					     &button.charge_delay)) {
+			button.charge_delay = 0;
+		} else {
+			if (button.charge_delay % 2500 == 0)
+				button.charge_delay =
+					button.charge_delay / 2500;
+			else
+				button.charge_delay = 0;
+		}
+
+		if (fwnode_property_read_u32(child, "microchip,average-samples",
+					 &button.samples)) {
+			button.samples = 0;
+		} else {
+			if (is_power_of_2(button.samples))
+				button.samples = ilog2(button.samples);
+			else
+				button.samples = 0;
+		}
+
+		if (fwnode_property_read_u32(child, "microchip,average-scaling",
+					     &button.scale)) {
+			button.scale = 0;
+		} else {
+			if (is_power_of_2(button.scale))
+				button.scale = ilog2(button.scale);
+			else
+				button.scale = 0;
+
+		}
+
+		if (fwnode_property_read_u32(child, "microchip,threshold",
+					 &button.thr_cnt)) {
+			button.thr_cnt = 20;
+		} else {
+			if (button.thr_cnt > 255)
+				button.thr_cnt = 20;
+		}
+
+		ts->keys[button.num] = button;
+	}
+
+	return 0;
+
+err:
+	fwnode_handle_put(child);
+	return -EINVAL;
+}
+
+static int qt1050_probe(struct i2c_client *client)
+{
+	struct qt1050_priv *ts;
+	struct input_dev *input;
+	struct device *dev = &client->dev;
+	struct regmap *map;
+	unsigned int status, i;
+	int err;
+
+	/* Check basic functionality */
+	err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
+	if (!err) {
+		dev_err(&client->dev, "%s adapter not supported\n",
+			dev_driver_string(&client->adapter->dev));
+		return -ENODEV;
+	}
+
+	if (!client->irq) {
+		dev_err(dev, "assign a irq line to this device\n");
+		return -EINVAL;
+	}
+
+	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	input = devm_input_allocate_device(dev);
+	if (!input)
+		return -ENOMEM;
+
+	map = devm_regmap_init_i2c(client, &qt1050_regmap_config);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	ts->client = client;
+	ts->input = input;
+	ts->regmap = map;
+
+	i2c_set_clientdata(client, ts);
+
+	/* Identify the qt1050 chip */
+	if (!qt1050_identify(ts))
+		return -ENODEV;
+
+	/* Get pdata */
+	err = qt1050_parse_fw(ts);
+	if (err) {
+		dev_err(dev, "Failed to parse firmware: %d\n", err);
+		return err;
+	}
+
+	input->name = "AT42QT1050 QTouch Sensor";
+	input->dev.parent = &client->dev;
+	input->id.bustype = BUS_I2C;
+
+	/* Add the keycode */
+	input->keycode = ts->keycodes;
+	input->keycodesize = sizeof(ts->keycodes[0]);
+	input->keycodemax = QT1050_MAX_KEYS;
+
+	__set_bit(EV_KEY, input->evbit);
+	for (i = 0; i < QT1050_MAX_KEYS; i++) {
+		ts->keycodes[i] = ts->keys[i].keycode;
+		__set_bit(ts->keycodes[i], input->keybit);
+	}
+
+	/* Trigger re-calibration */
+	err = regmap_update_bits(ts->regmap, QT1050_RES_CAL, 0x7f,
+				 QT1050_RES_CAL_CALIBRATE);
+	if (err) {
+		dev_err(dev, "Trigger calibration failed: %d\n", err);
+		return err;
+	}
+	err = regmap_read_poll_timeout(ts->regmap, QT1050_DET_STATUS, status,
+				 status >> 7 == 1, 10000, 200000);
+	if (err) {
+		dev_err(dev, "Calibration failed: %d\n", err);
+		return err;
+	}
+
+	/* Soft reset to set defaults */
+	err = regmap_update_bits(ts->regmap, QT1050_RES_CAL,
+				 QT1050_RES_CAL_RESET, QT1050_RES_CAL_RESET);
+	if (err) {
+		dev_err(dev, "Trigger soft reset failed: %d\n", err);
+		return err;
+	}
+	msleep(QT1050_RESET_TIME);
+
+	/* Set pdata */
+	err = qt1050_apply_fw_data(ts);
+	if (err) {
+		dev_err(dev, "Failed to set firmware data: %d\n", err);
+		return err;
+	}
+
+	err = devm_request_threaded_irq(dev, client->irq, NULL,
+					qt1050_irq_threaded, IRQF_ONESHOT,
+					"qt1050", ts);
+	if (err) {
+		dev_err(&client->dev, "Failed to request irq: %d\n", err);
+		return err;
+	}
+
+	/* Clear #CHANGE line */
+	err = regmap_read(ts->regmap, QT1050_DET_STATUS, &status);
+	if (err) {
+		dev_err(dev, "Failed to clear #CHANGE line level: %d\n", err);
+		return err;
+	}
+
+	/* Register the input device */
+	err = input_register_device(ts->input);
+	if (err) {
+		dev_err(&client->dev, "Failed to register input device: %d\n",
+			err);
+		return err;
+	}
+
+	return 0;
+}
+
+static int __maybe_unused qt1050_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct qt1050_priv *ts = i2c_get_clientdata(client);
+
+	disable_irq(client->irq);
+
+	/*
+	 * Set measurement interval to 1s (125 x 8ms) if wakeup is allowed
+	 * else turn off. The 1s interval seems to be a good compromise between
+	 * low power and response time.
+	 */
+	return regmap_write(ts->regmap, QT1050_LPMODE,
+			    device_may_wakeup(dev) ? 125 : 0);
+}
+
+static int __maybe_unused qt1050_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct qt1050_priv *ts = i2c_get_clientdata(client);
+
+	enable_irq(client->irq);
+
+	/* Set measurement interval back to 16ms (2 x 8ms) */
+	return regmap_write(ts->regmap, QT1050_LPMODE, 2);
+}
+
+static SIMPLE_DEV_PM_OPS(qt1050_pm_ops, qt1050_suspend, qt1050_resume);
+
+static const struct of_device_id __maybe_unused qt1050_of_match[] = {
+	{ .compatible = "microchip,qt1050", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, qt1050_of_match);
+
+static struct i2c_driver qt1050_driver = {
+	.driver	= {
+		.name = "qt1050",
+		.of_match_table = of_match_ptr(qt1050_of_match),
+		.pm = &qt1050_pm_ops,
+	},
+	.probe_new = qt1050_probe,
+};
+
+module_i2c_driver(qt1050_driver);
+
+MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de");
+MODULE_DESCRIPTION("Driver for AT42QT1050 QTouch sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 4c67cf30a5d9..5342d8d45f81 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -15,6 +15,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
 
@@ -167,28 +168,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
 	}
 
 	device_init_wakeup(&pdev->dev, pdata->wakeup);
-
-	return 0;
-}
-
-static int __maybe_unused imx_snvs_pwrkey_suspend(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
-
-	if (device_may_wakeup(&pdev->dev))
-		enable_irq_wake(pdata->irq);
-
-	return 0;
-}
-
-static int __maybe_unused imx_snvs_pwrkey_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
-
-	if (device_may_wakeup(&pdev->dev))
-		disable_irq_wake(pdata->irq);
+	error = dev_pm_set_wake_irq(&pdev->dev, pdata->irq);
+	if (error)
+		dev_err(&pdev->dev, "irq wake enable failed.\n");
 
 	return 0;
 }
@@ -199,13 +181,9 @@ static const struct of_device_id imx_snvs_pwrkey_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids);
 
-static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend,
-				imx_snvs_pwrkey_resume);
-
 static struct platform_driver imx_snvs_pwrkey_driver = {
 	.driver = {
 		.name = "snvs_pwrkey",
-		.pm     = &imx_snvs_pwrkey_pm_ops,
 		.of_match_table = imx_snvs_pwrkey_ids,
 	},
 	.probe = imx_snvs_pwrkey_probe,
diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
index 57272df34cd5..df3eec72a9b2 100644
--- a/drivers/input/keyboard/sun4i-lradc-keys.c
+++ b/drivers/input/keyboard/sun4i-lradc-keys.c
@@ -46,6 +46,7 @@
 #define CONTINUE_TIME_SEL(x)	((x) << 16) /* 4 bits */
 #define KEY_MODE_SEL(x)		((x) << 12) /* 2 bits */
 #define LEVELA_B_CNT(x)		((x) << 8)  /* 4 bits */
+#define HOLD_KEY_EN(x)		((x) << 7)
 #define HOLD_EN(x)		((x) << 6)
 #define LEVELB_VOL(x)		((x) << 4)  /* 2 bits */
 #define SAMPLE_RATE(x)		((x) << 2)  /* 2 bits */
@@ -63,6 +64,25 @@
 #define	CHAN0_KEYDOWN_IRQ	BIT(1)
 #define CHAN0_DATA_IRQ		BIT(0)
 
+/* struct lradc_variant - Describe sun4i-a10-lradc-keys hardware variant
+ * @divisor_numerator:		The numerator of lradc Vref internally divisor
+ * @divisor_denominator:	The denominator of lradc Vref internally divisor
+ */
+struct lradc_variant {
+	u8 divisor_numerator;
+	u8 divisor_denominator;
+};
+
+static const struct lradc_variant lradc_variant_a10 = {
+	.divisor_numerator = 2,
+	.divisor_denominator = 3
+};
+
+static const struct lradc_variant r_lradc_variant_a83t = {
+	.divisor_numerator = 3,
+	.divisor_denominator = 4
+};
+
 struct sun4i_lradc_keymap {
 	u32 voltage;
 	u32 keycode;
@@ -74,6 +94,7 @@ struct sun4i_lradc_data {
 	void __iomem *base;
 	struct regulator *vref_supply;
 	struct sun4i_lradc_keymap *chan0_map;
+	const struct lradc_variant *variant;
 	u32 chan0_map_count;
 	u32 chan0_keycode;
 	u32 vref;
@@ -128,9 +149,9 @@ static int sun4i_lradc_open(struct input_dev *dev)
 	if (error)
 		return error;
 
-	/* lradc Vref internally is divided by 2/3 */
-	lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3;
-
+	lradc->vref = regulator_get_voltage(lradc->vref_supply) *
+		      lradc->variant->divisor_numerator /
+		      lradc->variant->divisor_denominator;
 	/*
 	 * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
 	 * stabilize on press, wait (1 + 1) * 4 ms for key release
@@ -222,6 +243,12 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
 	if (error)
 		return error;
 
+	lradc->variant = of_device_get_match_data(&pdev->dev);
+	if (!lradc->variant) {
+		dev_err(&pdev->dev, "Missing sun4i-a10-lradc-keys variant\n");
+		return -EINVAL;
+	}
+
 	lradc->vref_supply = devm_regulator_get(dev, "vref");
 	if (IS_ERR(lradc->vref_supply))
 		return PTR_ERR(lradc->vref_supply);
@@ -265,7 +292,10 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id sun4i_lradc_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-lradc-keys", },
+	{ .compatible = "allwinner,sun4i-a10-lradc-keys",
+		.data = &lradc_variant_a10 },
+	{ .compatible = "allwinner,sun8i-a83t-r-lradc",
+		.data = &r_lradc_variant_a83t },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index e39aef84f357..16f41eece6d2 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -290,6 +290,18 @@ config INPUT_GPIO_DECODER
 	 To compile this driver as a module, choose M here: the module
 	 will be called gpio_decoder.
 
+config INPUT_GPIO_VIBRA
+	tristate "GPIO vibrator support"
+	depends on GPIOLIB || COMPILE_TEST
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here to get support for GPIO based vibrator devices.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called gpio-vibra.
+
 config INPUT_IXP4XX_BEEPER
 	tristate "IXP4XX Beeper support"
 	depends on ARCH_IXP4XX
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 96a6419cb1f2..d871991c2eee 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS)	+= drv2667.o
 obj-$(CONFIG_INPUT_GP2A)		+= gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_BEEPER)		+= gpio-beeper.o
 obj-$(CONFIG_INPUT_GPIO_DECODER)	+= gpio_decoder.o
+obj-$(CONFIG_INPUT_GPIO_VIBRA)		+= gpio-vibra.o
 obj-$(CONFIG_INPUT_HISI_POWERKEY)	+= hisi_powerkey.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IMS_PCU)		+= ims-pcu.o
diff --git a/drivers/input/misc/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c
new file mode 100644
index 000000000000..f79f75595dd7
--- /dev/null
+++ b/drivers/input/misc/gpio-vibra.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  GPIO vibrator driver
+ *
+ *  Copyright (C) 2019 Luca Weiss <luca@z3ntu.xyz>
+ *
+ *  Based on PWM vibrator driver:
+ *  Copyright (C) 2017 Collabora Ltd.
+ *
+ *  Based on previous work from:
+ *  Copyright (C) 2012 Dmitry Torokhov <dmitry.torokhov@gmail.com>
+ *
+ *  Based on PWM beeper driver:
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct gpio_vibrator {
+	struct input_dev *input;
+	struct gpio_desc *gpio;
+	struct regulator *vcc;
+
+	struct work_struct play_work;
+	bool running;
+	bool vcc_on;
+};
+
+static int gpio_vibrator_start(struct gpio_vibrator *vibrator)
+{
+	struct device *pdev = vibrator->input->dev.parent;
+	int err;
+
+	if (!vibrator->vcc_on) {
+		err = regulator_enable(vibrator->vcc);
+		if (err) {
+			dev_err(pdev, "failed to enable regulator: %d\n", err);
+			return err;
+		}
+		vibrator->vcc_on = true;
+	}
+
+	gpiod_set_value_cansleep(vibrator->gpio, 1);
+
+	return 0;
+}
+
+static void gpio_vibrator_stop(struct gpio_vibrator *vibrator)
+{
+	gpiod_set_value_cansleep(vibrator->gpio, 0);
+
+	if (vibrator->vcc_on) {
+		regulator_disable(vibrator->vcc);
+		vibrator->vcc_on = false;
+	}
+}
+
+static void gpio_vibrator_play_work(struct work_struct *work)
+{
+	struct gpio_vibrator *vibrator =
+		container_of(work, struct gpio_vibrator, play_work);
+
+	if (vibrator->running)
+		gpio_vibrator_start(vibrator);
+	else
+		gpio_vibrator_stop(vibrator);
+}
+
+static int gpio_vibrator_play_effect(struct input_dev *dev, void *data,
+				     struct ff_effect *effect)
+{
+	struct gpio_vibrator *vibrator = input_get_drvdata(dev);
+	int level;
+
+	level = effect->u.rumble.strong_magnitude;
+	if (!level)
+		level = effect->u.rumble.weak_magnitude;
+
+	vibrator->running = level;
+	schedule_work(&vibrator->play_work);
+
+	return 0;
+}
+
+static void gpio_vibrator_close(struct input_dev *input)
+{
+	struct gpio_vibrator *vibrator = input_get_drvdata(input);
+
+	cancel_work_sync(&vibrator->play_work);
+	gpio_vibrator_stop(vibrator);
+	vibrator->running = false;
+}
+
+static int gpio_vibrator_probe(struct platform_device *pdev)
+{
+	struct gpio_vibrator *vibrator;
+	int err;
+
+	vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
+	if (!vibrator)
+		return -ENOMEM;
+
+	vibrator->input = devm_input_allocate_device(&pdev->dev);
+	if (!vibrator->input)
+		return -ENOMEM;
+
+	vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
+	err = PTR_ERR_OR_ZERO(vibrator->vcc);
+	if (err) {
+		if (err != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to request regulator: %d\n",
+				err);
+		return err;
+	}
+
+	vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
+	err = PTR_ERR_OR_ZERO(vibrator->gpio);
+	if (err) {
+		if (err != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Failed to request main gpio: %d\n",
+				err);
+		return err;
+	}
+
+	INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work);
+
+	vibrator->input->name = "gpio-vibrator";
+	vibrator->input->id.bustype = BUS_HOST;
+	vibrator->input->close = gpio_vibrator_close;
+
+	input_set_drvdata(vibrator->input, vibrator);
+	input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
+
+	err = input_ff_create_memless(vibrator->input, NULL,
+				      gpio_vibrator_play_effect);
+	if (err) {
+		dev_err(&pdev->dev, "Couldn't create FF dev: %d\n", err);
+		return err;
+	}
+
+	err = input_register_device(vibrator->input);
+	if (err) {
+		dev_err(&pdev->dev, "Couldn't register input dev: %d\n", err);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, vibrator);
+
+	return 0;
+}
+
+static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
+
+	cancel_work_sync(&vibrator->play_work);
+	if (vibrator->running)
+		gpio_vibrator_stop(vibrator);
+
+	return 0;
+}
+
+static int __maybe_unused gpio_vibrator_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
+
+	if (vibrator->running)
+		gpio_vibrator_start(vibrator);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
+			 gpio_vibrator_suspend, gpio_vibrator_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_vibra_dt_match_table[] = {
+	{ .compatible = "gpio-vibrator" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, gpio_vibra_dt_match_table);
+#endif
+
+static struct platform_driver gpio_vibrator_driver = {
+	.probe	= gpio_vibrator_probe,
+	.driver	= {
+		.name	= "gpio-vibrator",
+		.pm	= &gpio_vibrator_pm_ops,
+		.of_match_table = of_match_ptr(gpio_vibra_dt_match_table),
+	},
+};
+module_platform_driver(gpio_vibrator_driver);
+
+MODULE_AUTHOR("Luca Weiss <luca@z3ntu.xy>");
+MODULE_DESCRIPTION("GPIO vibrator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-vibrator");
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index d3ff1fc09af7..94f7ca5ad077 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -373,6 +373,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
 		if  (ps2_handle_response(&psmouse->ps2dev, data))
 			goto out;
 
+	pm_wakeup_event(&serio->dev, 0);
+
 	if (psmouse->state <= PSMOUSE_RESYNCING)
 		goto out;
 
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index a6f515bcab22..516fea06ed59 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -456,25 +456,15 @@ static int rmi_f54_vidioc_fmt(struct file *file, void *priv,
 static int rmi_f54_vidioc_enum_fmt(struct file *file, void *priv,
 				   struct v4l2_fmtdesc *fmt)
 {
+	struct f54_data *f54 = video_drvdata(file);
+
 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	switch (fmt->index) {
-	case 0:
-		fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
-		break;
-
-	case 1:
-		fmt->pixelformat = V4L2_TCH_FMT_DELTA_TD08;
-		break;
-
-	case 2:
-		fmt->pixelformat = V4L2_TCH_FMT_TU16;
-		break;
-
-	default:
+	if (fmt->index)
 		return -EINVAL;
-	}
+
+	fmt->pixelformat = f54->format.pixelformat;
 
 	return 0;
 }
@@ -692,6 +682,7 @@ static int rmi_f54_probe(struct rmi_function *fn)
 		return -ENOMEM;
 
 	rmi_f54_create_input_map(f54);
+	rmi_f54_set_input(f54, 0);
 
 	/* register video device */
 	strlcpy(f54->v4l2.name, F54_NAME, sizeof(f54->v4l2.name));
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index c9c7224d5ae0..bfe436ccb046 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -254,6 +254,7 @@ config SERIO_APBPS2
 
 config SERIO_OLPC_APSP
 	tristate "OLPC AP-SP input support"
+	depends on ARCH_MMP || COMPILE_TEST
 	help
 	  Say Y here if you want support for the keyboard and touchpad included
 	  in the OLPC XO-1.75 and XO-4 laptops.
diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c
index a8b9be3e28db..7935e52b5435 100644
--- a/drivers/input/serio/hyperv-keyboard.c
+++ b/drivers/input/serio/hyperv-keyboard.c
@@ -440,5 +440,7 @@ static void __exit hv_kbd_exit(void)
 }
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Keyboard Driver");
+
 module_init(hv_kbd_init);
 module_exit(hv_kbd_exit);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 95a78ccbd847..6462f1798fbb 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -573,9 +573,6 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
 	port = &i8042_ports[port_no];
 	serio = port->exists ? port->serio : NULL;
 
-	if (irq && serio)
-		pm_wakeup_event(&serio->dev, 0);
-
 	filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
 		   port_no, irq,
 		   dfl & SERIO_PARITY ? ", bad parity" : "",
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index e6a07e68d1ff..22b8e05aa36c 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -409,6 +409,7 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 			ps2dev->nak = PS2_RET_ERR;
 			break;
 		}
+		/* Fall through */
 
 	/*
 	 * Workaround for mice which don't ACK the Get ID command.
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 7a4884ad198b..a2029c3235af 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1312,4 +1312,14 @@ config TOUCHSCREEN_ROHM_BU21023
 	  To compile this driver as a module, choose M here: the
 	  module will be called bu21023_ts.
 
+config TOUCHSCREEN_IQS5XX
+	tristate "Azoteq IQS550/572/525 trackpad/touchscreen controller"
+	depends on I2C
+	help
+	  Say Y to enable support for the Azoteq IQS550/572/525
+	  family of trackpad/touchscreen controllers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called iqs5xx.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index fcc7605fba8d..084a596a0c8b 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -110,3 +110,4 @@ obj-$(CONFIG_TOUCHSCREEN_ZFORCE)	+= zforce_ts.o
 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
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 702bfda7ee77..c639ebce914c 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -1,20 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
  * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
  * Lothar Waßmann <LW@KARO-electronics.de> (DT support)
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /*
@@ -39,7 +27,6 @@
 #include <linux/gpio/consumer.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
-#include <linux/of_device.h>
 
 #define WORK_REGISTER_THRESHOLD		0x00
 #define WORK_REGISTER_REPORT_RATE	0x08
@@ -1073,7 +1060,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 		return -ENOMEM;
 	}
 
-	chip_data = of_device_get_match_data(&client->dev);
+	chip_data = device_get_match_data(&client->dev);
 	if (!chip_data)
 		chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
 	if (!chip_data || !chip_data->max_support_points) {
@@ -1254,7 +1241,6 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
 
-#ifdef CONFIG_OF
 static const struct of_device_id edt_ft5x06_of_match[] = {
 	{ .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
 	{ .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
@@ -1266,12 +1252,11 @@ static const struct of_device_id edt_ft5x06_of_match[] = {
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
-#endif
 
 static struct i2c_driver edt_ft5x06_ts_driver = {
 	.driver = {
 		.name = "edt_ft5x06",
-		.of_match_table = of_match_ptr(edt_ft5x06_of_match),
+		.of_match_table = edt_ft5x06_of_match,
 		.pm = &edt_ft5x06_ts_pm_ops,
 	},
 	.id_table = edt_ft5x06_ts_id,
@@ -1283,4 +1268,4 @@ module_i2c_driver(edt_ft5x06_ts_driver);
 
 MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>");
 MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index f57d82220a88..f7c1d168dd89 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -27,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/of.h>
@@ -47,6 +48,8 @@ struct goodix_ts_data {
 	struct touchscreen_properties prop;
 	unsigned int max_touch_num;
 	unsigned int int_trigger_type;
+	struct regulator *avdd28;
+	struct regulator *vddio;
 	struct gpio_desc *gpiod_int;
 	struct gpio_desc *gpiod_rst;
 	u16 id;
@@ -216,6 +219,7 @@ static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
 {
 	switch (id) {
 	case 1151:
+	case 5663:
 	case 5688:
 		return &gt1x_chip_data;
 
@@ -532,6 +536,24 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
 		return -EINVAL;
 	dev = &ts->client->dev;
 
+	ts->avdd28 = devm_regulator_get(dev, "AVDD28");
+	if (IS_ERR(ts->avdd28)) {
+		error = PTR_ERR(ts->avdd28);
+		if (error != -EPROBE_DEFER)
+			dev_err(dev,
+				"Failed to get AVDD28 regulator: %d\n", error);
+		return error;
+	}
+
+	ts->vddio = devm_regulator_get(dev, "VDDIO");
+	if (IS_ERR(ts->vddio)) {
+		error = PTR_ERR(ts->vddio);
+		if (error != -EPROBE_DEFER)
+			dev_err(dev,
+				"Failed to get VDDIO regulator: %d\n", error);
+		return error;
+	}
+
 	/* Get the interrupt GPIO pin number */
 	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
 	if (IS_ERR(gpiod)) {
@@ -764,6 +786,14 @@ err_release_cfg:
 	complete_all(&ts->firmware_loading_complete);
 }
 
+static void goodix_disable_regulators(void *arg)
+{
+	struct goodix_ts_data *ts = arg;
+
+	regulator_disable(ts->vddio);
+	regulator_disable(ts->avdd28);
+}
+
 static int goodix_ts_probe(struct i2c_client *client,
 			   const struct i2c_device_id *id)
 {
@@ -789,6 +819,29 @@ static int goodix_ts_probe(struct i2c_client *client,
 	if (error)
 		return error;
 
+	/* power up the controller */
+	error = regulator_enable(ts->avdd28);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to enable AVDD28 regulator: %d\n",
+			error);
+		return error;
+	}
+
+	error = regulator_enable(ts->vddio);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to enable VDDIO regulator: %d\n",
+			error);
+		regulator_disable(ts->avdd28);
+		return error;
+	}
+
+	error = devm_add_action_or_reset(&client->dev,
+					 goodix_disable_regulators, ts);
+	if (error)
+		return error;
+
 	if (ts->gpiod_int && ts->gpiod_rst) {
 		/* reset the controller */
 		error = goodix_reset(ts);
@@ -945,6 +998,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
 #ifdef CONFIG_OF
 static const struct of_device_id goodix_of_match[] = {
 	{ .compatible = "goodix,gt1151" },
+	{ .compatible = "goodix,gt5663" },
 	{ .compatible = "goodix,gt5688" },
 	{ .compatible = "goodix,gt911" },
 	{ .compatible = "goodix,gt9110" },
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
new file mode 100644
index 000000000000..b832fe062645
--- /dev/null
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -0,0 +1,1133 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
+ *
+ * Copyright (C) 2018
+ * Author: Jeff LaBundy <jeff@labundy.com>
+ *
+ * These devices require firmware exported from a PC-based configuration tool
+ * made available by the vendor. Firmware files may be pushed to the device's
+ * nonvolatile memory by writing the filename to the 'fw_file' sysfs control.
+ *
+ * Link to PC-based configuration tool and data sheet: http://www.azoteq.com/
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.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/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define IQS5XX_FW_FILE_LEN	64
+#define IQS5XX_NUM_RETRIES	10
+#define IQS5XX_NUM_POINTS	256
+#define IQS5XX_NUM_CONTACTS	5
+#define IQS5XX_WR_BYTES_MAX	2
+
+#define IQS5XX_PROD_NUM_IQS550	40
+#define IQS5XX_PROD_NUM_IQS572	58
+#define IQS5XX_PROD_NUM_IQS525	52
+#define IQS5XX_PROJ_NUM_A000	0
+#define IQS5XX_PROJ_NUM_B000	15
+#define IQS5XX_MAJOR_VER_MIN	2
+
+#define IQS5XX_RESUME		0x00
+#define IQS5XX_SUSPEND		0x01
+
+#define IQS5XX_SW_INPUT_EVENT	0x10
+#define IQS5XX_SETUP_COMPLETE	0x40
+#define IQS5XX_EVENT_MODE	0x01
+#define IQS5XX_TP_EVENT		0x04
+
+#define IQS5XX_FLIP_X		0x01
+#define IQS5XX_FLIP_Y		0x02
+#define IQS5XX_SWITCH_XY_AXIS	0x04
+
+#define IQS5XX_PROD_NUM		0x0000
+#define IQS5XX_ABS_X		0x0016
+#define IQS5XX_ABS_Y		0x0018
+#define IQS5XX_SYS_CTRL0	0x0431
+#define IQS5XX_SYS_CTRL1	0x0432
+#define IQS5XX_SYS_CFG0		0x058E
+#define IQS5XX_SYS_CFG1		0x058F
+#define IQS5XX_TOTAL_RX		0x063D
+#define IQS5XX_TOTAL_TX		0x063E
+#define IQS5XX_XY_CFG0		0x0669
+#define IQS5XX_X_RES		0x066E
+#define IQS5XX_Y_RES		0x0670
+#define IQS5XX_CHKSM		0x83C0
+#define IQS5XX_APP		0x8400
+#define IQS5XX_CSTM		0xBE00
+#define IQS5XX_PMAP_END		0xBFFF
+#define IQS5XX_END_COMM		0xEEEE
+
+#define IQS5XX_CHKSM_LEN	(IQS5XX_APP - IQS5XX_CHKSM)
+#define IQS5XX_APP_LEN		(IQS5XX_CSTM - IQS5XX_APP)
+#define IQS5XX_CSTM_LEN		(IQS5XX_PMAP_END + 1 - IQS5XX_CSTM)
+#define IQS5XX_PMAP_LEN		(IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM)
+
+#define IQS5XX_REC_HDR_LEN	4
+#define IQS5XX_REC_LEN_MAX	255
+#define IQS5XX_REC_TYPE_DATA	0x00
+#define IQS5XX_REC_TYPE_EOF	0x01
+
+#define IQS5XX_BL_ADDR_MASK	0x40
+#define IQS5XX_BL_CMD_VER	0x00
+#define IQS5XX_BL_CMD_READ	0x01
+#define IQS5XX_BL_CMD_EXEC	0x02
+#define IQS5XX_BL_CMD_CRC	0x03
+#define IQS5XX_BL_BLK_LEN_MAX	64
+#define IQS5XX_BL_ID		0x0200
+#define IQS5XX_BL_STATUS_RESET	0x00
+#define IQS5XX_BL_STATUS_AVAIL	0xA5
+#define IQS5XX_BL_STATUS_NONE	0xEE
+#define IQS5XX_BL_CRC_PASS	0x00
+#define IQS5XX_BL_CRC_FAIL	0x01
+#define IQS5XX_BL_ATTEMPTS	3
+
+struct iqs5xx_private {
+	struct i2c_client *client;
+	struct input_dev *input;
+	struct gpio_desc *reset_gpio;
+	struct mutex lock;
+	u8 bl_status;
+};
+
+struct iqs5xx_dev_id_info {
+	__be16 prod_num;
+	__be16 proj_num;
+	u8 major_ver;
+	u8 minor_ver;
+	u8 bl_status;
+} __packed;
+
+struct iqs5xx_ihex_rec {
+	char start;
+	char len[2];
+	char addr[4];
+	char type[2];
+	char data[2];
+} __packed;
+
+struct iqs5xx_touch_data {
+	__be16 abs_x;
+	__be16 abs_y;
+	__be16 strength;
+	u8 area;
+} __packed;
+
+static int iqs5xx_read_burst(struct i2c_client *client,
+			     u16 reg, void *val, u16 len)
+{
+	__be16 reg_buf = cpu_to_be16(reg);
+	int ret, i;
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = sizeof(reg_buf),
+			.buf = (u8 *)&reg_buf,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = (u8 *)val,
+		},
+	};
+
+	/*
+	 * The first addressing attempt outside of a communication window fails
+	 * and must be retried, after which the device clock stretches until it
+	 * is available.
+	 */
+	for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
+		ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+		if (ret == ARRAY_SIZE(msg))
+			return 0;
+
+		usleep_range(200, 300);
+	}
+
+	if (ret >= 0)
+		ret = -EIO;
+
+	dev_err(&client->dev, "Failed to read from address 0x%04X: %d\n",
+		reg, ret);
+
+	return ret;
+}
+
+static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val)
+{
+	__be16 val_buf;
+	int error;
+
+	error = iqs5xx_read_burst(client, reg, &val_buf, sizeof(val_buf));
+	if (error)
+		return error;
+
+	*val = be16_to_cpu(val_buf);
+
+	return 0;
+}
+
+static int iqs5xx_read_byte(struct i2c_client *client, u16 reg, u8 *val)
+{
+	return iqs5xx_read_burst(client, reg, val, sizeof(*val));
+}
+
+static int iqs5xx_write_burst(struct i2c_client *client,
+			      u16 reg, const void *val, u16 len)
+{
+	int ret, i;
+	u16 mlen = sizeof(reg) + len;
+	u8 mbuf[sizeof(reg) + IQS5XX_WR_BYTES_MAX];
+
+	if (len > IQS5XX_WR_BYTES_MAX)
+		return -EINVAL;
+
+	put_unaligned_be16(reg, mbuf);
+	memcpy(mbuf + sizeof(reg), val, len);
+
+	/*
+	 * The first addressing attempt outside of a communication window fails
+	 * and must be retried, after which the device clock stretches until it
+	 * is available.
+	 */
+	for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
+		ret = i2c_master_send(client, mbuf, mlen);
+		if (ret == mlen)
+			return 0;
+
+		usleep_range(200, 300);
+	}
+
+	if (ret >= 0)
+		ret = -EIO;
+
+	dev_err(&client->dev, "Failed to write to address 0x%04X: %d\n",
+		reg, ret);
+
+	return ret;
+}
+
+static int iqs5xx_write_word(struct i2c_client *client, u16 reg, u16 val)
+{
+	__be16 val_buf = cpu_to_be16(val);
+
+	return iqs5xx_write_burst(client, reg, &val_buf, sizeof(val_buf));
+}
+
+static int iqs5xx_write_byte(struct i2c_client *client, u16 reg, u8 val)
+{
+	return iqs5xx_write_burst(client, reg, &val, sizeof(val));
+}
+
+static void iqs5xx_reset(struct i2c_client *client)
+{
+	struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+
+	gpiod_set_value_cansleep(iqs5xx->reset_gpio, 1);
+	usleep_range(200, 300);
+
+	gpiod_set_value_cansleep(iqs5xx->reset_gpio, 0);
+}
+
+static int iqs5xx_bl_cmd(struct i2c_client *client, u8 bl_cmd, u16 bl_addr)
+{
+	struct i2c_msg msg;
+	int ret;
+	u8 mbuf[sizeof(bl_cmd) + sizeof(bl_addr)];
+
+	msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+	msg.flags = 0;
+	msg.len = sizeof(bl_cmd);
+	msg.buf = mbuf;
+
+	*mbuf = bl_cmd;
+
+	switch (bl_cmd) {
+	case IQS5XX_BL_CMD_VER:
+	case IQS5XX_BL_CMD_CRC:
+	case IQS5XX_BL_CMD_EXEC:
+		break;
+	case IQS5XX_BL_CMD_READ:
+		msg.len += sizeof(bl_addr);
+		put_unaligned_be16(bl_addr, mbuf + sizeof(bl_cmd));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret != 1)
+		goto msg_fail;
+
+	switch (bl_cmd) {
+	case IQS5XX_BL_CMD_VER:
+		msg.len = sizeof(u16);
+		break;
+	case IQS5XX_BL_CMD_CRC:
+		msg.len = sizeof(u8);
+		/*
+		 * This delay saves the bus controller the trouble of having to
+		 * tolerate a relatively long clock-stretching period while the
+		 * CRC is calculated.
+		 */
+		msleep(50);
+		break;
+	case IQS5XX_BL_CMD_EXEC:
+		usleep_range(10000, 10100);
+		/* fall through */
+	default:
+		return 0;
+	}
+
+	msg.flags = I2C_M_RD;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	if (ret != 1)
+		goto msg_fail;
+
+	if (bl_cmd == IQS5XX_BL_CMD_VER &&
+	    get_unaligned_be16(mbuf) != IQS5XX_BL_ID) {
+		dev_err(&client->dev, "Unrecognized bootloader ID: 0x%04X\n",
+			get_unaligned_be16(mbuf));
+		return -EINVAL;
+	}
+
+	if (bl_cmd == IQS5XX_BL_CMD_CRC && *mbuf != IQS5XX_BL_CRC_PASS) {
+		dev_err(&client->dev, "Bootloader CRC failed\n");
+		return -EIO;
+	}
+
+	return 0;
+
+msg_fail:
+	if (ret >= 0)
+		ret = -EIO;
+
+	if (bl_cmd != IQS5XX_BL_CMD_VER)
+		dev_err(&client->dev,
+			"Unsuccessful bootloader command 0x%02X: %d\n",
+			bl_cmd, ret);
+
+	return ret;
+}
+
+static int iqs5xx_bl_open(struct i2c_client *client)
+{
+	int error, i, j;
+
+	/*
+	 * The device opens a bootloader polling window for 2 ms following the
+	 * release of reset. If the host cannot establish communication during
+	 * this time frame, it must cycle reset again.
+	 */
+	for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) {
+		iqs5xx_reset(client);
+
+		for (j = 0; j < IQS5XX_NUM_RETRIES; j++) {
+			error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
+			if (!error || error == -EINVAL)
+				return error;
+		}
+	}
+
+	dev_err(&client->dev, "Failed to open bootloader: %d\n", error);
+
+	return error;
+}
+
+static int iqs5xx_bl_write(struct i2c_client *client,
+			   u16 bl_addr, u8 *pmap_data, u16 pmap_len)
+{
+	struct i2c_msg msg;
+	int ret, i;
+	u8 mbuf[sizeof(bl_addr) + IQS5XX_BL_BLK_LEN_MAX];
+
+	if (pmap_len % IQS5XX_BL_BLK_LEN_MAX)
+		return -EINVAL;
+
+	msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+	msg.flags = 0;
+	msg.len = sizeof(mbuf);
+	msg.buf = mbuf;
+
+	for (i = 0; i < pmap_len; i += IQS5XX_BL_BLK_LEN_MAX) {
+		put_unaligned_be16(bl_addr + i, mbuf);
+		memcpy(mbuf + sizeof(bl_addr), pmap_data + i,
+		       sizeof(mbuf) - sizeof(bl_addr));
+
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret != 1)
+			goto msg_fail;
+
+		usleep_range(10000, 10100);
+	}
+
+	return 0;
+
+msg_fail:
+	if (ret >= 0)
+		ret = -EIO;
+
+	dev_err(&client->dev, "Failed to write block at address 0x%04X: %d\n",
+		bl_addr + i, ret);
+
+	return ret;
+}
+
+static int iqs5xx_bl_verify(struct i2c_client *client,
+			    u16 bl_addr, u8 *pmap_data, u16 pmap_len)
+{
+	struct i2c_msg msg;
+	int ret, i;
+	u8 bl_data[IQS5XX_BL_BLK_LEN_MAX];
+
+	if (pmap_len % IQS5XX_BL_BLK_LEN_MAX)
+		return -EINVAL;
+
+	msg.addr = client->addr ^ IQS5XX_BL_ADDR_MASK;
+	msg.flags = I2C_M_RD;
+	msg.len = sizeof(bl_data);
+	msg.buf = bl_data;
+
+	for (i = 0; i < pmap_len; i += IQS5XX_BL_BLK_LEN_MAX) {
+		ret = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_READ, bl_addr + i);
+		if (ret)
+			return ret;
+
+		ret = i2c_transfer(client->adapter, &msg, 1);
+		if (ret != 1)
+			goto msg_fail;
+
+		if (memcmp(bl_data, pmap_data + i, sizeof(bl_data))) {
+			dev_err(&client->dev,
+				"Failed to verify block at address 0x%04X\n",
+				bl_addr + i);
+			return -EIO;
+		}
+	}
+
+	return 0;
+
+msg_fail:
+	if (ret >= 0)
+		ret = -EIO;
+
+	dev_err(&client->dev, "Failed to read block at address 0x%04X: %d\n",
+		bl_addr + i, ret);
+
+	return ret;
+}
+
+static int iqs5xx_set_state(struct i2c_client *client, u8 state)
+{
+	struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+	int error1, error2;
+
+	if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+		return 0;
+
+	mutex_lock(&iqs5xx->lock);
+
+	/*
+	 * Addressing the device outside of a communication window prompts it
+	 * to assert the RDY output, so disable the interrupt line to prevent
+	 * the handler from servicing a false interrupt.
+	 */
+	disable_irq(client->irq);
+
+	error1 = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL1, state);
+	error2 = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+
+	usleep_range(50, 100);
+	enable_irq(client->irq);
+
+	mutex_unlock(&iqs5xx->lock);
+
+	if (error1)
+		return error1;
+
+	return error2;
+}
+
+static int iqs5xx_open(struct input_dev *input)
+{
+	struct iqs5xx_private *iqs5xx = input_get_drvdata(input);
+
+	return iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
+}
+
+static void iqs5xx_close(struct input_dev *input)
+{
+	struct iqs5xx_private *iqs5xx = input_get_drvdata(input);
+
+	iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
+}
+
+static int iqs5xx_axis_init(struct i2c_client *client)
+{
+	struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+	struct touchscreen_properties prop;
+	struct input_dev *input;
+	int error;
+	u16 max_x, max_x_hw;
+	u16 max_y, max_y_hw;
+	u8 val;
+
+	if (!iqs5xx->input) {
+		input = devm_input_allocate_device(&client->dev);
+		if (!input)
+			return -ENOMEM;
+
+		input->name = client->name;
+		input->id.bustype = BUS_I2C;
+		input->open = iqs5xx_open;
+		input->close = iqs5xx_close;
+
+		input_set_capability(input, EV_ABS, ABS_MT_POSITION_X);
+		input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
+		input_set_capability(input, EV_ABS, ABS_MT_PRESSURE);
+
+		error = input_mt_init_slots(input,
+				IQS5XX_NUM_CONTACTS, INPUT_MT_DIRECT);
+		if (error) {
+			dev_err(&client->dev,
+				"Failed to initialize slots: %d\n", error);
+			return error;
+		}
+
+		input_set_drvdata(input, iqs5xx);
+		iqs5xx->input = input;
+	}
+
+	touchscreen_parse_properties(iqs5xx->input, true, &prop);
+
+	error = iqs5xx_read_byte(client, IQS5XX_TOTAL_RX, &val);
+	if (error)
+		return error;
+	max_x_hw = (val - 1) * IQS5XX_NUM_POINTS;
+
+	error = iqs5xx_read_byte(client, IQS5XX_TOTAL_TX, &val);
+	if (error)
+		return error;
+	max_y_hw = (val - 1) * IQS5XX_NUM_POINTS;
+
+	error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val);
+	if (error)
+		return error;
+
+	if (val & IQS5XX_SWITCH_XY_AXIS)
+		swap(max_x_hw, max_y_hw);
+
+	if (prop.swap_x_y)
+		val ^= IQS5XX_SWITCH_XY_AXIS;
+
+	if (prop.invert_x)
+		val ^= prop.swap_x_y ? IQS5XX_FLIP_Y : IQS5XX_FLIP_X;
+
+	if (prop.invert_y)
+		val ^= prop.swap_x_y ? IQS5XX_FLIP_X : IQS5XX_FLIP_Y;
+
+	error = iqs5xx_write_byte(client, IQS5XX_XY_CFG0, val);
+	if (error)
+		return error;
+
+	if (prop.max_x > max_x_hw) {
+		dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
+			prop.max_x, max_x_hw);
+		return -EINVAL;
+	} else if (prop.max_x == 0) {
+		error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
+		if (error)
+			return error;
+
+		input_abs_set_max(iqs5xx->input,
+				  prop.swap_x_y ? ABS_MT_POSITION_Y :
+						  ABS_MT_POSITION_X,
+				  max_x);
+	} else {
+		max_x = (u16)prop.max_x;
+	}
+
+	if (prop.max_y > max_y_hw) {
+		dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
+			prop.max_y, max_y_hw);
+		return -EINVAL;
+	} else if (prop.max_y == 0) {
+		error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
+		if (error)
+			return error;
+
+		input_abs_set_max(iqs5xx->input,
+				  prop.swap_x_y ? ABS_MT_POSITION_X :
+						  ABS_MT_POSITION_Y,
+				  max_y);
+	} else {
+		max_y = (u16)prop.max_y;
+	}
+
+	/*
+	 * Write horizontal and vertical resolution to the device in case its
+	 * original defaults were overridden or swapped as per the properties
+	 * specified in the device tree.
+	 */
+	error = iqs5xx_write_word(client,
+				  prop.swap_x_y ? IQS5XX_Y_RES : IQS5XX_X_RES,
+				  max_x);
+	if (error)
+		return error;
+
+	return iqs5xx_write_word(client,
+				 prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
+				 max_y);
+}
+
+static int iqs5xx_dev_init(struct i2c_client *client)
+{
+	struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+	struct iqs5xx_dev_id_info *dev_id_info;
+	int error;
+	u8 val;
+	u8 buf[sizeof(*dev_id_info) + 1];
+
+	error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM,
+				  &buf[1], sizeof(*dev_id_info));
+	if (error)
+		return iqs5xx_bl_open(client);
+
+	/*
+	 * A000 and B000 devices use 8-bit and 16-bit addressing, respectively.
+	 * Querying an A000 device's version information with 16-bit addressing
+	 * gives the appearance that the data is shifted by one byte; a nonzero
+	 * leading array element suggests this could be the case (in which case
+	 * the missing zero is prepended).
+	 */
+	buf[0] = 0;
+	dev_id_info = (struct iqs5xx_dev_id_info *)&buf[(buf[1] > 0) ? 0 : 1];
+
+	switch (be16_to_cpu(dev_id_info->prod_num)) {
+	case IQS5XX_PROD_NUM_IQS550:
+	case IQS5XX_PROD_NUM_IQS572:
+	case IQS5XX_PROD_NUM_IQS525:
+		break;
+	default:
+		dev_err(&client->dev, "Unrecognized product number: %u\n",
+			be16_to_cpu(dev_id_info->prod_num));
+		return -EINVAL;
+	}
+
+	switch (be16_to_cpu(dev_id_info->proj_num)) {
+	case IQS5XX_PROJ_NUM_A000:
+		dev_err(&client->dev, "Unsupported project number: %u\n",
+			be16_to_cpu(dev_id_info->proj_num));
+		return iqs5xx_bl_open(client);
+	case IQS5XX_PROJ_NUM_B000:
+		break;
+	default:
+		dev_err(&client->dev, "Unrecognized project number: %u\n",
+			be16_to_cpu(dev_id_info->proj_num));
+		return -EINVAL;
+	}
+
+	if (dev_id_info->major_ver < IQS5XX_MAJOR_VER_MIN) {
+		dev_err(&client->dev, "Unsupported major version: %u\n",
+			dev_id_info->major_ver);
+		return iqs5xx_bl_open(client);
+	}
+
+	switch (dev_id_info->bl_status) {
+	case IQS5XX_BL_STATUS_AVAIL:
+	case IQS5XX_BL_STATUS_NONE:
+		break;
+	default:
+		dev_err(&client->dev,
+			"Unrecognized bootloader status: 0x%02X\n",
+			dev_id_info->bl_status);
+		return -EINVAL;
+	}
+
+	error = iqs5xx_axis_init(client);
+	if (error)
+		return error;
+
+	error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val);
+	if (error)
+		return error;
+
+	val |= IQS5XX_SETUP_COMPLETE;
+	val &= ~IQS5XX_SW_INPUT_EVENT;
+	error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, val);
+	if (error)
+		return error;
+
+	val = IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE;
+	error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, val);
+	if (error)
+		return error;
+
+	error = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+	if (error)
+		return error;
+
+	iqs5xx->bl_status = dev_id_info->bl_status;
+
+	/*
+	 * Closure of the first communication window that appears following the
+	 * release of reset appears to kick off an initialization period during
+	 * which further communication is met with clock stretching. The return
+	 * from this function is delayed so that further communication attempts
+	 * avoid this period.
+	 */
+	msleep(100);
+
+	return 0;
+}
+
+static irqreturn_t iqs5xx_irq(int irq, void *data)
+{
+	struct iqs5xx_private *iqs5xx = data;
+	struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
+	struct i2c_client *client = iqs5xx->client;
+	struct input_dev *input = iqs5xx->input;
+	int error, i;
+
+	/*
+	 * This check is purely a precaution, as the device does not assert the
+	 * RDY output during bootloader mode. If the device operates outside of
+	 * bootloader mode, the input device is guaranteed to be allocated.
+	 */
+	if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+		return IRQ_NONE;
+
+	error = iqs5xx_read_burst(client, IQS5XX_ABS_X,
+				  touch_data, sizeof(touch_data));
+	if (error)
+		return IRQ_NONE;
+
+	for (i = 0; i < ARRAY_SIZE(touch_data); i++) {
+		u16 pressure = be16_to_cpu(touch_data[i].strength);
+
+		input_mt_slot(input, i);
+		if (input_mt_report_slot_state(input, MT_TOOL_FINGER,
+					       pressure != 0)) {
+			input_report_abs(input, ABS_MT_POSITION_X,
+					 be16_to_cpu(touch_data[i].abs_x));
+			input_report_abs(input, ABS_MT_POSITION_Y,
+					 be16_to_cpu(touch_data[i].abs_y));
+			input_report_abs(input, ABS_MT_PRESSURE, pressure);
+		}
+	}
+
+	input_mt_sync_frame(input);
+	input_sync(input);
+
+	error = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
+	if (error)
+		return IRQ_NONE;
+
+	/*
+	 * Once the communication window is closed, a small delay is added to
+	 * ensure the device's RDY output has been deasserted by the time the
+	 * interrupt handler returns.
+	 */
+	usleep_range(50, 100);
+
+	return IRQ_HANDLED;
+}
+
+static int iqs5xx_fw_file_parse(struct i2c_client *client,
+				const char *fw_file, u8 *pmap)
+{
+	const struct firmware *fw;
+	struct iqs5xx_ihex_rec *rec;
+	size_t pos = 0;
+	int error, i;
+	u16 rec_num = 1;
+	u16 rec_addr;
+	u8 rec_len, rec_type, rec_chksm, chksm;
+	u8 rec_hdr[IQS5XX_REC_HDR_LEN];
+	u8 rec_data[IQS5XX_REC_LEN_MAX];
+
+	/*
+	 * Firmware exported from the vendor's configuration tool deviates from
+	 * standard ihex as follows: (1) the checksum for records corresponding
+	 * to user-exported settings is not recalculated, and (2) an address of
+	 * 0xFFFF is used for the EOF record.
+	 *
+	 * Because the ihex2fw tool tolerates neither (1) nor (2), the slightly
+	 * nonstandard ihex firmware is parsed directly by the driver.
+	 */
+	error = request_firmware(&fw, fw_file, &client->dev);
+	if (error) {
+		dev_err(&client->dev, "Failed to request firmware %s: %d\n",
+			fw_file, error);
+		return error;
+	}
+
+	do {
+		if (pos + sizeof(*rec) > fw->size) {
+			dev_err(&client->dev, "Insufficient firmware size\n");
+			error = -EINVAL;
+			break;
+		}
+		rec = (struct iqs5xx_ihex_rec *)(fw->data + pos);
+		pos += sizeof(*rec);
+
+		if (rec->start != ':') {
+			dev_err(&client->dev, "Invalid start at record %u\n",
+				rec_num);
+			error = -EINVAL;
+			break;
+		}
+
+		error = hex2bin(rec_hdr, rec->len, sizeof(rec_hdr));
+		if (error) {
+			dev_err(&client->dev, "Invalid header at record %u\n",
+				rec_num);
+			break;
+		}
+
+		rec_len = *rec_hdr;
+		rec_addr = get_unaligned_be16(rec_hdr + sizeof(rec_len));
+		rec_type = *(rec_hdr + sizeof(rec_len) + sizeof(rec_addr));
+
+		if (pos + rec_len * 2 > fw->size) {
+			dev_err(&client->dev, "Insufficient firmware size\n");
+			error = -EINVAL;
+			break;
+		}
+		pos += (rec_len * 2);
+
+		error = hex2bin(rec_data, rec->data, rec_len);
+		if (error) {
+			dev_err(&client->dev, "Invalid data at record %u\n",
+				rec_num);
+			break;
+		}
+
+		error = hex2bin(&rec_chksm,
+				rec->data + rec_len * 2, sizeof(rec_chksm));
+		if (error) {
+			dev_err(&client->dev, "Invalid checksum at record %u\n",
+				rec_num);
+			break;
+		}
+
+		chksm = 0;
+		for (i = 0; i < sizeof(rec_hdr); i++)
+			chksm += rec_hdr[i];
+		for (i = 0; i < rec_len; i++)
+			chksm += rec_data[i];
+		chksm = ~chksm + 1;
+
+		if (chksm != rec_chksm && rec_addr < IQS5XX_CSTM) {
+			dev_err(&client->dev,
+				"Incorrect checksum at record %u\n",
+				rec_num);
+			error = -EINVAL;
+			break;
+		}
+
+		switch (rec_type) {
+		case IQS5XX_REC_TYPE_DATA:
+			if (rec_addr < IQS5XX_CHKSM ||
+			    rec_addr > IQS5XX_PMAP_END) {
+				dev_err(&client->dev,
+					"Invalid address at record %u\n",
+					rec_num);
+				error = -EINVAL;
+			} else {
+				memcpy(pmap + rec_addr - IQS5XX_CHKSM,
+				       rec_data, rec_len);
+			}
+			break;
+		case IQS5XX_REC_TYPE_EOF:
+			break;
+		default:
+			dev_err(&client->dev, "Invalid type at record %u\n",
+				rec_num);
+			error = -EINVAL;
+		}
+
+		if (error)
+			break;
+
+		rec_num++;
+		while (pos < fw->size) {
+			if (*(fw->data + pos) == ':')
+				break;
+			pos++;
+		}
+	} while (rec_type != IQS5XX_REC_TYPE_EOF);
+
+	release_firmware(fw);
+
+	return error;
+}
+
+static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
+{
+	struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
+	int error;
+	u8 *pmap;
+
+	if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE)
+		return -EPERM;
+
+	pmap = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
+	if (!pmap)
+		return -ENOMEM;
+
+	error = iqs5xx_fw_file_parse(client, fw_file, pmap);
+	if (error)
+		goto err_kfree;
+
+	mutex_lock(&iqs5xx->lock);
+
+	/*
+	 * Disable the interrupt line in case the first attempt(s) to enter the
+	 * bootloader don't happen quickly enough, in which case the device may
+	 * assert the RDY output until the next attempt.
+	 */
+	disable_irq(client->irq);
+
+	iqs5xx->bl_status = IQS5XX_BL_STATUS_RESET;
+
+	error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
+	if (error) {
+		error = iqs5xx_bl_open(client);
+		if (error)
+			goto err_reset;
+	}
+
+	error = iqs5xx_bl_write(client, IQS5XX_CHKSM, pmap, IQS5XX_PMAP_LEN);
+	if (error)
+		goto err_reset;
+
+	error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_CRC, 0);
+	if (error)
+		goto err_reset;
+
+	error = iqs5xx_bl_verify(client, IQS5XX_CSTM,
+				 pmap + IQS5XX_CHKSM_LEN + IQS5XX_APP_LEN,
+				 IQS5XX_CSTM_LEN);
+	if (error)
+		goto err_reset;
+
+	error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_EXEC, 0);
+
+err_reset:
+	if (error) {
+		iqs5xx_reset(client);
+		usleep_range(10000, 10100);
+	}
+
+	error = iqs5xx_dev_init(client);
+	if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
+		error = -EINVAL;
+
+	enable_irq(client->irq);
+
+	mutex_unlock(&iqs5xx->lock);
+
+err_kfree:
+	kfree(pmap);
+
+	return error;
+}
+
+static ssize_t fw_file_store(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+	struct i2c_client *client = iqs5xx->client;
+	size_t len = count;
+	bool input_reg = !iqs5xx->input;
+	char fw_file[IQS5XX_FW_FILE_LEN + 1];
+	int error;
+
+	if (!len)
+		return -EINVAL;
+
+	if (buf[len - 1] == '\n')
+		len--;
+
+	if (len > IQS5XX_FW_FILE_LEN)
+		return -ENAMETOOLONG;
+
+	memcpy(fw_file, buf, len);
+	fw_file[len] = '\0';
+
+	error = iqs5xx_fw_file_write(client, fw_file);
+	if (error)
+		return error;
+
+	/*
+	 * If the input device was not allocated already, it is guaranteed to
+	 * be allocated by this point and can finally be registered.
+	 */
+	if (input_reg) {
+		error = input_register_device(iqs5xx->input);
+		if (error) {
+			dev_err(&client->dev,
+				"Failed to register device: %d\n",
+				error);
+			return error;
+		}
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR_WO(fw_file);
+
+static struct attribute *iqs5xx_attrs[] = {
+	&dev_attr_fw_file.attr,
+	NULL,
+};
+
+static const struct attribute_group iqs5xx_attr_group = {
+	.attrs = iqs5xx_attrs,
+};
+
+static int __maybe_unused iqs5xx_suspend(struct device *dev)
+{
+	struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+	struct input_dev *input = iqs5xx->input;
+	int error = 0;
+
+	if (!input)
+		return error;
+
+	mutex_lock(&input->mutex);
+
+	if (input->users)
+		error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
+
+	mutex_unlock(&input->mutex);
+
+	return error;
+}
+
+static int __maybe_unused iqs5xx_resume(struct device *dev)
+{
+	struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
+	struct input_dev *input = iqs5xx->input;
+	int error = 0;
+
+	if (!input)
+		return error;
+
+	mutex_lock(&input->mutex);
+
+	if (input->users)
+		error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
+
+	mutex_unlock(&input->mutex);
+
+	return error;
+}
+
+static SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
+
+static int iqs5xx_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct iqs5xx_private *iqs5xx;
+	int error;
+
+	iqs5xx = devm_kzalloc(&client->dev, sizeof(*iqs5xx), GFP_KERNEL);
+	if (!iqs5xx)
+		return -ENOMEM;
+
+	dev_set_drvdata(&client->dev, iqs5xx);
+
+	i2c_set_clientdata(client, iqs5xx);
+	iqs5xx->client = client;
+
+	iqs5xx->reset_gpio = devm_gpiod_get(&client->dev,
+					    "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(iqs5xx->reset_gpio)) {
+		error = PTR_ERR(iqs5xx->reset_gpio);
+		dev_err(&client->dev, "Failed to request GPIO: %d\n", error);
+		return error;
+	}
+
+	mutex_init(&iqs5xx->lock);
+
+	iqs5xx_reset(client);
+	usleep_range(10000, 10100);
+
+	error = iqs5xx_dev_init(client);
+	if (error)
+		return error;
+
+	error = devm_request_threaded_irq(&client->dev, client->irq,
+					  NULL, iqs5xx_irq, IRQF_ONESHOT,
+					  client->name, iqs5xx);
+	if (error) {
+		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+		return error;
+	}
+
+	error = devm_device_add_group(&client->dev, &iqs5xx_attr_group);
+	if (error) {
+		dev_err(&client->dev, "Failed to add attributes: %d\n", error);
+		return error;
+	}
+
+	if (iqs5xx->input) {
+		error = input_register_device(iqs5xx->input);
+		if (error)
+			dev_err(&client->dev,
+				"Failed to register device: %d\n",
+				error);
+	}
+
+	return error;
+}
+
+static const struct i2c_device_id iqs5xx_id[] = {
+	{ "iqs550", 0 },
+	{ "iqs572", 1 },
+	{ "iqs525", 2 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, iqs5xx_id);
+
+static const struct of_device_id iqs5xx_of_match[] = {
+	{ .compatible = "azoteq,iqs550" },
+	{ .compatible = "azoteq,iqs572" },
+	{ .compatible = "azoteq,iqs525" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, iqs5xx_of_match);
+
+static struct i2c_driver iqs5xx_i2c_driver = {
+	.driver = {
+		.name		= "iqs5xx",
+		.of_match_table	= iqs5xx_of_match,
+		.pm		= &iqs5xx_pm,
+	},
+	.id_table	= iqs5xx_id,
+	.probe		= iqs5xx_probe,
+};
+module_i2c_driver(iqs5xx_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS550/572/525 Trackpad/Touchscreen Controller");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index bc5054e51bef..4badaff0f548 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -606,6 +606,7 @@
 #define KEY_SCREENSAVER		0x245	/* AL Screen Saver */
 #define KEY_VOICECOMMAND		0x246	/* Listening Voice Command */
 #define KEY_ASSISTANT		0x247	/* AL Context-aware desktop assistant */
+#define KEY_KBD_LAYOUT_NEXT	0x248	/* AC Next Keyboard Layout Select */
 
 #define KEY_BRIGHTNESS_MIN		0x250	/* Set Brightness to Minimum */
 #define KEY_BRIGHTNESS_MAX		0x251	/* Set Brightness to Maximum */