Merge tag 'v6.4' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 17 Jul 2023 16:20:46 +0000 (09:20 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 17 Jul 2023 16:20:46 +0000 (09:20 -0700)
Sync up with mainline to bring in updates to shared infrastructure.

148 files changed:
Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml
Documentation/devicetree/bindings/input/cypress,cyapa.txt [deleted file]
Documentation/devicetree/bindings/input/cypress,cyapa.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/pwm-vibrator.yaml
Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/cypress,tt21000.yaml
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml
Documentation/input/devices/xpad.rst
Documentation/input/gamepad.rst
MAINTAINERS
drivers/input/Kconfig
drivers/input/gameport/Kconfig
drivers/input/gameport/gameport.c
drivers/input/input.c
drivers/input/joystick/Kconfig
drivers/input/joystick/as5011.c
drivers/input/joystick/qwiic-joystick.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/adp5589-keys.c
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/bcm-keypad.c
drivers/input/keyboard/cap11xx.c
drivers/input/keyboard/cypress-sf.c
drivers/input/keyboard/dlink-dir685-touchkeys.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/lm8333.c
drivers/input/keyboard/lpc32xx-keys.c
drivers/input/keyboard/max7359_keypad.c
drivers/input/keyboard/mcs_touchkey.c
drivers/input/keyboard/mpr121_touchkey.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/keyboard/nspire-keypad.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/keyboard/opencores-kbd.c
drivers/input/keyboard/pinephone-keyboard.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/keyboard/qt1050.c
drivers/input/keyboard/qt1070.c
drivers/input/keyboard/qt2160.c
drivers/input/keyboard/sun4i-lradc-keys.c
drivers/input/keyboard/tca6416-keypad.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/keyboard/tm2-touchkey.c
drivers/input/misc/Kconfig
drivers/input/misc/ad714x-i2c.c
drivers/input/misc/adxl34x-i2c.c
drivers/input/misc/adxl34x.c
drivers/input/misc/apanel.c
drivers/input/misc/atmel_captouch.c
drivers/input/misc/bma150.c
drivers/input/misc/cma3000_d0x_i2c.c
drivers/input/misc/da7280.c
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c
drivers/input/misc/drv2667.c
drivers/input/misc/gpio-vibra.c
drivers/input/misc/ibm-panel.c
drivers/input/misc/iqs269a.c
drivers/input/misc/iqs626a.c
drivers/input/misc/iqs7222.c
drivers/input/misc/kxtj9.c
drivers/input/misc/mma8450.c
drivers/input/misc/pcf8574_keypad.c
drivers/input/misc/pm8941-pwrkey.c
drivers/input/misc/pwm-beeper.c
drivers/input/misc/pwm-vibra.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/tps65219-pwrbutton.c
drivers/input/misc/uinput.c
drivers/input/mouse/cyapa.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics_i2c.c
drivers/input/mouse/trackpoint.c
drivers/input/rmi4/rmi_i2c.c
drivers/input/rmi4/rmi_smbus.c
drivers/input/serio/Kconfig
drivers/input/serio/libps2.c
drivers/input/tests/input_test.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7879-i2c.c
drivers/input/touchscreen/ar1021_i2c.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/auo-pixcir-ts.c
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/bu21029_ts.c
drivers/input/touchscreen/chipone_icn8318.c
drivers/input/touchscreen/chipone_icn8505.c
drivers/input/touchscreen/cy8ctma140.c
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/cyttsp4_core.c
drivers/input/touchscreen/cyttsp4_i2c.c
drivers/input/touchscreen/cyttsp5.c
drivers/input/touchscreen/cyttsp_i2c.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/eeti_ts.c
drivers/input/touchscreen/egalax_ts.c
drivers/input/touchscreen/ektf2127.c
drivers/input/touchscreen/elants_i2c.c
drivers/input/touchscreen/exc3000.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/hideep.c
drivers/input/touchscreen/himax_hx83112b.c
drivers/input/touchscreen/hycon-hy46xx.c
drivers/input/touchscreen/hynitron_cstxxx.c
drivers/input/touchscreen/ili210x.c
drivers/input/touchscreen/ilitek_ts_i2c.c
drivers/input/touchscreen/imagis.c
drivers/input/touchscreen/iqs5xx.c
drivers/input/touchscreen/iqs7211.c [new file with mode: 0644]
drivers/input/touchscreen/lpc32xx_ts.c
drivers/input/touchscreen/max11801_ts.c
drivers/input/touchscreen/mcs5000_ts.c
drivers/input/touchscreen/melfas_mip4.c
drivers/input/touchscreen/migor_ts.c
drivers/input/touchscreen/mms114.c
drivers/input/touchscreen/msg2638.c
drivers/input/touchscreen/novatek-nvt-ts.c
drivers/input/touchscreen/pixcir_i2c_ts.c
drivers/input/touchscreen/raydium_i2c_ts.c
drivers/input/touchscreen/resistive-adc-touch.c
drivers/input/touchscreen/rohm_bu21023.c
drivers/input/touchscreen/s6sy761.c
drivers/input/touchscreen/silead.c
drivers/input/touchscreen/sis_i2c.c
drivers/input/touchscreen/st1232.c
drivers/input/touchscreen/stmfts.c
drivers/input/touchscreen/surface3_spi.c
drivers/input/touchscreen/sx8654.c
drivers/input/touchscreen/tsc2004.c
drivers/input/touchscreen/tsc2007_core.c
drivers/input/touchscreen/wacom_i2c.c
drivers/input/touchscreen/wdt87xx_i2c.c
drivers/input/touchscreen/zet6223.c
drivers/input/touchscreen/zforce_ts.c
drivers/input/touchscreen/zinitix.c
include/linux/gameport.h
include/linux/i8042.h
include/linux/libps2.h

index 3ec579d..c407993 100644 (file)
@@ -14,6 +14,9 @@ description: |
   Atmel maXTouch touchscreen or touchpads such as the mXT244
   and similar devices.
 
+allOf:
+  - $ref: input.yaml#
+
 properties:
   compatible:
     const: atmel,maxtouch
@@ -60,6 +63,10 @@ properties:
       or experiment to determine which bit corresponds to which input. Use
       KEY_RESERVED for unused padding values.
 
+  linux,keycodes:
+    minItems: 1
+    maxItems: 8
+
   atmel,wakeup-method:
     $ref: /schemas/types.yaml#/definitions/uint32
     description: |
index 9ddba7f..5b1769c 100644 (file)
@@ -4,14 +4,14 @@
 $id: http://devicetree.org/schemas/input/azoteq,iqs7222.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Azoteq IQS7222A/B/C Capacitive Touch Controller
+title: Azoteq IQS7222A/B/C/D Capacitive Touch Controller
 
 maintainers:
   - Jeff LaBundy <jeff@labundy.com>
 
 description: |
-  The Azoteq IQS7222A, IQS7222B and IQS7222C are multichannel capacitive touch
-  controllers that feature additional sensing capabilities.
+  The Azoteq IQS7222A, IQS7222B, IQS7222C and IQS7222D are multichannel
+  capacitive touch controllers that feature additional sensing capabilities.
 
   Link to datasheets: https://www.azoteq.com/
 
@@ -21,6 +21,7 @@ properties:
       - azoteq,iqs7222a
       - azoteq,iqs7222b
       - azoteq,iqs7222c
+      - azoteq,iqs7222d
 
   reg:
     maxItems: 1
@@ -173,6 +174,152 @@ properties:
     maximum: 3000
     description: Specifies the report rate (in ms) during ultra-low-power mode.
 
+  touchscreen-size-x: true
+  touchscreen-size-y: true
+  touchscreen-inverted-x: true
+  touchscreen-inverted-y: true
+  touchscreen-swapped-x-y: true
+
+  trackpad:
+    type: object
+    description: Represents all channels associated with the trackpad.
+
+    properties:
+      azoteq,channel-select:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        maxItems: 12
+        items:
+          minimum: 0
+          maximum: 13
+        description:
+          Specifies the order of the channels that participate in the trackpad.
+          Specify 255 to omit a given channel for the purpose of mapping a non-
+          rectangular trackpad.
+
+      azoteq,num-rows:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 1
+        maximum: 12
+        description: Specifies the number of rows that comprise the trackpad.
+
+      azoteq,num-cols:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 1
+        maximum: 12
+        description: Specifies the number of columns that comprise the trackpad.
+
+      azoteq,top-speed:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        multipleOf: 4
+        minimum: 0
+        maximum: 1020
+        description:
+          Specifies the speed (in coordinates traveled per conversion) after
+          which coordinate filtering is no longer applied.
+
+      azoteq,bottom-speed:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description:
+          Specifies the speed (in coordinates traveled per conversion) after
+          which coordinate filtering is linearly reduced.
+
+      azoteq,use-prox:
+        type: boolean
+        description:
+          Directs the trackpad to respond to the proximity states of the
+          selected channels instead of their corresponding touch states.
+          Note the trackpad cannot report granular coordinates during a
+          state of proximity.
+
+    patternProperties:
+      "^azoteq,lower-cal-(x|y)$":
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the trackpad's lower starting points.
+
+      "^azoteq,upper-cal-(x|y)$":
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the trackpad's upper starting points.
+
+      "^event-(press|tap|(swipe|flick)-(x|y)-(pos|neg))$":
+        type: object
+        $ref: input.yaml#
+        description:
+          Represents a press or gesture event reported by the trackpad. Specify
+          'linux,code' under the press event to report absolute coordinates.
+
+        properties:
+          linux,code: true
+
+          azoteq,gesture-angle-tighten:
+            type: boolean
+            description:
+              Limits the tangent of the gesture angle to 0.5 (axial gestures
+              only). If specified in one direction, the effect is applied in
+              either direction.
+
+          azoteq,gesture-max-ms:
+            multipleOf: 16
+            minimum: 0
+            maximum: 4080
+            description:
+              Specifies the length of time (in ms) within which a tap, swipe
+              or flick gesture must be completed in order to be acknowledged
+              by the device. The number specified for any one swipe or flick
+              gesture applies to all other swipe or flick gestures.
+
+          azoteq,gesture-min-ms:
+            multipleOf: 16
+            minimum: 0
+            maximum: 4080
+            description:
+              Specifies the length of time (in ms) for which a tap gesture must
+              be held in order to be acknowledged by the device.
+
+          azoteq,gesture-dist:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            minimum: 0
+            maximum: 65535
+            description:
+              Specifies the distance (in coordinates) across which a swipe or
+              flick gesture must travel in order to be acknowledged by the
+              device. The number specified for any one swipe or flick gesture
+              applies to all remaining swipe or flick gestures.
+
+              For tap gestures, this property specifies the distance from the
+              original point of contact across which the contact is permitted
+              to travel before the gesture is rejected by the device.
+
+          azoteq,gpio-select:
+            $ref: /schemas/types.yaml#/definitions/uint32-array
+            minItems: 1
+            maxItems: 3
+            items:
+              minimum: 0
+              maximum: 2
+            description: |
+              Specifies one or more GPIO mapped to the event as follows:
+              0: GPIO0
+              1: GPIO3
+              2: GPIO4
+
+              Note that although multiple events can be mapped to a single
+              GPIO, they must all be of the same type (proximity, touch or
+              trackpad gesture).
+
+        additionalProperties: false
+
+    required:
+      - azoteq,channel-select
+
+    additionalProperties: false
+
 patternProperties:
   "^cycle-[0-9]$":
     type: object
@@ -288,6 +435,10 @@ patternProperties:
           Activates the reference channel in response to proximity events
           instead of touch events.
 
+      azoteq,counts-filt-enable:
+        type: boolean
+        description: Applies counts filtering to the channel.
+
       azoteq,ati-band:
         $ref: /schemas/types.yaml#/definitions/uint32
         enum: [0, 1, 2, 3]
@@ -432,12 +583,12 @@ patternProperties:
             description: |
               Specifies one or more GPIO mapped to the event as follows:
               0: GPIO0
-              1: GPIO3 (IQS7222C only)
-              2: GPIO4 (IQS7222C only)
+              1: GPIO3
+              2: GPIO4
 
               Note that although multiple events can be mapped to a single
               GPIO, they must all be of the same type (proximity, touch or
-              slider gesture).
+              slider/trackpad gesture).
 
           azoteq,thresh:
             $ref: /schemas/types.yaml#/definitions/uint32
@@ -521,16 +672,16 @@ patternProperties:
         minimum: 0
         maximum: 65535
         description:
-          Specifies the speed of movement after which coordinate filtering is
-          no longer applied.
+          Specifies the speed (in coordinates traveled per conversion) after
+          which coordinate filtering is no longer applied.
 
       azoteq,bottom-speed:
         $ref: /schemas/types.yaml#/definitions/uint32
         minimum: 0
         maximum: 255
         description:
-          Specifies the speed of movement after which coordinate filtering is
-          linearly reduced.
+          Specifies the speed (in coordinates traveled per conversion) after
+          which coordinate filtering is linearly reduced.
 
       azoteq,bottom-beta:
         $ref: /schemas/types.yaml#/definitions/uint32
@@ -595,10 +746,10 @@ patternProperties:
             minimum: 0
             maximum: 4080
             description:
-              Specifies the distance across which a swipe or flick gesture must
-              travel in order to be acknowledged by the device. The number spec-
-              ified for any one swipe or flick gesture applies to all remaining
-              swipe or flick gestures.
+              Specifies the distance (in coordinates) across which a swipe or
+              flick gesture must travel in order to be acknowledged by the
+              device. The number specified for any one swipe or flick gesture
+              applies to all remaining swipe or flick gestures.
 
           azoteq,gpio-select:
             $ref: /schemas/types.yaml#/definitions/uint32-array
@@ -610,8 +761,8 @@ patternProperties:
             description: |
               Specifies one or more GPIO mapped to the event as follows:
               0: GPIO0
-              1: GPIO3 (IQS7222C only)
-              2: GPIO4 (IQS7222C only)
+              1: GPIO3
+              2: GPIO4
 
               Note that although multiple events can be mapped to a single
               GPIO, they must all be of the same type (proximity, touch or
@@ -629,8 +780,8 @@ patternProperties:
     description: |
       Represents a GPIO mapped to one or more events as follows:
       gpio-0: GPIO0
-      gpio-1: GPIO3 (IQS7222C only)
-      gpio-2: GPIO4 (IQS7222C only)
+      gpio-1: GPIO3
+      gpio-2: GPIO4
 
     allOf:
       - $ref: ../pinctrl/pincfg-node.yaml#
@@ -641,11 +792,53 @@ patternProperties:
     additionalProperties: false
 
 allOf:
+  - $ref: touchscreen/touchscreen.yaml#
+
   - if:
       properties:
         compatible:
           contains:
-            const: azoteq,iqs7222b
+            enum:
+              - azoteq,iqs7222a
+              - azoteq,iqs7222b
+              - azoteq,iqs7222c
+
+    then:
+      properties:
+        touchscreen-size-x: false
+        touchscreen-size-y: false
+        touchscreen-inverted-x: false
+        touchscreen-inverted-y: false
+        touchscreen-swapped-x-y: false
+
+        trackpad: false
+
+      patternProperties:
+        "^channel-([0-9]|1[0-9])$":
+          properties:
+            azoteq,counts-filt-enable: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - azoteq,iqs7222b
+              - azoteq,iqs7222c
+
+    then:
+      patternProperties:
+        "^channel-([0-9]|1[0-9])$":
+          properties:
+            azoteq,ulp-allow: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - azoteq,iqs7222b
+              - azoteq,iqs7222d
 
     then:
       patternProperties:
@@ -657,13 +850,22 @@ allOf:
           properties:
             azoteq,ref-select: false
 
+        "^slider-[0-1]$": false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: azoteq,iqs7222b
+
+    then:
+      patternProperties:
+        "^channel-([0-9]|1[0-9])$":
           patternProperties:
             "^event-(prox|touch)$":
               properties:
                 azoteq,gpio-select: false
 
-        "^slider-[0-1]$": false
-
         "^gpio-[0-2]$": false
 
   - if:
@@ -704,10 +906,6 @@ allOf:
 
     else:
       patternProperties:
-        "^channel-([0-9]|1[0-9])$":
-          properties:
-            azoteq,ulp-allow: false
-
         "^slider-[0-1]$":
           patternProperties:
             "^event-(press|tap|(swipe|flick)-(pos|neg))$":
diff --git a/Documentation/devicetree/bindings/input/cypress,cyapa.txt b/Documentation/devicetree/bindings/input/cypress,cyapa.txt
deleted file mode 100644 (file)
index d3db659..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-Cypress I2C Touchpad
-
-Required properties:
-- compatible: must be "cypress,cyapa".
-- reg: I2C address of the chip.
-- interrupts: interrupt to which the chip is connected (see interrupt
-       binding[0]).
-
-Optional properties:
-- wakeup-source: touchpad can be used as a wakeup source.
-- pinctrl-names: should be "default" (see pinctrl binding [1]).
-- pinctrl-0: a phandle pointing to the pin settings for the device (see
-       pinctrl binding [1]).
-- vcc-supply: a phandle for the regulator supplying 3.3V power.
-
-[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
-[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
-
-Example:
-       &i2c0 {
-               /* ... */
-
-               /* Cypress Gen3 touchpad */
-               touchpad@67 {
-                       compatible = "cypress,cyapa";
-                       reg = <0x67>;
-                       interrupt-parent = <&gpio>;
-                       interrupts = <2 IRQ_TYPE_EDGE_FALLING>; /* GPIO 2 */
-                       wakeup-source;
-               };
-
-               /* Cypress Gen5 and later touchpad */
-               touchpad@24 {
-                       compatible = "cypress,cyapa";
-                       reg = <0x24>;
-                       interrupt-parent = <&gpio>;
-                       interrupts = <2 IRQ_TYPE_EDGE_FALLING>; /* GPIO 2 */
-                       wakeup-source;
-               };
-
-               /* ... */
-       };
diff --git a/Documentation/devicetree/bindings/input/cypress,cyapa.yaml b/Documentation/devicetree/bindings/input/cypress,cyapa.yaml
new file mode 100644 (file)
index 0000000..2951515
--- /dev/null
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/cypress,cyapa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cypress All Points Addressable (APA) I2C Touchpad / Trackpad
+
+maintainers:
+  - Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+properties:
+  compatible:
+    const: cypress,cyapa
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  wakeup-source: true
+
+  vcc-supply:
+    description: 3.3V power
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        trackpad@67 {
+            reg = <0x67>;
+            compatible = "cypress,cyapa";
+            interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+            interrupt-parent = <&gpx1>;
+            wakeup-source;
+        };
+    };
index d32716c..6398534 100644 (file)
@@ -32,6 +32,8 @@ properties:
     minItems: 1
     maxItems: 2
 
+  enable-gpios: true
+
   vcc-supply: true
 
   direction-duty-cycle-ns:
diff --git a/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml b/Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml
new file mode 100644 (file)
index 0000000..8cf371b
--- /dev/null
@@ -0,0 +1,769 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/azoteq,iqs7211.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller
+
+maintainers:
+  - Jeff LaBundy <jeff@labundy.com>
+
+description: |
+  The Azoteq IQS7210A, IQS7211A and IQS7211E trackpad and touchscreen control-
+  lers employ projected-capacitance sensing and can track two contacts.
+
+  Link to datasheets: https://www.azoteq.com/
+
+properties:
+  compatible:
+    enum:
+      - azoteq,iqs7210a
+      - azoteq,iqs7211a
+      - azoteq,iqs7211e
+
+  reg:
+    maxItems: 1
+
+  irq-gpios:
+    maxItems: 1
+    description:
+      Specifies the GPIO connected to the device's active-low RDY output. The
+      pin doubles as the IQS7211E's active-low MCLR input, in which case this
+      GPIO must be configured as open-drain.
+
+  reset-gpios:
+    maxItems: 1
+    description:
+      Specifies the GPIO connected to the device's active-low MCLR input. The
+      device is temporarily held in hardware reset prior to initialization if
+      this property is present.
+
+  azoteq,forced-comms:
+    type: boolean
+    description:
+      Enables forced communication; to be used with host adapters that cannot
+      tolerate clock stretching.
+
+  azoteq,forced-comms-default:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1]
+    description:
+      Indicates if the device's OTP memory enables (1) or disables (0) forced
+      communication by default. Specifying this property can expedite startup
+      time if the default value is known.
+
+      If this property is not specified, communication is not initiated until
+      the device asserts its RDY pin shortly after exiting hardware reset. At
+      that point, forced communication is either enabled or disabled based on
+      the presence or absence of the 'azoteq,forced-comms' property.
+
+  azoteq,rate-active-ms:
+    minimum: 0
+    maximum: 65535
+    description: Specifies the report rate (in ms) during active mode.
+
+  azoteq,rate-touch-ms:
+    minimum: 0
+    maximum: 65535
+    description: Specifies the report rate (in ms) during idle-touch mode.
+
+  azoteq,rate-idle-ms:
+    minimum: 0
+    maximum: 65535
+    description: Specifies the report rate (in ms) during idle mode.
+
+  azoteq,rate-lp1-ms:
+    minimum: 0
+    maximum: 65535
+    description: Specifies the report rate (in ms) during low-power mode 1.
+
+  azoteq,rate-lp2-ms:
+    minimum: 0
+    maximum: 65535
+    description: Specifies the report rate (in ms) during low-power mode 2.
+
+  azoteq,timeout-active-ms:
+    multipleOf: 1000
+    minimum: 0
+    maximum: 65535000
+    description:
+      Specifies the length of time (in ms) to wait for an event before moving
+      from active mode to idle or idle-touch modes.
+
+  azoteq,timeout-touch-ms:
+    multipleOf: 1000
+    minimum: 0
+    maximum: 65535000
+    description:
+      Specifies the length of time (in ms) to wait for an event before moving
+      from idle-touch mode to idle mode.
+
+  azoteq,timeout-idle-ms:
+    multipleOf: 1000
+    minimum: 0
+    maximum: 65535000
+    description:
+      Specifies the length of time (in ms) to wait for an event before moving
+      from idle mode to low-power mode 1.
+
+  azoteq,timeout-lp1-ms:
+    multipleOf: 1000
+    minimum: 0
+    maximum: 65535000
+    description:
+      Specifies the length of time (in ms) to wait for an event before moving
+      from low-power mode 1 to low-power mode 2.
+
+  azoteq,timeout-lp2-ms:
+    multipleOf: 1000
+    minimum: 0
+    maximum: 60000
+    description:
+      Specifies the rate (in ms) at which the trackpad reference values
+      are updated during low-power modes 1 and 2.
+
+  azoteq,timeout-ati-ms:
+    multipleOf: 1000
+    minimum: 0
+    maximum: 60000
+    description:
+      Specifies the delay (in ms) before the automatic tuning implementation
+      (ATI) is retried in the event it fails to complete.
+
+  azoteq,timeout-comms-ms:
+    minimum: 0
+    maximum: 65535
+    description:
+      Specifies the delay (in ms) before a communication window is closed.
+
+  azoteq,timeout-press-ms:
+    multipleOf: 1000
+    minimum: 0
+    maximum: 60000
+    description:
+      Specifies the length of time (in ms) to wait before automatically
+      releasing a press event. Specify zero to allow the press state to
+      persist indefinitely.
+
+  azoteq,fosc-freq:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [0, 1]
+    description: |
+      Specifies the device's core clock frequency as follows:
+      0: 14 MHz
+      1: 18 MHz
+
+  azoteq,fosc-trim:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 15
+    description: Specifies the device's core clock frequency trim.
+
+  azoteq,num-contacts:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 2
+    default: 0
+    description: Specifies the number of contacts reported by the device.
+
+  azoteq,contact-split:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 255
+    description: Specifies the contact (finger) split factor.
+
+  azoteq,trim-x:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 255
+    description: Specifies the horizontal trim width.
+
+  azoteq,trim-y:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 255
+    description: Specifies the vertical trim height.
+
+  trackpad:
+    type: object
+    description: Represents all channels associated with the trackpad.
+
+    properties:
+      azoteq,rx-enable:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        maxItems: 8
+        items:
+          minimum: 0
+          maximum: 7
+        description:
+          Specifies the order of the CRx pin(s) associated with the trackpad.
+
+      azoteq,tx-enable:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        maxItems: 12
+        items:
+          minimum: 0
+          maximum: 11
+        description:
+          Specifies the order of the CTx pin(s) associated with the trackpad.
+
+      azoteq,channel-select:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        maxItems: 36
+        items:
+          minimum: 0
+          maximum: 255
+        description: |
+          Specifies the channels mapped to each cycle in the following order:
+          Cycle 0, slot 0
+          Cycle 0, slot 1
+          Cycle 1, slot 0
+          Cycle 1, slot 1
+          ...and so on. Specify 255 to disable a given slot.
+
+      azoteq,ati-frac-div-fine:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the trackpad's ATI fine fractional divider.
+
+      azoteq,ati-frac-mult-coarse:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 15
+        description: Specifies the trackpad's ATI coarse fractional multiplier.
+
+      azoteq,ati-frac-div-coarse:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the trackpad's ATI coarse fractional divider.
+
+      azoteq,ati-comp-div:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the trackpad's ATI compensation divider.
+
+      azoteq,ati-target:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 65535
+        description: Specifies the trackpad's ATI target.
+
+      azoteq,touch-enter:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the trackpad's touch entrance factor.
+
+      azoteq,touch-exit:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the trackpad's touch exit factor.
+
+      azoteq,thresh:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the trackpad's stationary touch threshold.
+
+      azoteq,conv-period:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the trackpad's conversion period.
+
+      azoteq,conv-frac:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the trackpad's conversion frequency fraction.
+
+    patternProperties:
+      "^event-(tap(-double|-triple)?|hold|palm|swipe-(x|y)-(pos|neg)(-hold)?)$":
+        type: object
+        $ref: ../input.yaml#
+        description:
+          Represents a gesture event reported by the trackpad. In the case of
+          axial gestures, the duration or distance specified in one direction
+          applies to both directions along the same axis.
+
+        properties:
+          linux,code: true
+
+          azoteq,gesture-max-ms:
+            minimum: 0
+            maximum: 65535
+            description: Specifies the maximum duration of tap/swipe gestures.
+
+          azoteq,gesture-mid-ms:
+            minimum: 0
+            maximum: 65535
+            description:
+              Specifies the maximum duration between subsequent tap gestures
+              (IQS7211E only).
+
+          azoteq,gesture-min-ms:
+            minimum: 0
+            maximum: 65535
+            description: Specifies the minimum duration of hold gestures.
+
+          azoteq,gesture-dist:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            minimum: 0
+            maximum: 65535
+            description:
+              Specifies the minimum (swipe) or maximum (tap and hold) distance
+              a finger may travel to be considered a gesture.
+
+          azoteq,gesture-dist-rep:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            minimum: 0
+            maximum: 65535
+            description:
+              Specifies the minimum distance a finger must travel to elicit a
+              repeated swipe gesture (IQS7211E only).
+
+          azoteq,gesture-angle:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            minimum: 0
+            maximum: 75
+            description:
+              Specifies the maximum angle (in degrees) a finger may travel to
+              be considered a swipe gesture.
+
+          azoteq,thresh:
+            $ref: /schemas/types.yaml#/definitions/uint32
+            minimum: 0
+            maximum: 42
+            description: Specifies the palm gesture threshold (IQS7211E only).
+
+        additionalProperties: false
+
+    dependencies:
+      azoteq,rx-enable: ["azoteq,tx-enable"]
+      azoteq,tx-enable: ["azoteq,rx-enable"]
+      azoteq,channel-select: ["azoteq,rx-enable"]
+
+    additionalProperties: false
+
+  alp:
+    type: object
+    $ref: ../input.yaml#
+    description: Represents the alternate low-power channel (ALP).
+
+    properties:
+      azoteq,rx-enable:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        maxItems: 8
+        items:
+          minimum: 0
+          maximum: 7
+        description:
+          Specifies the CRx pin(s) associated with the ALP in no particular
+          order.
+
+      azoteq,tx-enable:
+        $ref: /schemas/types.yaml#/definitions/uint32-array
+        minItems: 1
+        maxItems: 12
+        items:
+          minimum: 0
+          maximum: 11
+        description:
+          Specifies the CTx pin(s) associated with the ALP in no particular
+          order.
+
+      azoteq,ati-frac-div-fine:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the ALP's ATI fine fractional divider.
+
+      azoteq,ati-frac-mult-coarse:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 15
+        description: Specifies the ALP's ATI coarse fractional multiplier.
+
+      azoteq,ati-frac-div-coarse:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the ALP's ATI coarse fractional divider.
+
+      azoteq,ati-comp-div:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the ALP's ATI compensation divider.
+
+      azoteq,ati-target:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 65535
+        description: Specifies the ALP's ATI target.
+
+      azoteq,ati-base:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        multipleOf: 8
+        minimum: 0
+        maximum: 255
+        description: Specifies the ALP's ATI base.
+
+      azoteq,ati-mode:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1]
+        description: |
+          Specifies the ALP's ATI mode as follows:
+          0: Partial
+          1: Full
+
+      azoteq,sense-mode:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1]
+        description: |
+          Specifies the ALP's sensing mode as follows:
+          0: Self capacitive
+          1: Mutual capacitive
+
+      azoteq,debounce-enter:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the ALP's debounce entrance factor.
+
+      azoteq,debounce-exit:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the ALP's debounce exit factor.
+
+      azoteq,thresh:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 65535
+        description: Specifies the ALP's proximity or touch threshold.
+
+      azoteq,conv-period:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the ALP's conversion period.
+
+      azoteq,conv-frac:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the ALP's conversion frequency fraction.
+
+      linux,code: true
+
+    additionalProperties: false
+
+  button:
+    type: object
+    description: Represents the inductive or capacitive button.
+
+    properties:
+      azoteq,ati-frac-div-fine:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the button's ATI fine fractional divider.
+
+      azoteq,ati-frac-mult-coarse:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 15
+        description: Specifies the button's ATI coarse fractional multiplier.
+
+      azoteq,ati-frac-div-coarse:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the button's ATI coarse fractional divider.
+
+      azoteq,ati-comp-div:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 31
+        description: Specifies the button's ATI compensation divider.
+
+      azoteq,ati-target:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 65535
+        description: Specifies the button's ATI target.
+
+      azoteq,ati-base:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        multipleOf: 8
+        minimum: 0
+        maximum: 255
+        description: Specifies the button's ATI base.
+
+      azoteq,ati-mode:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1]
+        description: |
+          Specifies the button's ATI mode as follows:
+          0: Partial
+          1: Full
+
+      azoteq,sense-mode:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        enum: [0, 1, 2]
+        description: |
+          Specifies the button's sensing mode as follows:
+          0: Self capacitive
+          1: Mutual capacitive
+          2: Inductive
+
+      azoteq,touch-enter:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the button's touch entrance factor.
+
+      azoteq,touch-exit:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the button's touch exit factor.
+
+      azoteq,debounce-enter:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the button's debounce entrance factor.
+
+      azoteq,debounce-exit:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the button's debounce exit factor.
+
+      azoteq,thresh:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 65535
+        description: Specifies the button's proximity threshold.
+
+      azoteq,conv-period:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the button's conversion period.
+
+      azoteq,conv-frac:
+        $ref: /schemas/types.yaml#/definitions/uint32
+        minimum: 0
+        maximum: 255
+        description: Specifies the button's conversion frequency fraction.
+
+    patternProperties:
+      "^event-(prox|touch)$":
+        type: object
+        $ref: ../input.yaml#
+        description:
+          Represents a proximity or touch event reported by the button.
+
+        properties:
+          linux,code: true
+
+        additionalProperties: false
+
+    additionalProperties: false
+
+  wakeup-source: true
+
+  touchscreen-size-x: true
+  touchscreen-size-y: true
+  touchscreen-inverted-x: true
+  touchscreen-inverted-y: true
+  touchscreen-swapped-x-y: true
+
+dependencies:
+  touchscreen-size-x: ["azoteq,num-contacts"]
+  touchscreen-size-y: ["azoteq,num-contacts"]
+  touchscreen-inverted-x: ["azoteq,num-contacts"]
+  touchscreen-inverted-y: ["azoteq,num-contacts"]
+  touchscreen-swapped-x-y: ["azoteq,num-contacts"]
+
+required:
+  - compatible
+  - reg
+  - irq-gpios
+
+additionalProperties: false
+
+allOf:
+  - $ref: touchscreen.yaml#
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: azoteq,iqs7210a
+
+    then:
+      properties:
+        alp:
+          properties:
+            azoteq,rx-enable:
+              maxItems: 4
+              items:
+                minimum: 4
+
+    else:
+      properties:
+        azoteq,timeout-press-ms: false
+
+        alp:
+          properties:
+            azoteq,ati-mode: false
+
+        button: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: azoteq,iqs7211e
+
+    then:
+      properties:
+        reset-gpios: false
+
+        trackpad:
+          properties:
+            azoteq,tx-enable:
+              maxItems: 13
+              items:
+                maximum: 12
+
+        alp:
+          properties:
+            azoteq,tx-enable:
+              maxItems: 13
+              items:
+                maximum: 12
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/input/input.h>
+
+    i2c {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            touch@56 {
+                    compatible = "azoteq,iqs7210a";
+                    reg = <0x56>;
+                    irq-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
+                    reset-gpios = <&gpio 17 (GPIO_ACTIVE_LOW |
+                                             GPIO_PUSH_PULL)>;
+                    azoteq,num-contacts = <2>;
+
+                    trackpad {
+                            azoteq,rx-enable = <6>, <5>, <4>, <3>, <2>;
+                            azoteq,tx-enable = <1>, <7>, <8>, <9>, <10>;
+                    };
+
+                    button {
+                            azoteq,sense-mode = <2>;
+                            azoteq,touch-enter = <40>;
+                            azoteq,touch-exit = <36>;
+
+                            event-touch {
+                                    linux,code = <KEY_HOME>;
+                            };
+                    };
+
+                    alp {
+                            azoteq,sense-mode = <1>;
+                            linux,code = <KEY_POWER>;
+                    };
+            };
+    };
+
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/input/input.h>
+
+    i2c {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            touch@56 {
+                    compatible = "azoteq,iqs7211e";
+                    reg = <0x56>;
+                    irq-gpios = <&gpio 4 (GPIO_ACTIVE_LOW |
+                                          GPIO_OPEN_DRAIN)>;
+
+                    trackpad {
+                            event-tap {
+                                    linux,code = <KEY_PLAYPAUSE>;
+                            };
+
+                            event-tap-double {
+                                    linux,code = <KEY_SHUFFLE>;
+                            };
+
+                            event-tap-triple {
+                                    linux,code = <KEY_AGAIN>;
+                            };
+
+                            event-hold {
+                                    linux,code = <KEY_STOP>;
+                            };
+
+                            event-palm {
+                                    linux,code = <KEY_EXIT>;
+                            };
+
+                            event-swipe-x-pos {
+                                    linux,code = <KEY_REWIND>;
+                            };
+
+                            event-swipe-x-pos-hold {
+                                    linux,code = <KEY_PREVIOUS>;
+                            };
+
+                            event-swipe-x-neg {
+                                    linux,code = <KEY_FASTFORWARD>;
+                            };
+
+                            event-swipe-x-neg-hold {
+                                    linux,code = <KEY_NEXT>;
+                            };
+
+                            event-swipe-y-pos {
+                                    linux,code = <KEY_VOLUMEUP>;
+                            };
+
+                            event-swipe-y-pos-hold {
+                                    linux,code = <KEY_MUTE>;
+                            };
+
+                            event-swipe-y-neg {
+                                    linux,code = <KEY_VOLUMEDOWN>;
+                            };
+
+                            event-swipe-y-neg-hold {
+                                    linux,code = <KEY_MUTE>;
+                            };
+                    };
+            };
+    };
+
+...
index 1959ec3..4080422 100644 (file)
@@ -40,6 +40,8 @@ properties:
   linux,keycodes:
     description: EV_ABS specific event code generated by the axis.
 
+  wakeup-source: true
+
 patternProperties:
   "^button@[0-9]+$":
     type: object
index ef4c841..f2808cb 100644 (file)
@@ -93,6 +93,12 @@ properties:
     minimum: 1
     maximum: 255
 
+  threshold:
+    description: Allows setting the  "click"-threshold in the range from 0 to 255.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 255
+
   touchscreen-size-x: true
   touchscreen-size-y: true
   touchscreen-fuzz-x: true
index 007adbc..9dc25d3 100644 (file)
@@ -24,6 +24,8 @@ properties:
     maxItems: 1
   reset-gpios:
     maxItems: 1
+  vdd-supply:
+    description: Power supply regulator for the chip
   touchscreen-size-x: true
   touchscreen-size-y: true
   touchscreen-inverted-x: true
index 173c2ac..a480bc7 100644 (file)
@@ -4,16 +4,16 @@ xpad - Linux USB driver for Xbox compatible controllers
 
 This driver exposes all first-party and third-party Xbox compatible
 controllers. It has a long history and has enjoyed considerable usage
-as Window's xinput library caused most PC games to focus on Xbox
+as Windows' xinput library caused most PC games to focus on Xbox
 controller compatibility.
 
 Due to backwards compatibility all buttons are reported as digital.
-This only effects Original Xbox controllers. All later controller models
+This only affects Original Xbox controllers. All later controller models
 have only digital face buttons.
 
 Rumble is supported on some models of Xbox 360 controllers but not of
 Original Xbox controllers nor on Xbox One controllers. As of writing
-the Xbox One's rumble protocol has not been reverse engineered but in
+the Xbox One's rumble protocol has not been reverse-engineered but in
 the future could be supported.
 
 
@@ -82,7 +82,7 @@ I've tested this with Stepmania, and it works quite well.
 Unknown Controllers
 -------------------
 
-If you have an unknown xbox controller, it should work just fine with
+If you have an unknown Xbox controller, it should work just fine with
 the default settings.
 
 HOWEVER if you have an unknown dance pad not listed below, it will not
@@ -123,7 +123,7 @@ can be found on the net ([1]_, [2]_, [3]_).
 
 Thanks to the trip splitter found on the cable you don't even need to cut the
 original one. You can buy an extension cable and cut that instead. That way,
-you can still use the controller with your X-Box, if you have one ;)
+you can still use the controller with your Xbox, if you have one ;)
 
 
 
index 71019de..eca17a7 100644 (file)
@@ -184,7 +184,7 @@ Gamepads report the following events:
 
   Many pads also have a third button which is branded or has a special symbol
   and meaning. Such buttons are mapped as BTN_MODE. Examples are the Nintendo
-  "HOME" button, the XBox "X"-button or Sony "PS" button.
+  "HOME" button, the Xbox "X" button or the Sony PlayStation "PS" button.
 
 - Rumble:
 
index 35e1959..54ef320 100644 (file)
@@ -2586,9 +2586,9 @@ F:        arch/arm/boot/dts/qcom-*.dtsi
 F:     arch/arm/configs/qcom_defconfig
 F:     arch/arm/mach-qcom/
 F:     arch/arm64/boot/dts/qcom/
+F:     drivers/*/*/pm8???-*
 F:     drivers/*/*/qcom*
 F:     drivers/*/*/qcom/
-F:     drivers/*/pm8???-*
 F:     drivers/*/qcom*
 F:     drivers/*/qcom/
 F:     drivers/bluetooth/btqcomsmd.c
index 735f90b..3bdbd34 100644 (file)
@@ -168,7 +168,7 @@ config INPUT_EVBUG
 
 config INPUT_KUNIT_TEST
        tristate "KUnit tests for Input" if !KUNIT_ALL_TESTS
-       depends on INPUT && KUNIT=y
+       depends on INPUT && KUNIT
        default KUNIT_ALL_TESTS
        help
          Say Y here if you want to build the KUnit tests for the input
index 5a2c2fb..fe73b26 100644 (file)
@@ -25,6 +25,7 @@ if GAMEPORT
 
 config GAMEPORT_NS558
        tristate "Classic ISA and PnP gameport support"
+       depends on ISA
        help
          Say Y here if you have an ISA or PnP gameport.
 
@@ -35,6 +36,7 @@ config GAMEPORT_NS558
 
 config GAMEPORT_L4
        tristate "PDPI Lightning 4 gamecard support"
+       depends on ISA
        help
          Say Y here if you have a PDPI Lightning 4 gamecard.
 
@@ -53,7 +55,7 @@ config GAMEPORT_EMU10K1
 
 config GAMEPORT_FM801
        tristate "ForteMedia FM801 gameport support"
-       depends on PCI
+       depends on PCI && HAS_IOPORT
        help
          Say Y here if you have ForteMedia FM801 PCI audio controller
          (Abit AU10, Genius Sound Maker, HP Workstation zx2000,
index db58a01..34f416a 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/stddef.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/gameport.h>
@@ -21,8 +22,6 @@
 #include <linux/mutex.h>
 #include <linux/timekeeping.h>
 
-/*#include <asm/io.h>*/
-
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Generic gameport layer");
 MODULE_LICENSE("GPL");
@@ -518,6 +517,36 @@ void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)
 }
 EXPORT_SYMBOL(gameport_set_phys);
 
+static void gameport_default_trigger(struct gameport *gameport)
+{
+#ifdef CONFIG_HAS_IOPORT
+       outb(0xff, gameport->io);
+#endif
+}
+
+static unsigned char gameport_default_read(struct gameport *gameport)
+{
+#ifdef CONFIG_HAS_IOPORT
+       return inb(gameport->io);
+#else
+       return 0xff;
+#endif
+}
+
+static void gameport_setup_default_handlers(struct gameport *gameport)
+{
+       if ((!gameport->trigger || !gameport->read) &&
+           !IS_ENABLED(CONFIG_HAS_IOPORT))
+               dev_err(&gameport->dev,
+                       "I/O port access is required for %s (%s) but is not available\n",
+                       gameport->phys, gameport->name);
+
+       if (!gameport->trigger)
+               gameport->trigger = gameport_default_trigger;
+       if (!gameport->read)
+               gameport->read = gameport_default_read;
+}
+
 /*
  * Prepare gameport port for registration.
  */
@@ -536,6 +565,7 @@ static void gameport_init_port(struct gameport *gameport)
        if (gameport->parent)
                gameport->dev.parent = &gameport->parent->dev;
 
+       gameport_setup_default_handlers(gameport);
        INIT_LIST_HEAD(&gameport->node);
        spin_lock_init(&gameport->timer_lock);
        timer_setup(&gameport->poll_timer, gameport_run_poll_handler, 0);
index 641eb86..8c5fdb0 100644 (file)
@@ -190,6 +190,7 @@ static int input_handle_abs_event(struct input_dev *dev,
                                  unsigned int code, int *pval)
 {
        struct input_mt *mt = dev->mt;
+       bool is_new_slot = false;
        bool is_mt_event;
        int *pold;
 
@@ -210,6 +211,7 @@ static int input_handle_abs_event(struct input_dev *dev,
                pold = &dev->absinfo[code].value;
        } else if (mt) {
                pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
+               is_new_slot = mt->slot != dev->absinfo[ABS_MT_SLOT].value;
        } else {
                /*
                 * Bypass filtering for multi-touch events when
@@ -228,8 +230,8 @@ static int input_handle_abs_event(struct input_dev *dev,
        }
 
        /* Flush pending "slot" event */
-       if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
-               input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
+       if (is_new_slot) {
+               dev->absinfo[ABS_MT_SLOT].value = mt->slot;
                return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
        }
 
index 04ca3d1..ac6925c 100644 (file)
@@ -292,33 +292,33 @@ config JOYSTICK_JOYDUMP
          module will be called joydump.
 
 config JOYSTICK_XPAD
-       tristate "X-Box gamepad support"
+       tristate "Xbox gamepad support"
        depends on USB_ARCH_HAS_HCD
        select USB
        help
-         Say Y here if you want to use the X-Box pad with your computer.
+         Say Y here if you want to use Xbox pads with your computer.
          Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
          and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
 
-         For information about how to connect the X-Box pad to USB, see
+         For information about how to connect the Xbox pad to USB, see
          <file:Documentation/input/devices/xpad.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called xpad.
 
 config JOYSTICK_XPAD_FF
-       bool "X-Box gamepad rumble support"
+       bool "Xbox gamepad rumble support"
        depends on JOYSTICK_XPAD && INPUT
        select INPUT_FF_MEMLESS
        help
-         Say Y here if you want to take advantage of xbox 360 rumble features.
+         Say Y here if you want to take advantage of Xbox 360 rumble features.
 
 config JOYSTICK_XPAD_LEDS
-       bool "LED Support for Xbox360 controller 'BigX' LED"
+       bool "LED Support for the Xbox 360 controller Guide button"
        depends on JOYSTICK_XPAD && (LEDS_CLASS=y || LEDS_CLASS=JOYSTICK_XPAD)
        help
          This option enables support for the LED which surrounds the Big X on
-         XBox 360 controller.
+         Xbox 360 controllers.
 
 config JOYSTICK_WALKERA0701
        tristate "Walkera WK-0701 RC transmitter"
index 3b88f0b..bf8b1cc 100644 (file)
@@ -348,7 +348,7 @@ static struct i2c_driver as5011_driver = {
        .driver = {
                .name = "as5011",
        },
-       .probe_new      = as5011_probe,
+       .probe          = as5011_probe,
        .remove         = as5011_remove,
        .id_table       = as5011_id,
 };
index d4da31c..7d88d76 100644 (file)
@@ -137,7 +137,7 @@ static struct i2c_driver qwiic_driver = {
                .of_match_table = of_match_ptr(of_qwiic_match),
        },
        .id_table       = qwiic_id_table,
-       .probe_new      = qwiic_probe,
+       .probe          = qwiic_probe,
 };
 module_i2c_driver(qwiic_driver);
 
index f33622f..ede3805 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * X-Box gamepad driver
+ * Xbox gamepad driver
  *
  * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
  *               2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>,
@@ -23,8 +23,8 @@
  *  - ITO Takayuki for providing essential xpad information on his website
  *  - Vojtech Pavlik     - iforce driver / input subsystem
  *  - Greg Kroah-Hartman - usb-skeleton driver
- *  - XBOX Linux project - extra USB id's
- *  - Pekka Pöyry (quantus) - Xbox One controller reverse engineering
+ *  - Xbox Linux project - extra USB IDs
+ *  - Pekka Pöyry (quantus) - Xbox One controller reverse-engineering
  *
  * TODO:
  *  - fine tune axes (especially trigger axes)
@@ -52,7 +52,7 @@
  * 2002-07-17 - 0.0.5 : simplified d-pad handling
  *
  * 2004-10-02 - 0.0.6 : DDR pad support
- *  - borrowed from the XBOX linux kernel
+ *  - borrowed from the Xbox Linux kernel
  *  - USB id's for commonly used dance pads are present
  *  - dance pads will map D-PAD to buttons, not axes
  *  - pass the module paramater 'dpad_to_buttons' to force
@@ -264,6 +264,7 @@ static const struct xpad_device {
        { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE },
        { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
        { 0x0f0d, 0x00c5, "Hori Fighting Commander ONE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
+       { 0x0f0d, 0x00dc, "HORIPAD FPS for Nintendo Switch", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX },
        { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
        { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
@@ -365,6 +366,7 @@ static const struct xpad_device {
        { 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 },
        { 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 },
        { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 },
+       { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 },
        { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX },
        { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
        { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
@@ -454,51 +456,53 @@ static const signed short xpad_btn_paddles[] = {
        { XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) }
 
 static const struct usb_device_id xpad_table[] = {
-       { USB_INTERFACE_INFO('X', 'B', 0) },    /* X-Box USB-IF not approved class */
-       XPAD_XBOX360_VENDOR(0x0079),            /* GPD Win 2 Controller */
+       { USB_INTERFACE_INFO('X', 'B', 0) },    /* Xbox USB-IF not-approved class */
+       XPAD_XBOX360_VENDOR(0x0079),            /* GPD Win 2 controller */
        XPAD_XBOX360_VENDOR(0x03eb),            /* Wooting Keyboards (Legacy) */
-       XPAD_XBOX360_VENDOR(0x044f),            /* Thrustmaster X-Box 360 controllers */
-       XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft X-Box 360 controllers */
-       XPAD_XBOXONE_VENDOR(0x045e),            /* Microsoft X-Box One controllers */
-       XPAD_XBOX360_VENDOR(0x046d),            /* Logitech X-Box 360 style controllers */
+       XPAD_XBOX360_VENDOR(0x044f),            /* Thrustmaster Xbox 360 controllers */
+       XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft Xbox 360 controllers */
+       XPAD_XBOXONE_VENDOR(0x045e),            /* Microsoft Xbox One controllers */
+       XPAD_XBOX360_VENDOR(0x046d),            /* Logitech Xbox 360-style controllers */
        XPAD_XBOX360_VENDOR(0x056e),            /* Elecom JC-U3613M */
        XPAD_XBOX360_VENDOR(0x06a3),            /* Saitek P3600 */
-       XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz X-Box 360 controllers */
+       XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz Xbox 360 controllers */
        { USB_DEVICE(0x0738, 0x4540) },         /* Mad Catz Beat Pad */
        XPAD_XBOXONE_VENDOR(0x0738),            /* Mad Catz FightStick TE 2 */
-       XPAD_XBOX360_VENDOR(0x07ff),            /* Mad Catz GamePad */
+       XPAD_XBOX360_VENDOR(0x07ff),            /* Mad Catz Gamepad */
        XPAD_XBOX360_VENDOR(0x0c12),            /* Zeroplus X-Box 360 controllers */
-       XPAD_XBOX360_VENDOR(0x0e6f),            /* 0x0e6f X-Box 360 controllers */
-       XPAD_XBOXONE_VENDOR(0x0e6f),            /* 0x0e6f X-Box One controllers */
-       XPAD_XBOX360_VENDOR(0x0f0d),            /* Hori Controllers */
-       XPAD_XBOXONE_VENDOR(0x0f0d),            /* Hori Controllers */
-       XPAD_XBOX360_VENDOR(0x1038),            /* SteelSeries Controllers */
+       XPAD_XBOX360_VENDOR(0x0e6f),            /* 0x0e6f Xbox 360 controllers */
+       XPAD_XBOXONE_VENDOR(0x0e6f),            /* 0x0e6f Xbox One controllers */
+       XPAD_XBOX360_VENDOR(0x0f0d),            /* Hori controllers */
+       XPAD_XBOXONE_VENDOR(0x0f0d),            /* Hori controllers */
+       XPAD_XBOX360_VENDOR(0x1038),            /* SteelSeries controllers */
        XPAD_XBOXONE_VENDOR(0x10f5),            /* Turtle Beach Controllers */
        XPAD_XBOX360_VENDOR(0x11c9),            /* Nacon GC100XF */
        XPAD_XBOX360_VENDOR(0x1209),            /* Ardwiino Controllers */
-       XPAD_XBOX360_VENDOR(0x12ab),            /* X-Box 360 dance pads */
-       XPAD_XBOX360_VENDOR(0x1430),            /* RedOctane X-Box 360 controllers */
-       XPAD_XBOX360_VENDOR(0x146b),            /* BigBen Interactive Controllers */
+       XPAD_XBOX360_VENDOR(0x12ab),            /* Xbox 360 dance pads */
+       XPAD_XBOX360_VENDOR(0x1430),            /* RedOctane Xbox 360 controllers */
+       XPAD_XBOX360_VENDOR(0x146b),            /* Bigben Interactive controllers */
        XPAD_XBOX360_VENDOR(0x1532),            /* Razer Sabertooth */
        XPAD_XBOXONE_VENDOR(0x1532),            /* Razer Wildcat */
-       XPAD_XBOX360_VENDOR(0x15e4),            /* Numark X-Box 360 controllers */
-       XPAD_XBOX360_VENDOR(0x162e),            /* Joytech X-Box 360 controllers */
+       XPAD_XBOX360_VENDOR(0x15e4),            /* Numark Xbox 360 controllers */
+       XPAD_XBOX360_VENDOR(0x162e),            /* Joytech Xbox 360 controllers */
        XPAD_XBOX360_VENDOR(0x1689),            /* Razer Onza */
        XPAD_XBOX360_VENDOR(0x1949),            /* Amazon controllers */
-       XPAD_XBOX360_VENDOR(0x1bad),            /* Harminix Rock Band Guitar and Drums */
-       XPAD_XBOX360_VENDOR(0x20d6),            /* PowerA Controllers */
-       XPAD_XBOXONE_VENDOR(0x20d6),            /* PowerA Controllers */
-       XPAD_XBOX360_VENDOR(0x24c6),            /* PowerA Controllers */
-       XPAD_XBOXONE_VENDOR(0x24c6),            /* PowerA Controllers */
+       XPAD_XBOX360_VENDOR(0x1bad),            /* Harmonix Rock Band guitar and drums */
+       XPAD_XBOX360_VENDOR(0x20d6),            /* PowerA controllers */
+       XPAD_XBOXONE_VENDOR(0x20d6),            /* PowerA controllers */
+       XPAD_XBOX360_VENDOR(0x24c6),            /* PowerA controllers */
+       XPAD_XBOXONE_VENDOR(0x24c6),            /* PowerA controllers */
        XPAD_XBOX360_VENDOR(0x2563),            /* OneXPlayer Gamepad */
        XPAD_XBOX360_VENDOR(0x260d),            /* Dareu H101 */
        XPAD_XBOX360_VENDOR(0x2c22),            /* Qanba Controllers */
        XPAD_XBOX360_VENDOR(0x2dc8),            /* 8BitDo Pro 2 Wired Controller */
        XPAD_XBOXONE_VENDOR(0x2dc8),            /* 8BitDo Pro 2 Wired Controller for Xbox */
-       XPAD_XBOXONE_VENDOR(0x2e24),            /* Hyperkin Duke X-Box One pad */
-       XPAD_XBOX360_VENDOR(0x2f24),            /* GameSir Controllers */
+       XPAD_XBOXONE_VENDOR(0x2e24),            /* Hyperkin Duke Xbox One pad */
+       XPAD_XBOX360_VENDOR(0x2f24),            /* GameSir controllers */
        XPAD_XBOX360_VENDOR(0x31e3),            /* Wooting Keyboards */
        XPAD_XBOX360_VENDOR(0x3285),            /* Nacon GC-100 */
+       XPAD_XBOX360_VENDOR(0x3537),            /* GameSir Controllers */
+       XPAD_XBOXONE_VENDOR(0x3537),            /* GameSir Controllers */
        { }
 };
 
@@ -724,7 +728,7 @@ static void xpad360w_poweroff_controller(struct usb_xpad *xpad);
  *     Completes a request by converting the data into events for the
  *     input subsystem.
  *
- *     The used report descriptor was taken from ITO Takayukis website:
+ *     The used report descriptor was taken from ITO Takayuki's website:
  *      http://euc.jp/periphs/xbox-controller.ja.html
  */
 static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
@@ -1569,7 +1573,7 @@ struct xpad_led {
 };
 
 /*
- * set the LEDs on Xbox360 / Wireless Controllers
+ * set the LEDs on Xbox 360 / Wireless Controllers
  * @param command
  *  0: off
  *  1: all blink, then previous setting
@@ -1720,6 +1724,27 @@ static int xpad_start_input(struct usb_xpad *xpad)
                        return error;
                }
        }
+       if (xpad->xtype == XTYPE_XBOX360) {
+               /*
+                * Some third-party controllers Xbox 360-style controllers
+                * require this message to finish initialization.
+                */
+               u8 dummy[20];
+
+               error = usb_control_msg_recv(xpad->udev, 0,
+                                            /* bRequest */ 0x01,
+                                            /* bmRequestType */
+                                            USB_TYPE_VENDOR | USB_DIR_IN |
+                                               USB_RECIP_INTERFACE,
+                                            /* wValue */ 0x100,
+                                            /* wIndex */ 0x00,
+                                            dummy, sizeof(dummy),
+                                            25, GFP_KERNEL);
+               if (error)
+                       dev_warn(&xpad->dev->dev,
+                                "unable to receive magic message: %d\n",
+                                error);
+       }
 
        return 0;
 }
@@ -2229,5 +2254,5 @@ static struct usb_driver xpad_driver = {
 module_usb_driver(xpad_driver);
 
 MODULE_AUTHOR("Marko Friedemann <mfr@bmx-chemnitz.de>");
-MODULE_DESCRIPTION("X-Box pad driver");
+MODULE_DESCRIPTION("Xbox pad driver");
 MODULE_LICENSE("GPL");
index 72ae5ce..61e8e43 100644 (file)
@@ -713,17 +713,11 @@ static int adp5588_fw_parse(struct adp5588_kpad *kpad)
        return 0;
 }
 
-static void adp5588_disable_regulator(void *reg)
-{
-       regulator_disable(reg);
-}
-
 static int adp5588_probe(struct i2c_client *client)
 {
        struct adp5588_kpad *kpad;
        struct input_dev *input;
        struct gpio_desc *gpio;
-       struct regulator *vcc;
        unsigned int revid;
        int ret;
        int error;
@@ -749,16 +743,7 @@ static int adp5588_probe(struct i2c_client *client)
        if (error)
                return error;
 
-       vcc = devm_regulator_get(&client->dev, "vcc");
-       if (IS_ERR(vcc))
-               return PTR_ERR(vcc);
-
-       error = regulator_enable(vcc);
-       if (error)
-               return error;
-
-       error = devm_add_action_or_reset(&client->dev,
-                                        adp5588_disable_regulator, vcc);
+       error = devm_regulator_get_enable(&client->dev, "vcc");
        if (error)
                return error;
 
@@ -866,7 +851,7 @@ static struct i2c_driver adp5588_driver = {
                .of_match_table = adp5588_of_match,
                .pm   = pm_sleep_ptr(&adp5588_dev_pm_ops),
        },
-       .probe_new = adp5588_probe,
+       .probe    = adp5588_probe,
        .remove   = adp5588_remove,
        .id_table = adp5588_id,
 };
index 38d7073..8996e00 100644 (file)
@@ -1054,7 +1054,7 @@ static struct i2c_driver adp5589_driver = {
                .name = KBUILD_MODNAME,
                .pm = pm_sleep_ptr(&adp5589_dev_pm_ops),
        },
-       .probe_new = adp5589_probe,
+       .probe = adp5589_probe,
        .id_table = adp5589_id,
 };
 
index 2469587..c92e544 100644 (file)
@@ -309,12 +309,19 @@ static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf)
        return vivaldi_function_row_physmap_show(&atkbd->vdata, buf);
 }
 
+static struct atkbd *atkbd_from_serio(struct serio *serio)
+{
+       struct ps2dev *ps2dev = serio_get_drvdata(serio);
+
+       return container_of(ps2dev, struct atkbd, ps2dev);
+}
+
 static umode_t atkbd_attr_is_visible(struct kobject *kobj,
                                struct attribute *attr, int i)
 {
        struct device *dev = kobj_to_dev(kobj);
        struct serio *serio = to_serio_port(dev);
-       struct atkbd *atkbd = serio_get_drvdata(serio);
+       struct atkbd *atkbd = atkbd_from_serio(serio);
 
        if (attr == &atkbd_attr_function_row_physmap.attr &&
            !atkbd->vdata.num_function_row_keys)
@@ -392,46 +399,60 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code
 }
 
 /*
- * atkbd_interrupt(). Here takes place processing of data received from
- * the keyboard into events.
+ * Tries to handle frame or parity error by requesting the keyboard controller
+ * to resend the last byte. This historically not done on x86 as controllers
+ * there typically do not implement this command.
  */
-
-static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
-                                  unsigned int flags)
+static bool __maybe_unused atkbd_handle_frame_error(struct ps2dev *ps2dev,
+                                                   u8 data, unsigned int flags)
 {
-       struct atkbd *atkbd = serio_get_drvdata(serio);
-       struct input_dev *dev = atkbd->dev;
-       unsigned int code = data;
-       int scroll = 0, hscroll = 0, click = -1;
-       int value;
-       unsigned short keycode;
-
-       dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
+       struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev);
+       struct serio *serio = ps2dev->serio;
 
-#if !defined(__i386__) && !defined (__x86_64__)
-       if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
+       if ((flags & (SERIO_FRAME | SERIO_PARITY)) &&
+           (~flags & SERIO_TIMEOUT) &&
+           !atkbd->resend && atkbd->write) {
                dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
                serio_write(serio, ATKBD_CMD_RESEND);
                atkbd->resend = true;
-               goto out;
+               return true;
        }
 
        if (!flags && data == ATKBD_RET_ACK)
                atkbd->resend = false;
+
+       return false;
+}
+
+static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev,
+                                                  u8 data, unsigned int flags)
+{
+       struct serio *serio = ps2dev->serio;
+
+       dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
+
+#if !defined(__i386__) && !defined (__x86_64__)
+       if (atkbd_handle_frame_error(ps2dev, data, flags))
+               return PS2_IGNORE;
 #endif
 
-       if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
-               if  (ps2_handle_ack(&atkbd->ps2dev, data))
-                       goto out;
+       return PS2_PROCESS;
+}
 
-       if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
-               if  (ps2_handle_response(&atkbd->ps2dev, data))
-                       goto out;
+static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data)
+{
+       struct serio *serio = ps2dev->serio;
+       struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev);
+       struct input_dev *dev = atkbd->dev;
+       unsigned int code = data;
+       int scroll = 0, hscroll = 0, click = -1;
+       int value;
+       unsigned short keycode;
 
        pm_wakeup_event(&serio->dev, 0);
 
        if (!atkbd->enabled)
-               goto out;
+               return;
 
        input_event(dev, EV_MSC, MSC_RAW, code);
 
@@ -453,16 +474,16 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
        case ATKBD_RET_BAT:
                atkbd->enabled = false;
                serio_reconnect(atkbd->ps2dev.serio);
-               goto out;
+               return;
        case ATKBD_RET_EMUL0:
                atkbd->emul = 1;
-               goto out;
+               return;
        case ATKBD_RET_EMUL1:
                atkbd->emul = 2;
-               goto out;
+               return;
        case ATKBD_RET_RELEASE:
                atkbd->release = true;
-               goto out;
+               return;
        case ATKBD_RET_ACK:
        case ATKBD_RET_NAK:
                if (printk_ratelimit())
@@ -470,18 +491,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
                                 "Spurious %s on %s. "
                                 "Some program might be trying to access hardware directly.\n",
                                 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
-               goto out;
+               return;
        case ATKBD_RET_ERR:
                atkbd->err_count++;
                dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
                        serio->phys);
-               goto out;
+               return;
        }
 
        code = atkbd_compat_scancode(atkbd, code);
 
        if (atkbd->emul && --atkbd->emul)
-               goto out;
+               return;
 
        keycode = atkbd->keycode[code];
 
@@ -557,8 +578,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
        }
 
        atkbd->release = false;
-out:
-       return IRQ_HANDLED;
 }
 
 static int atkbd_set_repeat_rate(struct atkbd *atkbd)
@@ -909,7 +928,7 @@ static int atkbd_reset_state(struct atkbd *atkbd)
 
 static void atkbd_cleanup(struct serio *serio)
 {
-       struct atkbd *atkbd = serio_get_drvdata(serio);
+       struct atkbd *atkbd = atkbd_from_serio(serio);
 
        atkbd_disable(atkbd);
        ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
@@ -922,7 +941,7 @@ static void atkbd_cleanup(struct serio *serio)
 
 static void atkbd_disconnect(struct serio *serio)
 {
-       struct atkbd *atkbd = serio_get_drvdata(serio);
+       struct atkbd *atkbd = atkbd_from_serio(serio);
 
        atkbd_disable(atkbd);
 
@@ -1188,7 +1207,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
 
 static void atkbd_parse_fwnode_data(struct serio *serio)
 {
-       struct atkbd *atkbd = serio_get_drvdata(serio);
+       struct atkbd *atkbd = atkbd_from_serio(serio);
        struct device *dev = &serio->dev;
        int n;
 
@@ -1222,7 +1241,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
                goto fail1;
 
        atkbd->dev = dev;
-       ps2_init(&atkbd->ps2dev, serio);
+       ps2_init(&atkbd->ps2dev, serio,
+                atkbd_pre_receive_byte, atkbd_receive_byte);
        INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
        mutex_init(&atkbd->mutex);
 
@@ -1295,7 +1315,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 
 static int atkbd_reconnect(struct serio *serio)
 {
-       struct atkbd *atkbd = serio_get_drvdata(serio);
+       struct atkbd *atkbd = atkbd_from_serio(serio);
        struct serio_driver *drv = serio->drv;
        int retval = -1;
 
@@ -1378,7 +1398,7 @@ static struct serio_driver atkbd_drv = {
        },
        .description    = DRIVER_DESC,
        .id_table       = atkbd_serio_ids,
-       .interrupt      = atkbd_interrupt,
+       .interrupt      = ps2_interrupt,
        .connect        = atkbd_connect,
        .reconnect      = atkbd_reconnect,
        .disconnect     = atkbd_disconnect,
@@ -1389,7 +1409,7 @@ static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
                                ssize_t (*handler)(struct atkbd *, char *))
 {
        struct serio *serio = to_serio_port(dev);
-       struct atkbd *atkbd = serio_get_drvdata(serio);
+       struct atkbd *atkbd = atkbd_from_serio(serio);
 
        return handler(atkbd, buf);
 }
@@ -1398,7 +1418,7 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t
                                ssize_t (*handler)(struct atkbd *, const char *, size_t))
 {
        struct serio *serio = to_serio_port(dev);
-       struct atkbd *atkbd = serio_get_drvdata(serio);
+       struct atkbd *atkbd = atkbd_from_serio(serio);
        int retval;
 
        retval = mutex_lock_interruptible(&atkbd->mutex);
index 56a919e..f3c3746 100644 (file)
@@ -307,7 +307,6 @@ static int bcm_kp_probe(struct platform_device *pdev)
 {
        struct bcm_kp *kp;
        struct input_dev *input_dev;
-       struct resource *res;
        int error;
 
        kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
@@ -353,29 +352,16 @@ static int bcm_kp_probe(struct platform_device *pdev)
                return error;
        }
 
-       /* Get the KEYPAD base address */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Missing keypad base address resource\n");
-               return -ENODEV;
-       }
-
-       kp->base = devm_ioremap_resource(&pdev->dev, res);
+       kp->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(kp->base))
                return PTR_ERR(kp->base);
 
        /* Enable clock */
-       kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
+       kp->clk = devm_clk_get_optional(&pdev->dev, "peri_clk");
        if (IS_ERR(kp->clk)) {
-               error = PTR_ERR(kp->clk);
-               if (error != -ENOENT) {
-                       if (error != -EPROBE_DEFER)
-                               dev_err(&pdev->dev, "Failed to get clock\n");
-                       return error;
-               }
-               dev_dbg(&pdev->dev,
-                       "No clock specified. Assuming it's enabled\n");
-               kp->clk = NULL;
+               return dev_err_probe(&pdev->dev, PTR_ERR(kp->clk), "Failed to get clock\n");
+       } else if (!kp->clk) {
+               dev_dbg(&pdev->dev, "No clock specified. Assuming it's enabled\n");
        } else {
                unsigned int desired_rate;
                long actual_rate;
index 040696d..1b4937d 100644 (file)
@@ -518,7 +518,7 @@ static struct i2c_driver cap11xx_i2c_driver = {
                .of_match_table = cap11xx_dt_ids,
        },
        .id_table       = cap11xx_i2c_ids,
-       .probe_new      = cap11xx_i2c_probe,
+       .probe          = cap11xx_i2c_probe,
 };
 
 module_i2c_driver(cap11xx_i2c_driver);
index 686388f..2bacd9d 100644 (file)
@@ -229,7 +229,7 @@ static struct i2c_driver cypress_sf_driver = {
                .of_match_table = of_match_ptr(cypress_sf_of_match),
        },
        .id_table = cypress_sf_id_table,
-       .probe_new = cypress_sf_probe,
+       .probe = cypress_sf_probe,
 };
 module_i2c_driver(cypress_sf_driver);
 
index ddba2bc..6c065ef 100644 (file)
@@ -145,7 +145,7 @@ static struct i2c_driver dir685_tk_i2c_driver = {
                .name   = "dlink-dir685-touchkeys",
                .of_match_table = of_match_ptr(dir685_tk_of_match),
        },
-       .probe_new      = dir685_tk_probe,
+       .probe          = dir685_tk_probe,
        .id_table       = dir685_tk_id,
 };
 module_i2c_driver(dir685_tk_i2c_driver);
index c42f86a..c928829 100644 (file)
@@ -456,7 +456,7 @@ static enum hrtimer_restart gpio_keys_irq_timer(struct hrtimer *t)
        struct input_dev *input = bdata->input;
 
        if (bdata->key_pressed) {
-               input_event(input, EV_KEY, *bdata->code, 0);
+               input_report_key(input, *bdata->code, 0);
                input_sync(input);
                bdata->key_pressed = false;
        }
@@ -478,11 +478,11 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
                if (bdata->button->wakeup)
                        pm_wakeup_event(bdata->input->dev.parent, 0);
 
-               input_event(input, EV_KEY, *bdata->code, 1);
+               input_report_key(input, *bdata->code, 1);
                input_sync(input);
 
                if (!bdata->release_delay) {
-                       input_event(input, EV_KEY, *bdata->code, 0);
+                       input_report_key(input, *bdata->code, 0);
                        input_sync(input);
                        goto out;
                }
index c3937d2..ba00ecf 100644 (file)
@@ -299,13 +299,9 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                                                             NULL, GPIOD_IN,
                                                             button->desc);
                        if (IS_ERR(bdata->gpiod)) {
-                               error = PTR_ERR(bdata->gpiod);
-                               if (error != -EPROBE_DEFER)
-                                       dev_err(dev,
-                                               "failed to get gpio: %d\n",
-                                               error);
                                fwnode_handle_put(child);
-                               return error;
+                               return dev_err_probe(dev, PTR_ERR(bdata->gpiod),
+                                                    "failed to get gpio\n");
                        }
                } else if (gpio_is_valid(button->gpio)) {
                        /*
index 5df4d5a..3964f6e 100644 (file)
@@ -826,7 +826,7 @@ static struct i2c_driver lm8323_i2c_driver = {
                .name   = "lm8323",
                .pm     = pm_sleep_ptr(&lm8323_pm_ops),
        },
-       .probe_new      = lm8323_probe,
+       .probe          = lm8323_probe,
        .remove         = lm8323_remove,
        .id_table       = lm8323_id,
 };
index 7457c32..c9f0576 100644 (file)
@@ -218,7 +218,7 @@ static struct i2c_driver lm8333_driver = {
        .driver = {
                .name           = "lm8333",
        },
-       .probe_new      = lm8333_probe,
+       .probe          = lm8333_probe,
        .remove         = lm8333_remove,
        .id_table       = lm8333_id,
 };
index 911e118..322a878 100644 (file)
@@ -160,17 +160,10 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev)
 {
        struct lpc32xx_kscan_drv *kscandat;
        struct input_dev *input;
-       struct resource *res;
        size_t keymap_size;
        int error;
        int irq;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get platform I/O memory\n");
-               return -EINVAL;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return -EINVAL;
@@ -221,7 +214,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev)
 
        input_set_drvdata(kscandat->input, kscandat);
 
-       kscandat->kscan_base = devm_ioremap_resource(&pdev->dev, res);
+       kscandat->kscan_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(kscandat->kscan_base))
                return PTR_ERR(kscandat->kscan_base);
 
index b363749..faab769 100644 (file)
@@ -280,7 +280,7 @@ static struct i2c_driver max7359_i2c_driver = {
                .name = "max7359",
                .pm   = pm_sleep_ptr(&max7359_pm),
        },
-       .probe_new      = max7359_probe,
+       .probe          = max7359_probe,
        .id_table       = max7359_ids,
 };
 
index d414e19..de312d8 100644 (file)
@@ -258,7 +258,7 @@ static struct i2c_driver mcs_touchkey_driver = {
                .name   = "mcs_touchkey",
                .pm     = pm_sleep_ptr(&mcs_touchkey_pm_ops),
        },
-       .probe_new      = mcs_touchkey_probe,
+       .probe          = mcs_touchkey_probe,
        .remove         = mcs_touchkey_remove,
        .shutdown       = mcs_touchkey_shutdown,
        .id_table       = mcs_touchkey_id,
index 74ad353..d434753 100644 (file)
@@ -389,7 +389,7 @@ static struct i2c_driver mpr_touchkey_driver = {
                .of_match_table = of_match_ptr(mpr121_touchkey_dt_match_table),
        },
        .id_table       = mpr121_id,
-       .probe_new      = mpr_touchkey_probe,
+       .probe          = mpr_touchkey_probe,
 };
 
 module_i2c_driver(mpr_touchkey_driver);
index 970f2a6..b3ccc97 100644 (file)
@@ -221,13 +221,20 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static void ske_keypad_board_exit(void *data)
+{
+       struct ske_keypad *keypad = data;
+
+       keypad->board->exit();
+}
+
 static int __init ske_keypad_probe(struct platform_device *pdev)
 {
        const struct ske_keypad_platform_data *plat =
                        dev_get_platdata(&pdev->dev);
+       struct device *dev = &pdev->dev;
        struct ske_keypad *keypad;
        struct input_dev *input;
-       struct resource *res;
        int irq;
        int error;
 
@@ -238,20 +245,14 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
-               return -EINVAL;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "missing platform resources\n");
-               return -EINVAL;
-       }
+               return irq;
 
-       keypad = kzalloc(sizeof(struct ske_keypad), GFP_KERNEL);
-       input = input_allocate_device();
+       keypad = devm_kzalloc(dev, sizeof(struct ske_keypad),
+                             GFP_KERNEL);
+       input = devm_input_allocate_device(dev);
        if (!keypad || !input) {
                dev_err(&pdev->dev, "failed to allocate keypad memory\n");
-               error = -ENOMEM;
-               goto err_free_mem;
+               return -ENOMEM;
        }
 
        keypad->irq = irq;
@@ -259,31 +260,20 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
        keypad->input = input;
        spin_lock_init(&keypad->ske_keypad_lock);
 
-       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
-               dev_err(&pdev->dev, "failed to request I/O memory\n");
-               error = -EBUSY;
-               goto err_free_mem;
-       }
-
-       keypad->reg_base = ioremap(res->start, resource_size(res));
-       if (!keypad->reg_base) {
-               dev_err(&pdev->dev, "failed to remap I/O memory\n");
-               error = -ENXIO;
-               goto err_free_mem_region;
-       }
+       keypad->reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(keypad->reg_base))
+               return PTR_ERR(keypad->reg_base);
 
-       keypad->pclk = clk_get(&pdev->dev, "apb_pclk");
+       keypad->pclk = devm_clk_get_enabled(dev, "apb_pclk");
        if (IS_ERR(keypad->pclk)) {
                dev_err(&pdev->dev, "failed to get pclk\n");
-               error = PTR_ERR(keypad->pclk);
-               goto err_iounmap;
+               return PTR_ERR(keypad->pclk);
        }
 
-       keypad->clk = clk_get(&pdev->dev, NULL);
+       keypad->clk = devm_clk_get_enabled(dev, NULL);
        if (IS_ERR(keypad->clk)) {
                dev_err(&pdev->dev, "failed to get clk\n");
-               error = PTR_ERR(keypad->clk);
-               goto err_pclk;
+               return PTR_ERR(keypad->clk);
        }
 
        input->id.bustype = BUS_HOST;
@@ -295,48 +285,43 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
                                           keypad->keymap, input);
        if (error) {
                dev_err(&pdev->dev, "Failed to build keymap\n");
-               goto err_clk;
+               return error;
        }
 
        input_set_capability(input, EV_MSC, MSC_SCAN);
        if (!plat->no_autorepeat)
                __set_bit(EV_REP, input->evbit);
 
-       error = clk_prepare_enable(keypad->pclk);
-       if (error) {
-               dev_err(&pdev->dev, "Failed to prepare/enable pclk\n");
-               goto err_clk;
-       }
-
-       error = clk_prepare_enable(keypad->clk);
-       if (error) {
-               dev_err(&pdev->dev, "Failed to prepare/enable clk\n");
-               goto err_pclk_disable;
-       }
-
-
        /* go through board initialization helpers */
        if (keypad->board->init)
                keypad->board->init();
 
+       if (keypad->board->exit) {
+               error = devm_add_action_or_reset(dev, ske_keypad_board_exit,
+                                                keypad);
+               if (error)
+                       return error;
+       }
+
        error = ske_keypad_chip_init(keypad);
        if (error) {
                dev_err(&pdev->dev, "unable to init keypad hardware\n");
-               goto err_clk_disable;
+               return error;
        }
 
-       error = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq,
-                                    IRQF_ONESHOT, "ske-keypad", keypad);
+       error = devm_request_threaded_irq(dev, keypad->irq,
+                                         NULL, ske_keypad_irq,
+                                         IRQF_ONESHOT, "ske-keypad", keypad);
        if (error) {
                dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
-               goto err_clk_disable;
+               return error;
        }
 
        error = input_register_device(input);
        if (error) {
                dev_err(&pdev->dev,
-                               "unable to register input device: %d\n", error);
-               goto err_free_irq;
+                       "unable to register input device: %d\n", error);
+               return error;
        }
 
        if (plat->wakeup_enable)
@@ -344,47 +329,6 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, keypad);
 
-       return 0;
-
-err_free_irq:
-       free_irq(keypad->irq, keypad);
-err_clk_disable:
-       clk_disable_unprepare(keypad->clk);
-err_pclk_disable:
-       clk_disable_unprepare(keypad->pclk);
-err_clk:
-       clk_put(keypad->clk);
-err_pclk:
-       clk_put(keypad->pclk);
-err_iounmap:
-       iounmap(keypad->reg_base);
-err_free_mem_region:
-       release_mem_region(res->start, resource_size(res));
-err_free_mem:
-       input_free_device(input);
-       kfree(keypad);
-       return error;
-}
-
-static int ske_keypad_remove(struct platform_device *pdev)
-{
-       struct ske_keypad *keypad = platform_get_drvdata(pdev);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       free_irq(keypad->irq, keypad);
-
-       input_unregister_device(keypad->input);
-
-       clk_disable_unprepare(keypad->clk);
-       clk_put(keypad->clk);
-
-       if (keypad->board->exit)
-               keypad->board->exit();
-
-       iounmap(keypad->reg_base);
-       release_mem_region(res->start, resource_size(res));
-       kfree(keypad);
-
        return 0;
 }
 
@@ -424,7 +368,6 @@ static struct platform_driver ske_keypad_driver = {
                .name = "nmk-ske-keypad",
                .pm = pm_sleep_ptr(&ske_keypad_dev_pm_ops),
        },
-       .remove = ske_keypad_remove,
 };
 
 module_platform_driver_probe(ske_keypad_driver, ske_keypad_probe);
index e9fa142..096c18d 100644 (file)
@@ -186,8 +186,7 @@ static int nspire_keypad_probe(struct platform_device *pdev)
                return PTR_ERR(keypad->clk);
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       keypad->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       keypad->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(keypad->reg_base))
                return PTR_ERR(keypad->reg_base);
 
index 9f085d5..773e55e 100644 (file)
@@ -341,17 +341,10 @@ static int omap4_keypad_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct omap4_keypad *keypad_data;
        struct input_dev *input_dev;
-       struct resource *res;
        unsigned int max_keys;
        int irq;
        int error;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no base address specified\n");
-               return -EINVAL;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
@@ -370,7 +363,7 @@ static int omap4_keypad_probe(struct platform_device *pdev)
        if (error)
                return error;
 
-       keypad_data->base = devm_ioremap_resource(dev, res);
+       keypad_data->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(keypad_data->base))
                return PTR_ERR(keypad_data->base);
 
index b0ea387..7ffe1a7 100644 (file)
@@ -39,15 +39,8 @@ static int opencores_kbd_probe(struct platform_device *pdev)
 {
        struct input_dev *input;
        struct opencores_kbd *opencores_kbd;
-       struct resource *res;
        int irq, i, error;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "missing board memory resource\n");
-               return -EINVAL;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return -EINVAL;
@@ -65,7 +58,7 @@ static int opencores_kbd_probe(struct platform_device *pdev)
 
        opencores_kbd->input = input;
 
-       opencores_kbd->addr = devm_ioremap_resource(&pdev->dev, res);
+       opencores_kbd->addr = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(opencores_kbd->addr))
                return PTR_ERR(opencores_kbd->addr);
 
index 5548699..147b1f2 100644 (file)
@@ -318,40 +318,22 @@ static void ppkb_close(struct input_dev *input)
        ppkb_set_scan(client, false);
 }
 
-static void ppkb_regulator_disable(void *regulator)
-{
-       regulator_disable(regulator);
-}
-
 static int ppkb_probe(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        unsigned int phys_rows, phys_cols;
        struct pinephone_keyboard *ppkb;
-       struct regulator *vbat_supply;
        u8 info[PPKB_MATRIX_SIZE + 1];
        struct device_node *i2c_bus;
        int ret;
        int error;
 
-       vbat_supply = devm_regulator_get(dev, "vbat");
-       error = PTR_ERR_OR_ZERO(vbat_supply);
+       error = devm_regulator_get_enable(dev, "vbat");
        if (error) {
                dev_err(dev, "Failed to get VBAT supply: %d\n", error);
                return error;
        }
 
-       error = regulator_enable(vbat_supply);
-       if (error) {
-               dev_err(dev, "Failed to enable VBAT: %d\n", error);
-               return error;
-       }
-
-       error = devm_add_action_or_reset(dev, ppkb_regulator_disable,
-                                        vbat_supply);
-       if (error)
-               return error;
-
        ret = i2c_smbus_read_i2c_block_data(client, 0, sizeof(info), info);
        if (ret != sizeof(info)) {
                error = ret < 0 ? ret : -EIO;
@@ -455,7 +437,7 @@ static const struct of_device_id ppkb_of_match[] = {
 MODULE_DEVICE_TABLE(of, ppkb_of_match);
 
 static struct i2c_driver ppkb_driver = {
-       .probe_new      = ppkb_probe,
+       .probe          = ppkb_probe,
        .driver         = {
                .name           = DRV_NAME,
                .of_match_table = ppkb_of_match,
index 871f858..3724363 100644 (file)
@@ -717,7 +717,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct pxa27x_keypad *keypad;
        struct input_dev *input_dev;
-       struct resource *res;
        int irq, error;
 
        /* Driver need build keycode from device tree or pdata */
@@ -728,12 +727,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
        if (irq < 0)
                return -ENXIO;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "failed to get I/O memory\n");
-               return -ENXIO;
-       }
-
        keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad),
                              GFP_KERNEL);
        if (!keypad)
@@ -747,7 +740,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
        keypad->input_dev = input_dev;
        keypad->irq = irq;
 
-       keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+       keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(keypad->mmio_base))
                return PTR_ERR(keypad->mmio_base);
 
index 317fe2b..6953097 100644 (file)
@@ -588,7 +588,7 @@ static struct i2c_driver qt1050_driver = {
                .of_match_table = of_match_ptr(qt1050_of_match),
                .pm = pm_sleep_ptr(&qt1050_pm_ops),
        },
-       .probe_new = qt1050_probe,
+       .probe = qt1050_probe,
 };
 
 module_i2c_driver(qt1050_driver);
index fabb50b..91aaa9f 100644 (file)
@@ -271,7 +271,7 @@ static struct i2c_driver qt1070_driver = {
                .pm     = pm_sleep_ptr(&qt1070_pm_ops),
        },
        .id_table       = qt1070_id,
-       .probe_new      = qt1070_probe,
+       .probe          = qt1070_probe,
        .remove         = qt1070_remove,
 };
 
index 04d2ee6..599ea85 100644 (file)
@@ -460,7 +460,7 @@ static struct i2c_driver qt2160_driver = {
        },
 
        .id_table       = qt2160_idtable,
-       .probe_new      = qt2160_probe,
+       .probe          = qt2160_probe,
        .remove         = qt2160_remove,
 };
 
index 15c15c0..95d927c 100644 (file)
@@ -307,8 +307,7 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
 
        input_set_drvdata(lradc->input, lradc);
 
-       lradc->base = devm_ioremap_resource(dev,
-                             platform_get_resource(pdev, IORESOURCE_MEM, 0));
+       lradc->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(lradc->base))
                return PTR_ERR(lradc->base);
 
index 673b905..2f745ca 100644 (file)
@@ -350,7 +350,7 @@ static struct i2c_driver tca6416_keypad_driver = {
                .name   = "tca6416-keypad",
                .pm     = pm_sleep_ptr(&tca6416_keypad_dev_pm_ops),
        },
-       .probe_new      = tca6416_keypad_probe,
+       .probe          = tca6416_keypad_probe,
        .remove         = tca6416_keypad_remove,
        .id_table       = tca6416_id,
 };
index 3d7492f..76fc19f 100644 (file)
@@ -370,7 +370,7 @@ static struct i2c_driver tca8418_keypad_driver = {
                .name   = "tca8418_keypad",
                .of_match_table = tca8418_dt_ids,
        },
-       .probe_new      = tca8418_keypad_probe,
+       .probe          = tca8418_keypad_probe,
        .id_table       = tca8418_id,
 };
 
index d5a6c7d..c9a823e 100644 (file)
@@ -640,7 +640,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)
 
        timer_setup(&kbc->timer, tegra_kbc_keypress_timer, 0);
 
-       kbc->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+       kbc->mmio = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(kbc->mmio))
                return PTR_ERR(kbc->mmio);
 
index 4e20571..75bd3ea 100644 (file)
@@ -356,7 +356,7 @@ static struct i2c_driver tm2_touchkey_driver = {
                .pm = pm_sleep_ptr(&tm2_touchkey_pm_ops),
                .of_match_table = tm2_touchkey_of_match,
        },
-       .probe_new = tm2_touchkey_probe,
+       .probe = tm2_touchkey_probe,
        .id_table = tm2_touchkey_id_table,
 };
 module_i2c_driver(tm2_touchkey_driver);
index 81a54a5..c47eecc 100644 (file)
@@ -791,10 +791,10 @@ config INPUT_IQS626A
          module will be called iqs626a.
 
 config INPUT_IQS7222
-       tristate "Azoteq IQS7222A/B/C capacitive touch controller"
+       tristate "Azoteq IQS7222A/B/C/D capacitive touch controller"
        depends on I2C
        help
-         Say Y to enable support for the Azoteq IQS7222A/B/C family
+         Say Y to enable support for the Azoteq IQS7222A/B/C/D family
          of capacitive touch controllers.
 
          To compile this driver as a module, choose M here: the
index d8e39f4..679fcfe 100644 (file)
@@ -86,7 +86,7 @@ static struct i2c_driver ad714x_i2c_driver = {
                .name = "ad714x_captouch",
                .pm   = pm_sleep_ptr(&ad714x_pm),
        },
-       .probe_new = ad714x_i2c_probe,
+       .probe = ad714x_i2c_probe,
        .id_table = ad714x_id,
 };
 
index 1c75d98..6b880e2 100644 (file)
@@ -135,7 +135,7 @@ static struct i2c_driver adxl34x_driver = {
                .pm = pm_sleep_ptr(&adxl34x_pm),
                .of_match_table = adxl34x_of_id,
        },
-       .probe_new = adxl34x_i2c_probe,
+       .probe    = adxl34x_i2c_probe,
        .remove   = adxl34x_i2c_remove,
        .id_table = adxl34x_id,
 };
index eecca67..a3f45e0 100644 (file)
@@ -817,8 +817,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
        AC_WRITE(ac, POWER_CTL, 0);
 
        err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
-                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-                                  dev_name(dev), ac);
+                                  IRQF_ONESHOT, dev_name(dev), ac);
        if (err) {
                dev_err(dev, "irq %d busy?\n", ac->irq);
                goto err_free_mem;
index f42d321..b5219bb 100644 (file)
@@ -201,7 +201,7 @@ static struct i2c_driver apanel_driver = {
        .driver = {
                .name = APANEL,
        },
-       .probe_new      = apanel_probe,
+       .probe          = apanel_probe,
        .shutdown       = apanel_shutdown,
        .id_table       = apanel_id,
 };
index d9704b1..b6a3004 100644 (file)
@@ -263,7 +263,7 @@ static const struct i2c_device_id atmel_captouch_id[] = {
 MODULE_DEVICE_TABLE(i2c, atmel_captouch_id);
 
 static struct i2c_driver atmel_captouch_driver = {
-       .probe_new      = atmel_captouch_probe,
+       .probe          = atmel_captouch_probe,
        .id_table       = atmel_captouch_id,
        .driver         = {
                .name   = "atmel_captouch",
index 3f9da5c..0fb4cc6 100644 (file)
@@ -551,7 +551,7 @@ static struct i2c_driver bma150_driver = {
        },
        .class          = I2C_CLASS_HWMON,
        .id_table       = bma150_id,
-       .probe_new      = bma150_probe,
+       .probe          = bma150_probe,
        .remove         = bma150_remove,
 };
 
index 136eb37..a4dfb30 100644 (file)
@@ -97,7 +97,7 @@ static const struct i2c_device_id cma3000_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id);
 
 static struct i2c_driver cma3000_i2c_driver = {
-       .probe_new      = cma3000_i2c_probe,
+       .probe          = cma3000_i2c_probe,
        .remove         = cma3000_i2c_remove,
        .id_table       = cma3000_i2c_id,
        .driver = {
index b85a19e..ce82548 100644 (file)
@@ -1321,7 +1321,7 @@ static struct i2c_driver da7280_driver = {
                .of_match_table = of_match_ptr(da7280_of_match),
                .pm = pm_sleep_ptr(&da7280_pm_ops),
        },
-       .probe_new = da7280_probe,
+       .probe = da7280_probe,
        .id_table = da7280_i2c_id,
 };
 module_i2c_driver(da7280_driver);
index 8a9ebfc..6717e3c 100644 (file)
 
 /* Control 3 Register */
 #define DRV260X_LRA_OPEN_LOOP          (1 << 0)
-#define DRV260X_ANANLOG_IN                     (1 << 1)
+#define DRV260X_ANALOG_IN                      (1 << 1)
 #define DRV260X_LRA_DRV_MODE           (1 << 2)
 #define DRV260X_RTP_UNSIGNED_DATA      (1 << 3)
 #define DRV260X_SUPPLY_COMP_DIS                (1 << 4)
@@ -186,51 +186,13 @@ struct drv260x_data {
        struct work_struct work;
        struct gpio_desc *enable_gpio;
        struct regulator *regulator;
-       u32 magnitude;
+       u8 magnitude;
        u32 mode;
        u32 library;
        int rated_voltage;
        int overdrive_voltage;
 };
 
-static const struct reg_default drv260x_reg_defs[] = {
-       { DRV260X_STATUS, 0xe0 },
-       { DRV260X_MODE, 0x40 },
-       { DRV260X_RT_PB_IN, 0x00 },
-       { DRV260X_LIB_SEL, 0x00 },
-       { DRV260X_WV_SEQ_1, 0x01 },
-       { DRV260X_WV_SEQ_2, 0x00 },
-       { DRV260X_WV_SEQ_3, 0x00 },
-       { DRV260X_WV_SEQ_4, 0x00 },
-       { DRV260X_WV_SEQ_5, 0x00 },
-       { DRV260X_WV_SEQ_6, 0x00 },
-       { DRV260X_WV_SEQ_7, 0x00 },
-       { DRV260X_WV_SEQ_8, 0x00 },
-       { DRV260X_GO, 0x00 },
-       { DRV260X_OVERDRIVE_OFF, 0x00 },
-       { DRV260X_SUSTAIN_P_OFF, 0x00 },
-       { DRV260X_SUSTAIN_N_OFF, 0x00 },
-       { DRV260X_BRAKE_OFF, 0x00 },
-       { DRV260X_A_TO_V_CTRL, 0x05 },
-       { DRV260X_A_TO_V_MIN_INPUT, 0x19 },
-       { DRV260X_A_TO_V_MAX_INPUT, 0xff },
-       { DRV260X_A_TO_V_MIN_OUT, 0x19 },
-       { DRV260X_A_TO_V_MAX_OUT, 0xff },
-       { DRV260X_RATED_VOLT, 0x3e },
-       { DRV260X_OD_CLAMP_VOLT, 0x8c },
-       { DRV260X_CAL_COMP, 0x0c },
-       { DRV260X_CAL_BACK_EMF, 0x6c },
-       { DRV260X_FEEDBACK_CTRL, 0x36 },
-       { DRV260X_CTRL1, 0x93 },
-       { DRV260X_CTRL2, 0xfa },
-       { DRV260X_CTRL3, 0xa0 },
-       { DRV260X_CTRL4, 0x20 },
-       { DRV260X_CTRL5, 0x80 },
-       { DRV260X_LRA_LOOP_PERIOD, 0x33 },
-       { DRV260X_VBAT_MON, 0x00 },
-       { DRV260X_LRA_RES_PERIOD, 0x00 },
-};
-
 #define DRV260X_DEF_RATED_VOLT         0x90
 #define DRV260X_DEF_OD_CLAMP_VOLT      0x90
 
@@ -275,10 +237,11 @@ static int drv260x_haptics_play(struct input_dev *input, void *data,
 
        haptics->mode = DRV260X_LRA_NO_CAL_MODE;
 
+       /* Scale u16 magnitude into u8 register value */
        if (effect->u.rumble.strong_magnitude > 0)
-               haptics->magnitude = effect->u.rumble.strong_magnitude;
+               haptics->magnitude = effect->u.rumble.strong_magnitude >> 8;
        else if (effect->u.rumble.weak_magnitude > 0)
-               haptics->magnitude = effect->u.rumble.weak_magnitude;
+               haptics->magnitude = effect->u.rumble.weak_magnitude >> 8;
        else
                haptics->magnitude = 0;
 
@@ -304,7 +267,7 @@ static void drv260x_close(struct input_dev *input)
 
 static const struct reg_sequence drv260x_lra_cal_regs[] = {
        { DRV260X_MODE, DRV260X_AUTO_CAL },
-       { DRV260X_CTRL3, DRV260X_NG_THRESH_2 },
+       { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA },
        { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE |
                DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH },
 };
@@ -322,7 +285,7 @@ static const struct reg_sequence drv260x_lra_init_regs[] = {
                DRV260X_BEMF_GAIN_3 },
        { DRV260X_CTRL1, DRV260X_STARTUP_BOOST },
        { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 },
-       { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ANANLOG_IN },
+       { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA | DRV260X_ANALOG_IN },
        { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
 };
 
@@ -337,7 +300,7 @@ static const struct reg_sequence drv260x_erm_cal_regs[] = {
        { DRV260X_CTRL1, DRV260X_STARTUP_BOOST },
        { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 | DRV260X_BLANK_TIME_75 |
                DRV260X_IDISS_TIME_75 },
-       { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ERM_OPEN_LOOP },
+       { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA },
        { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
 };
 
@@ -435,6 +398,7 @@ static int drv260x_init(struct drv260x_data *haptics)
        }
 
        do {
+               usleep_range(15000, 15500);
                error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
                if (error) {
                        dev_err(&haptics->client->dev,
@@ -452,8 +416,6 @@ static const struct regmap_config drv260x_regmap_config = {
        .val_bits = 8,
 
        .max_register = DRV260X_MAX_REG,
-       .reg_defaults = drv260x_reg_defs,
-       .num_reg_defaults = ARRAY_SIZE(drv260x_reg_defs),
        .cache_type = REGCACHE_NONE,
 };
 
@@ -653,7 +615,7 @@ static const struct of_device_id drv260x_of_match[] = {
 MODULE_DEVICE_TABLE(of, drv260x_of_match);
 
 static struct i2c_driver drv260x_driver = {
-       .probe_new      = drv260x_probe,
+       .probe          = drv260x_probe,
        .driver         = {
                .name   = "drv260x-haptics",
                .of_match_table = drv260x_of_match,
index 9145096..de27e60 100644 (file)
@@ -297,7 +297,7 @@ MODULE_DEVICE_TABLE(of, drv2665_of_match);
 #endif
 
 static struct i2c_driver drv2665_driver = {
-       .probe_new      = drv2665_probe,
+       .probe          = drv2665_probe,
        .driver         = {
                .name   = "drv2665-haptics",
                .of_match_table = of_match_ptr(drv2665_of_match),
index 88b4dbe..11c5855 100644 (file)
@@ -474,7 +474,7 @@ MODULE_DEVICE_TABLE(of, drv2667_of_match);
 #endif
 
 static struct i2c_driver drv2667_driver = {
-       .probe_new      = drv2667_probe,
+       .probe          = drv2667_probe,
        .driver         = {
                .name   = "drv2667-haptics",
                .of_match_table = of_match_ptr(drv2667_of_match),
index 134a130..c1c3ba5 100644 (file)
@@ -113,22 +113,14 @@ static int gpio_vibrator_probe(struct platform_device *pdev)
                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;
-       }
+       if (IS_ERR(vibrator->vcc))
+               return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc),
+                                    "Failed to request regulator\n");
 
        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;
-       }
+       if (IS_ERR(vibrator->gpio))
+               return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->gpio),
+                                    "Failed to request main gpio\n");
 
        INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work);
 
index 3969ffc..867ac7a 100644 (file)
@@ -189,7 +189,7 @@ static struct i2c_driver ibm_panel_driver = {
                .name = DEVICE_NAME,
                .of_match_table = ibm_panel_match,
        },
-       .probe_new = ibm_panel_probe,
+       .probe = ibm_panel_probe,
        .remove = ibm_panel_remove,
 };
 module_i2c_driver(ibm_panel_driver);
index f4c3aff..1272ef7 100644 (file)
@@ -1746,7 +1746,7 @@ static struct i2c_driver iqs269_i2c_driver = {
                .of_match_table = iqs269_of_match,
                .pm = pm_sleep_ptr(&iqs269_pm),
        },
-       .probe_new = iqs269_probe,
+       .probe = iqs269_probe,
 };
 module_i2c_driver(iqs269_i2c_driver);
 
index 90f997a..50035c2 100644 (file)
@@ -1822,7 +1822,7 @@ static struct i2c_driver iqs626_i2c_driver = {
                .of_match_table = iqs626_of_match,
                .pm = pm_sleep_ptr(&iqs626_pm),
        },
-       .probe_new = iqs626_probe,
+       .probe = iqs626_probe,
 };
 module_i2c_driver(iqs626_i2c_driver);
 
index e47ab6c..a9c1dba 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Azoteq IQS7222A/B/C Capacitive Touch Controller
+ * Azoteq IQS7222A/B/C/D Capacitive Touch Controller
  *
  * Copyright (C) 2022 Jeff LaBundy <jeff@labundy.com>
  */
@@ -12,6 +12,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/touchscreen.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/ktime.h>
@@ -25,6 +26,7 @@
 #define IQS7222_PROD_NUM_A                     840
 #define IQS7222_PROD_NUM_B                     698
 #define IQS7222_PROD_NUM_C                     863
+#define IQS7222_PROD_NUM_D                     1046
 
 #define IQS7222_SYS_STATUS                     0x10
 #define IQS7222_SYS_STATUS_RESET               BIT(3)
@@ -54,6 +56,7 @@
 
 #define IQS7222_EVENT_MASK_ATI                 BIT(12)
 #define IQS7222_EVENT_MASK_SLDR                        BIT(10)
+#define IQS7222_EVENT_MASK_TPAD                        IQS7222_EVENT_MASK_SLDR
 #define IQS7222_EVENT_MASK_TOUCH               BIT(1)
 #define IQS7222_EVENT_MASK_PROX                        BIT(0)
 
@@ -71,6 +74,7 @@
 #define IQS7222_MAX_COLS_CHAN                  6
 #define IQS7222_MAX_COLS_FILT                  2
 #define IQS7222_MAX_COLS_SLDR                  11
+#define IQS7222_MAX_COLS_TPAD                  24
 #define IQS7222_MAX_COLS_GPIO                  3
 #define IQS7222_MAX_COLS_SYS                   13
 
@@ -102,16 +106,18 @@ enum iqs7222_reg_grp_id {
        IQS7222_REG_GRP_BTN,
        IQS7222_REG_GRP_CHAN,
        IQS7222_REG_GRP_SLDR,
+       IQS7222_REG_GRP_TPAD,
        IQS7222_REG_GRP_GPIO,
        IQS7222_REG_GRP_SYS,
        IQS7222_NUM_REG_GRPS
 };
 
 static const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = {
-       [IQS7222_REG_GRP_CYCLE] = "cycle",
-       [IQS7222_REG_GRP_CHAN] = "channel",
-       [IQS7222_REG_GRP_SLDR] = "slider",
-       [IQS7222_REG_GRP_GPIO] = "gpio",
+       [IQS7222_REG_GRP_CYCLE] = "cycle-%d",
+       [IQS7222_REG_GRP_CHAN] = "channel-%d",
+       [IQS7222_REG_GRP_SLDR] = "slider-%d",
+       [IQS7222_REG_GRP_TPAD] = "trackpad",
+       [IQS7222_REG_GRP_GPIO] = "gpio-%d",
 };
 
 static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = {
@@ -122,6 +128,7 @@ static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = {
        [IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN,
        [IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT,
        [IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR,
+       [IQS7222_REG_GRP_TPAD] = IQS7222_MAX_COLS_TPAD,
        [IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO,
        [IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS,
 };
@@ -130,8 +137,10 @@ static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, };
 
 struct iqs7222_event_desc {
        const char *name;
+       u16 link;
        u16 mask;
        u16 val;
+       u16 strict;
        u16 enable;
        enum iqs7222_reg_key_id reg_key;
 };
@@ -188,6 +197,93 @@ static const struct iqs7222_event_desc iqs7222_sl_events[] = {
        },
 };
 
+static const struct iqs7222_event_desc iqs7222_tp_events[] = {
+       {
+               .name = "event-press",
+               .link = BIT(7),
+       },
+       {
+               .name = "event-tap",
+               .link = BIT(0),
+               .mask = BIT(0),
+               .val = BIT(0),
+               .enable = BIT(0),
+               .reg_key = IQS7222_REG_KEY_TAP,
+       },
+       {
+               .name = "event-swipe-x-pos",
+               .link = BIT(2),
+               .mask = BIT(2) | BIT(1),
+               .val = BIT(2),
+               .strict = BIT(4),
+               .enable = BIT(1),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+       {
+               .name = "event-swipe-y-pos",
+               .link = BIT(3),
+               .mask = BIT(3) | BIT(1),
+               .val = BIT(3),
+               .strict = BIT(3),
+               .enable = BIT(1),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+       {
+               .name = "event-swipe-x-neg",
+               .link = BIT(4),
+               .mask = BIT(4) | BIT(1),
+               .val = BIT(4),
+               .strict = BIT(4),
+               .enable = BIT(1),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+       {
+               .name = "event-swipe-y-neg",
+               .link = BIT(5),
+               .mask = BIT(5) | BIT(1),
+               .val = BIT(5),
+               .strict = BIT(3),
+               .enable = BIT(1),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+       {
+               .name = "event-flick-x-pos",
+               .link = BIT(2),
+               .mask = BIT(2) | BIT(1),
+               .val = BIT(2) | BIT(1),
+               .strict = BIT(4),
+               .enable = BIT(2),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+       {
+               .name = "event-flick-y-pos",
+               .link = BIT(3),
+               .mask = BIT(3) | BIT(1),
+               .val = BIT(3) | BIT(1),
+               .strict = BIT(3),
+               .enable = BIT(2),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+       {
+               .name = "event-flick-x-neg",
+               .link = BIT(4),
+               .mask = BIT(4) | BIT(1),
+               .val = BIT(4) | BIT(1),
+               .strict = BIT(4),
+               .enable = BIT(2),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+       {
+               .name = "event-flick-y-neg",
+               .link = BIT(5),
+               .mask = BIT(5) | BIT(1),
+               .val = BIT(5) | BIT(1),
+               .strict = BIT(3),
+               .enable = BIT(2),
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+       },
+};
+
 struct iqs7222_reg_grp_desc {
        u16 base;
        int num_row;
@@ -524,6 +620,62 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
                        },
                },
        },
+       {
+               .prod_num = IQS7222_PROD_NUM_D,
+               .fw_major = 0,
+               .fw_minor = 37,
+               .touch_link = 1770,
+               .allow_offset = 9,
+               .event_offset = 10,
+               .comms_offset = 11,
+               .reg_grps = {
+                       [IQS7222_REG_GRP_STAT] = {
+                               .base = IQS7222_SYS_STATUS,
+                               .num_row = 1,
+                               .num_col = 7,
+                       },
+                       [IQS7222_REG_GRP_CYCLE] = {
+                               .base = 0x8000,
+                               .num_row = 7,
+                               .num_col = 2,
+                       },
+                       [IQS7222_REG_GRP_GLBL] = {
+                               .base = 0x8700,
+                               .num_row = 1,
+                               .num_col = 3,
+                       },
+                       [IQS7222_REG_GRP_BTN] = {
+                               .base = 0x9000,
+                               .num_row = 14,
+                               .num_col = 3,
+                       },
+                       [IQS7222_REG_GRP_CHAN] = {
+                               .base = 0xA000,
+                               .num_row = 14,
+                               .num_col = 4,
+                       },
+                       [IQS7222_REG_GRP_FILT] = {
+                               .base = 0xAE00,
+                               .num_row = 1,
+                               .num_col = 2,
+                       },
+                       [IQS7222_REG_GRP_TPAD] = {
+                               .base = 0xB000,
+                               .num_row = 1,
+                               .num_col = 24,
+                       },
+                       [IQS7222_REG_GRP_GPIO] = {
+                               .base = 0xC000,
+                               .num_row = 3,
+                               .num_col = 3,
+                       },
+                       [IQS7222_REG_GRP_SYS] = {
+                               .base = IQS7222_SYS_SETUP,
+                               .num_row = 1,
+                               .num_col = 12,
+                       },
+               },
+       },
 };
 
 struct iqs7222_prop_desc {
@@ -1008,6 +1160,123 @@ static const struct iqs7222_prop_desc iqs7222_props[] = {
                .val_pitch = 4,
                .label = "maximum gesture time",
        },
+       {
+               .name = "azoteq,num-rows",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 0,
+               .reg_shift = 4,
+               .reg_width = 4,
+               .val_min = 1,
+               .val_max = 12,
+               .label = "number of rows",
+       },
+       {
+               .name = "azoteq,num-cols",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 0,
+               .reg_shift = 0,
+               .reg_width = 4,
+               .val_min = 1,
+               .val_max = 12,
+               .label = "number of columns",
+       },
+       {
+               .name = "azoteq,lower-cal-y",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 1,
+               .reg_shift = 8,
+               .reg_width = 8,
+               .label = "lower vertical calibration",
+       },
+       {
+               .name = "azoteq,lower-cal-x",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 1,
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "lower horizontal calibration",
+       },
+       {
+               .name = "azoteq,upper-cal-y",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 2,
+               .reg_shift = 8,
+               .reg_width = 8,
+               .label = "upper vertical calibration",
+       },
+       {
+               .name = "azoteq,upper-cal-x",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 2,
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "upper horizontal calibration",
+       },
+       {
+               .name = "azoteq,top-speed",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 3,
+               .reg_shift = 8,
+               .reg_width = 8,
+               .val_pitch = 4,
+               .label = "top speed",
+       },
+       {
+               .name = "azoteq,bottom-speed",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_offset = 3,
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "bottom speed",
+       },
+       {
+               .name = "azoteq,gesture-min-ms",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_key = IQS7222_REG_KEY_TAP,
+               .reg_offset = 20,
+               .reg_shift = 8,
+               .reg_width = 8,
+               .val_pitch = 16,
+               .label = "minimum gesture time",
+       },
+       {
+               .name = "azoteq,gesture-max-ms",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+               .reg_offset = 21,
+               .reg_shift = 8,
+               .reg_width = 8,
+               .val_pitch = 16,
+               .label = "maximum gesture time",
+       },
+       {
+               .name = "azoteq,gesture-max-ms",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_key = IQS7222_REG_KEY_TAP,
+               .reg_offset = 21,
+               .reg_shift = 0,
+               .reg_width = 8,
+               .val_pitch = 16,
+               .label = "maximum gesture time",
+       },
+       {
+               .name = "azoteq,gesture-dist",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_key = IQS7222_REG_KEY_TAP,
+               .reg_offset = 22,
+               .reg_shift = 0,
+               .reg_width = 16,
+               .label = "gesture distance",
+       },
+       {
+               .name = "azoteq,gesture-dist",
+               .reg_grp = IQS7222_REG_GRP_TPAD,
+               .reg_key = IQS7222_REG_KEY_AXIAL,
+               .reg_offset = 23,
+               .reg_shift = 0,
+               .reg_width = 16,
+               .label = "gesture distance",
+       },
        {
                .name = "drive-open-drain",
                .reg_grp = IQS7222_REG_GRP_GPIO,
@@ -1091,16 +1360,19 @@ struct iqs7222_private {
        struct gpio_desc *irq_gpio;
        struct i2c_client *client;
        struct input_dev *keypad;
+       struct touchscreen_properties prop;
        unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
        unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
        unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)];
        unsigned int sl_axis[IQS7222_MAX_SLDR];
+       unsigned int tp_code[ARRAY_SIZE(iqs7222_tp_events)];
        u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE];
        u16 glbl_setup[IQS7222_MAX_COLS_GLBL];
        u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN];
        u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN];
        u16 filt_setup[IQS7222_MAX_COLS_FILT];
        u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR];
+       u16 tpad_setup[IQS7222_MAX_COLS_TPAD];
        u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO];
        u16 sys_setup[IQS7222_MAX_COLS_SYS];
 };
@@ -1127,6 +1399,9 @@ static u16 *iqs7222_setup(struct iqs7222_private *iqs7222,
        case IQS7222_REG_GRP_SLDR:
                return iqs7222->sldr_setup[row];
 
+       case IQS7222_REG_GRP_TPAD:
+               return iqs7222->tpad_setup;
+
        case IQS7222_REG_GRP_GPIO:
                return iqs7222->gpio_setup[row];
 
@@ -1381,9 +1656,6 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
        if (error)
                return error;
 
-       sys_setup &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
-       sys_setup &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
-
        for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
                /*
                 * Trigger ATI from streaming and normal-power modes so that
@@ -1561,8 +1833,11 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
                        return error;
        }
 
-       if (dir == READ)
+       if (dir == READ) {
+               iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
+               iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
                return 0;
+       }
 
        return iqs7222_ati_trigger(iqs7222);
 }
@@ -1936,6 +2211,14 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
                ref_setup[4] = dev_desc->touch_link;
                if (fwnode_property_present(chan_node, "azoteq,use-prox"))
                        ref_setup[4] -= 2;
+       } else if (dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row &&
+                  fwnode_property_present(chan_node,
+                                          "azoteq,counts-filt-enable")) {
+               /*
+                * In the case of IQS7222D, however, the reference mode field
+                * is partially repurposed as a counts filter enable control.
+                */
+               chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
        }
 
        if (fwnode_property_present(chan_node, "azoteq,rx-enable")) {
@@ -2278,6 +2561,136 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
                                   IQS7222_REG_KEY_NO_WHEEL);
 }
 
+static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222,
+                             struct fwnode_handle *tpad_node, int tpad_index)
+{
+       const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
+       struct touchscreen_properties *prop = &iqs7222->prop;
+       struct i2c_client *client = iqs7222->client;
+       int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
+       int count, error, i;
+       u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
+       u16 *tpad_setup = iqs7222->tpad_setup;
+       unsigned int chan_sel[12];
+
+       error = iqs7222_parse_props(iqs7222, tpad_node, tpad_index,
+                                   IQS7222_REG_GRP_TPAD,
+                                   IQS7222_REG_KEY_NONE);
+       if (error)
+               return error;
+
+       count = fwnode_property_count_u32(tpad_node, "azoteq,channel-select");
+       if (count < 0) {
+               dev_err(&client->dev, "Failed to count %s channels: %d\n",
+                       fwnode_get_name(tpad_node), count);
+               return count;
+       } else if (!count || count > ARRAY_SIZE(chan_sel)) {
+               dev_err(&client->dev, "Invalid number of %s channels\n",
+                       fwnode_get_name(tpad_node));
+               return -EINVAL;
+       }
+
+       error = fwnode_property_read_u32_array(tpad_node,
+                                              "azoteq,channel-select",
+                                              chan_sel, count);
+       if (error) {
+               dev_err(&client->dev, "Failed to read %s channels: %d\n",
+                       fwnode_get_name(tpad_node), error);
+               return error;
+       }
+
+       tpad_setup[6] &= ~GENMASK(num_chan - 1, 0);
+
+       for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
+               tpad_setup[8 + i] = 0;
+               if (i >= count || chan_sel[i] == U8_MAX)
+                       continue;
+
+               if (chan_sel[i] >= num_chan) {
+                       dev_err(&client->dev, "Invalid %s channel: %u\n",
+                               fwnode_get_name(tpad_node), chan_sel[i]);
+                       return -EINVAL;
+               }
+
+               /*
+                * The following fields indicate which channels participate in
+                * the trackpad, as well as each channel's relative placement.
+                */
+               tpad_setup[6] |= BIT(chan_sel[i]);
+               tpad_setup[8 + i] = chan_sel[i] * 34 + 1072;
+       }
+
+       tpad_setup[7] = dev_desc->touch_link;
+       if (fwnode_property_present(tpad_node, "azoteq,use-prox"))
+               tpad_setup[7] -= 2;
+
+       for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++)
+               tpad_setup[20] &= ~(iqs7222_tp_events[i].strict |
+                                   iqs7222_tp_events[i].enable);
+
+       for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) {
+               const char *event_name = iqs7222_tp_events[i].name;
+               struct fwnode_handle *event_node;
+
+               event_node = fwnode_get_named_child_node(tpad_node, event_name);
+               if (!event_node)
+                       continue;
+
+               if (fwnode_property_present(event_node,
+                                           "azoteq,gesture-angle-tighten"))
+                       tpad_setup[20] |= iqs7222_tp_events[i].strict;
+
+               tpad_setup[20] |= iqs7222_tp_events[i].enable;
+
+               error = iqs7222_parse_event(iqs7222, event_node, tpad_index,
+                                           IQS7222_REG_GRP_TPAD,
+                                           iqs7222_tp_events[i].reg_key,
+                                           iqs7222_tp_events[i].link, 1566,
+                                           NULL,
+                                           &iqs7222->tp_code[i]);
+               fwnode_handle_put(event_node);
+               if (error)
+                       return error;
+
+               if (!dev_desc->event_offset)
+                       continue;
+
+               /*
+                * The press/release event is determined based on whether the
+                * coordinate fields report 0xFFFF and solely relies on touch
+                * or proximity interrupts to be unmasked.
+                */
+               if (i)
+                       *event_mask |= IQS7222_EVENT_MASK_TPAD;
+               else if (tpad_setup[7] == dev_desc->touch_link)
+                       *event_mask |= IQS7222_EVENT_MASK_TOUCH;
+               else
+                       *event_mask |= IQS7222_EVENT_MASK_PROX;
+       }
+
+       if (!iqs7222->tp_code[0])
+               return 0;
+
+       input_set_abs_params(iqs7222->keypad, ABS_X,
+                            0, (tpad_setup[4] ? : 1) - 1, 0, 0);
+
+       input_set_abs_params(iqs7222->keypad, ABS_Y,
+                            0, (tpad_setup[5] ? : 1) - 1, 0, 0);
+
+       touchscreen_parse_properties(iqs7222->keypad, false, prop);
+
+       if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) {
+               dev_err(&client->dev, "Invalid trackpad size: %u*%u\n",
+                       prop->max_x, prop->max_y);
+               return -EINVAL;
+       }
+
+       tpad_setup[4] = prop->max_x + 1;
+       tpad_setup[5] = prop->max_y + 1;
+
+       return 0;
+}
+
 static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS])
                                (struct iqs7222_private *iqs7222,
                                 struct fwnode_handle *reg_grp_node,
@@ -2285,6 +2698,7 @@ static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS])
        [IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle,
        [IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan,
        [IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr,
+       [IQS7222_REG_GRP_TPAD] = iqs7222_parse_tpad,
 };
 
 static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
@@ -2298,7 +2712,7 @@ static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
        if (iqs7222_reg_grp_names[reg_grp]) {
                char reg_grp_name[16];
 
-               snprintf(reg_grp_name, sizeof(reg_grp_name), "%s-%d",
+               snprintf(reg_grp_name, sizeof(reg_grp_name),
                         iqs7222_reg_grp_names[reg_grp], reg_grp_index);
 
                reg_grp_node = device_get_named_child_node(&client->dev,
@@ -2346,8 +2760,8 @@ static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
                        continue;
 
                /*
-                * The IQS7222C exposes multiple GPIO and must be informed
-                * as to which GPIO this group represents.
+                * The IQS7222C and IQS7222D expose multiple GPIO and must be
+                * informed as to which GPIO this group represents.
                 */
                for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++)
                        gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]);
@@ -2480,6 +2894,41 @@ static int iqs7222_report(struct iqs7222_private *iqs7222)
                                         iqs7222->sl_code[i][j], 0);
        }
 
+       for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row; i++) {
+               u16 tpad_pos_x = le16_to_cpu(status[4]);
+               u16 tpad_pos_y = le16_to_cpu(status[5]);
+               u16 state = le16_to_cpu(status[6]);
+
+               input_report_key(iqs7222->keypad, iqs7222->tp_code[0],
+                                tpad_pos_x < U16_MAX);
+
+               if (tpad_pos_x < U16_MAX)
+                       touchscreen_report_pos(iqs7222->keypad, &iqs7222->prop,
+                                              tpad_pos_x, tpad_pos_y, false);
+
+               if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_TPAD))
+                       continue;
+
+               /*
+                * Skip the press/release event, as it does not have separate
+                * status fields and is handled separately.
+                */
+               for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) {
+                       u16 mask = iqs7222_tp_events[j].mask;
+                       u16 val = iqs7222_tp_events[j].val;
+
+                       input_report_key(iqs7222->keypad,
+                                        iqs7222->tp_code[j],
+                                        (state & mask) == val);
+               }
+
+               input_sync(iqs7222->keypad);
+
+               for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++)
+                       input_report_key(iqs7222->keypad,
+                                        iqs7222->tp_code[j], 0);
+       }
+
        input_sync(iqs7222->keypad);
 
        return 0;
@@ -2584,6 +3033,7 @@ static const struct of_device_id iqs7222_of_match[] = {
        { .compatible = "azoteq,iqs7222a" },
        { .compatible = "azoteq,iqs7222b" },
        { .compatible = "azoteq,iqs7222c" },
+       { .compatible = "azoteq,iqs7222d" },
        { }
 };
 MODULE_DEVICE_TABLE(of, iqs7222_of_match);
@@ -2593,10 +3043,10 @@ static struct i2c_driver iqs7222_i2c_driver = {
                .name = "iqs7222",
                .of_match_table = iqs7222_of_match,
        },
-       .probe_new = iqs7222_probe,
+       .probe = iqs7222_probe,
 };
 module_i2c_driver(iqs7222_i2c_driver);
 
 MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
-MODULE_DESCRIPTION("Azoteq IQS7222A/B/C Capacitive Touch Controller");
+MODULE_DESCRIPTION("Azoteq IQS7222A/B/C/D Capacitive Touch Controller");
 MODULE_LICENSE("GPL");
index 4e806d5..912e614 100644 (file)
@@ -538,7 +538,7 @@ static struct i2c_driver kxtj9_driver = {
                .name   = NAME,
                .pm     = pm_sleep_ptr(&kxtj9_pm_ops),
        },
-       .probe_new      = kxtj9_probe,
+       .probe          = kxtj9_probe,
        .id_table       = kxtj9_id,
 };
 
index b121525..76a190b 100644 (file)
@@ -202,7 +202,7 @@ static struct i2c_driver mma8450_driver = {
                .name   = MMA8450_DRV_NAME,
                .of_match_table = mma8450_dt_ids,
        },
-       .probe_new      = mma8450_probe,
+       .probe          = mma8450_probe,
        .id_table       = mma8450_id,
 };
 
index 6323c3d..536cede 100644 (file)
@@ -199,7 +199,7 @@ static struct i2c_driver pcf8574_kp_driver = {
                .name  = DRV_NAME,
                .pm = pm_sleep_ptr(&pcf8574_kp_pm_ops),
        },
-       .probe_new = pcf8574_kp_probe,
+       .probe    = pcf8574_kp_probe,
        .remove   = pcf8574_kp_remove,
        .id_table = pcf8574_kp_id,
 };
index b6a27eb..74d77d8 100644 (file)
 #define  PON_RESIN_PULL_UP             BIT(0)
 
 #define PON_DBC_CTL                    0x71
-#define  PON_DBC_DELAY_MASK            0x7
+#define  PON_DBC_DELAY_MASK_GEN1       0x7
+#define  PON_DBC_DELAY_MASK_GEN2       0xf
+#define  PON_DBC_SHIFT_GEN1            6
+#define  PON_DBC_SHIFT_GEN2            14
 
 struct pm8941_data {
        unsigned int    pull_up_bit;
@@ -247,7 +250,7 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
        struct device *parent;
        struct device_node *regmap_node;
        const __be32 *addr;
-       u32 req_delay;
+       u32 req_delay, mask, delay_shift;
        int error;
 
        if (of_property_read_u32(pdev->dev.of_node, "debounce", &req_delay))
@@ -336,12 +339,20 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
        pwrkey->input->phys = pwrkey->data->phys;
 
        if (pwrkey->data->supports_debounce_config) {
-               req_delay = (req_delay << 6) / USEC_PER_SEC;
+               if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY) {
+                       mask = PON_DBC_DELAY_MASK_GEN2;
+                       delay_shift = PON_DBC_SHIFT_GEN2;
+               } else {
+                       mask = PON_DBC_DELAY_MASK_GEN1;
+                       delay_shift = PON_DBC_SHIFT_GEN1;
+               }
+
+               req_delay = (req_delay << delay_shift) / USEC_PER_SEC;
                req_delay = ilog2(req_delay);
 
                error = regmap_update_bits(pwrkey->regmap,
                                           pwrkey->baseaddr + PON_DBC_CTL,
-                                          PON_DBC_DELAY_MASK,
+                                          mask,
                                           req_delay);
                if (error) {
                        dev_err(&pdev->dev, "failed to set debounce: %d\n",
index 3cf1812..1e731d8 100644 (file)
@@ -132,13 +132,8 @@ static int pwm_beeper_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        beeper->pwm = devm_pwm_get(dev, NULL);
-       if (IS_ERR(beeper->pwm)) {
-               error = PTR_ERR(beeper->pwm);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to request PWM device: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(beeper->pwm))
+               return dev_err_probe(dev, PTR_ERR(beeper->pwm), "Failed to request PWM device\n");
 
        /* Sync up PWM state and ensure it is off. */
        pwm_init_state(beeper->pwm, &state);
@@ -151,13 +146,9 @@ static int pwm_beeper_probe(struct platform_device *pdev)
        }
 
        beeper->amplifier = devm_regulator_get(dev, "amp");
-       if (IS_ERR(beeper->amplifier)) {
-               error = PTR_ERR(beeper->amplifier);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get 'amp' regulator: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(beeper->amplifier))
+               return dev_err_probe(dev, PTR_ERR(beeper->amplifier),
+                                    "Failed to get 'amp' regulator\n");
 
        INIT_WORK(&beeper->work, pwm_beeper_work);
 
index d0e58a7..a3cde30 100644 (file)
@@ -11,6 +11,7 @@
  *  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>
@@ -23,6 +24,7 @@
 
 struct pwm_vibrator {
        struct input_dev *input;
+       struct gpio_desc *enable_gpio;
        struct pwm_device *pwm;
        struct pwm_device *pwm_dir;
        struct regulator *vcc;
@@ -42,19 +44,21 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
        if (!vibrator->vcc_on) {
                err = regulator_enable(vibrator->vcc);
                if (err) {
-                       dev_err(pdev, "failed to enable regulator: %d", err);
+                       dev_err(pdev, "failed to enable regulator: %d\n", err);
                        return err;
                }
                vibrator->vcc_on = true;
        }
 
+       gpiod_set_value_cansleep(vibrator->enable_gpio, 1);
+
        pwm_get_state(vibrator->pwm, &state);
        pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff);
        state.enabled = true;
 
        err = pwm_apply_state(vibrator->pwm, &state);
        if (err) {
-               dev_err(pdev, "failed to apply pwm state: %d", err);
+               dev_err(pdev, "failed to apply pwm state: %d\n", err);
                return err;
        }
 
@@ -65,7 +69,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
 
                err = pwm_apply_state(vibrator->pwm_dir, &state);
                if (err) {
-                       dev_err(pdev, "failed to apply dir-pwm state: %d", err);
+                       dev_err(pdev, "failed to apply dir-pwm state: %d\n", err);
                        pwm_disable(vibrator->pwm);
                        return err;
                }
@@ -80,6 +84,8 @@ static void pwm_vibrator_stop(struct pwm_vibrator *vibrator)
                pwm_disable(vibrator->pwm_dir);
        pwm_disable(vibrator->pwm);
 
+       gpiod_set_value_cansleep(vibrator->enable_gpio, 0);
+
        if (vibrator->vcc_on) {
                regulator_disable(vibrator->vcc);
                vibrator->vcc_on = false;
@@ -134,22 +140,20 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
                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",
-                               err);
-               return err;
-       }
+       if (IS_ERR(vibrator->vcc))
+               return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc),
+                                    "Failed to request regulator\n");
+
+       vibrator->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+                                                       GPIOD_OUT_LOW);
+       if (IS_ERR(vibrator->enable_gpio))
+               return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->enable_gpio),
+                                    "Failed to request enable gpio\n");
 
        vibrator->pwm = devm_pwm_get(&pdev->dev, "enable");
-       err = PTR_ERR_OR_ZERO(vibrator->pwm);
-       if (err) {
-               if (err != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "Failed to request main pwm: %d",
-                               err);
-               return err;
-       }
+       if (IS_ERR(vibrator->pwm))
+               return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->pwm),
+                                    "Failed to request main pwm\n");
 
        INIT_WORK(&vibrator->play_work, pwm_vibrator_play_work);
 
@@ -158,7 +162,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
        state.enabled = false;
        err = pwm_apply_state(vibrator->pwm, &state);
        if (err) {
-               dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
+               dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
                        err);
                return err;
        }
@@ -172,7 +176,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
                state.enabled = false;
                err = pwm_apply_state(vibrator->pwm_dir, &state);
                if (err) {
-                       dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
+                       dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
                                err);
                        return err;
                }
@@ -189,7 +193,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
                break;
 
        default:
-               dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
+               dev_err(&pdev->dev, "Failed to request direction pwm: %d\n", err);
                fallthrough;
 
        case -EPROBE_DEFER:
@@ -207,13 +211,13 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
        err = input_ff_create_memless(vibrator->input, NULL,
                                      pwm_vibrator_play_effect);
        if (err) {
-               dev_err(&pdev->dev, "Couldn't create FF dev: %d", 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", err);
+               dev_err(&pdev->dev, "Couldn't register input dev: %d\n", err);
                return err;
        }
 
index 22ec620..e94cab8 100644 (file)
@@ -236,12 +236,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
                device_property_read_bool(dev, "rotary-encoder,relative-axis");
 
        encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
-       if (IS_ERR(encoder->gpios)) {
-               err = PTR_ERR(encoder->gpios);
-               if (err != -EPROBE_DEFER)
-                       dev_err(dev, "unable to get gpios: %d\n", err);
-               return err;
-       }
+       if (IS_ERR(encoder->gpios))
+               return dev_err_probe(dev, PTR_ERR(encoder->gpios), "unable to get gpios\n");
        if (encoder->gpios->ndescs < 2) {
                dev_err(dev, "not enough gpios found\n");
                return -EINVAL;
@@ -255,7 +251,6 @@ static int rotary_encoder_probe(struct platform_device *pdev)
 
        input->name = pdev->name;
        input->id.bustype = BUS_HOST;
-       input->dev.parent = dev;
 
        if (encoder->relative_axis)
                input_set_capability(input, EV_REL, encoder->axis);
index 245134b..eeb9f23 100644 (file)
@@ -117,14 +117,16 @@ static int tps65219_pb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int tps65219_pb_remove(struct platform_device *pdev)
+static void tps65219_pb_remove(struct platform_device *pdev)
 {
        struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
+       int ret;
 
        /* Disable interrupt for the pushbutton */
-       return regmap_update_bits(tps->regmap, TPS65219_REG_MASK_CONFIG,
-                                 TPS65219_REG_MASK_INT_FOR_PB_MASK,
-                                 TPS65219_REG_MASK_INT_FOR_PB_MASK);
+       ret = regmap_set_bits(tps->regmap, TPS65219_REG_MASK_CONFIG,
+                             TPS65219_REG_MASK_INT_FOR_PB_MASK);
+       if (ret)
+               dev_warn(&pdev->dev, "Failed to disable irq (%pe)\n", ERR_PTR(ret));
 }
 
 static const struct platform_device_id tps65219_pwrbtn_id_table[] = {
@@ -135,7 +137,7 @@ MODULE_DEVICE_TABLE(platform, tps65219_pwrbtn_id_table);
 
 static struct platform_driver tps65219_pb_driver = {
        .probe = tps65219_pb_probe,
-       .remove = tps65219_pb_remove,
+       .remove_new = tps65219_pb_remove,
        .driver = {
                .name = "tps65219_pwrbutton",
        },
index f259313..d98212d 100644 (file)
@@ -33,6 +33,7 @@
 #define UINPUT_NAME            "uinput"
 #define UINPUT_BUFFER_SIZE     16
 #define UINPUT_NUM_REQUESTS    16
+#define UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS 10
 
 enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
 
@@ -569,11 +570,40 @@ static int uinput_setup_device_legacy(struct uinput_device *udev,
        return retval;
 }
 
+/*
+ * Returns true if the given timestamp is valid (i.e., if all the following
+ * conditions are satisfied), false otherwise.
+ * 1) given timestamp is positive
+ * 2) it's within the allowed offset before the current time
+ * 3) it's not in the future
+ */
+static bool is_valid_timestamp(const ktime_t timestamp)
+{
+       ktime_t zero_time;
+       ktime_t current_time;
+       ktime_t min_time;
+       ktime_t offset;
+
+       zero_time = ktime_set(0, 0);
+       if (ktime_compare(zero_time, timestamp) >= 0)
+               return false;
+
+       current_time = ktime_get();
+       offset = ktime_set(UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS, 0);
+       min_time = ktime_sub(current_time, offset);
+
+       if (ktime_after(min_time, timestamp) || ktime_after(timestamp, current_time))
+               return false;
+
+       return true;
+}
+
 static ssize_t uinput_inject_events(struct uinput_device *udev,
                                    const char __user *buffer, size_t count)
 {
        struct input_event ev;
        size_t bytes = 0;
+       ktime_t timestamp;
 
        if (count != 0 && count < input_event_size())
                return -EINVAL;
@@ -588,6 +618,10 @@ static ssize_t uinput_inject_events(struct uinput_device *udev,
                if (input_event_from_user(buffer + bytes, &ev))
                        return -EFAULT;
 
+               timestamp = ktime_set(ev.input_event_sec, ev.input_event_usec * NSEC_PER_USEC);
+               if (is_valid_timestamp(timestamp))
+                       input_set_timestamp(udev->dev, timestamp);
+
                input_event(udev->dev, ev.type, ev.code, ev.value);
                bytes += input_event_size();
                cond_resched();
index dd7b0d7..05851bc 100644 (file)
@@ -1489,7 +1489,7 @@ static struct i2c_driver cyapa_driver = {
                .of_match_table = of_match_ptr(cyapa_of_match),
        },
 
-       .probe_new = cyapa_probe,
+       .probe = cyapa_probe,
        .id_table = cyapa_id_table,
 };
 
index 5f0d75a..148a601 100644 (file)
@@ -1221,13 +1221,8 @@ static int elan_probe(struct i2c_client *client)
        mutex_init(&data->sysfs_mutex);
 
        data->vcc = devm_regulator_get(dev, "vcc");
-       if (IS_ERR(data->vcc)) {
-               error = PTR_ERR(data->vcc);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get 'vcc' regulator: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(data->vcc))
+               return dev_err_probe(dev, PTR_ERR(data->vcc), "Failed to get 'vcc' regulator\n");
 
        error = regulator_enable(data->vcc);
        if (error) {
@@ -1424,7 +1419,7 @@ static struct i2c_driver elan_driver = {
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
                .dev_groups = elan_sysfs_groups,
        },
-       .probe_new      = elan_probe,
+       .probe          = elan_probe,
        .id_table       = elan_id,
 };
 
index c9a7e87..a0aac76 100644 (file)
@@ -116,6 +116,13 @@ static DEFINE_MUTEX(psmouse_mutex);
 
 static struct workqueue_struct *kpsmoused_wq;
 
+struct psmouse *psmouse_from_serio(struct serio *serio)
+{
+       struct ps2dev *ps2dev = serio_get_drvdata(serio);
+
+       return container_of(ps2dev, struct psmouse, ps2dev);
+}
+
 void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons)
 {
        input_report_key(dev, BTN_LEFT,   buttons & BIT(0));
@@ -329,17 +336,14 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data)
        }
 }
 
-/*
- * psmouse_interrupt() handles incoming characters, either passing them
- * for normal processing or gathering them as command response.
- */
-static irqreturn_t psmouse_interrupt(struct serio *serio,
-                                    u8 data, unsigned int flags)
+static enum ps2_disposition psmouse_pre_receive_byte(struct ps2dev *ps2dev,
+                                                    u8 data,
+                                                    unsigned int flags)
 {
-       struct psmouse *psmouse = serio_get_drvdata(serio);
+       struct psmouse *psmouse = container_of(ps2dev, struct psmouse, ps2dev);
 
        if (psmouse->state == PSMOUSE_IGNORE)
-               goto out;
+               return PS2_IGNORE;
 
        if (unlikely((flags & SERIO_TIMEOUT) ||
                     ((flags & SERIO_PARITY) &&
@@ -350,27 +354,25 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
                                     "bad data from KBC -%s%s\n",
                                     flags & SERIO_TIMEOUT ? " timeout" : "",
                                     flags & SERIO_PARITY ? " bad parity" : "");
-               ps2_cmd_aborted(&psmouse->ps2dev);
-               goto out;
+               return PS2_ERROR;
        }
 
        if (flags & SERIO_OOB_DATA) {
                psmouse_handle_oob_data(psmouse, data);
-               goto out;
+               return PS2_IGNORE;
        }
 
-       if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
-               if  (ps2_handle_ack(&psmouse->ps2dev, data))
-                       goto out;
+       return PS2_PROCESS;
+}
 
-       if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
-               if  (ps2_handle_response(&psmouse->ps2dev, data))
-                       goto out;
+static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data)
+{
+       struct psmouse *psmouse = container_of(ps2dev, struct psmouse, ps2dev);
 
-       pm_wakeup_event(&serio->dev, 0);
+       pm_wakeup_event(&ps2dev->serio->dev, 0);
 
        if (psmouse->state <= PSMOUSE_RESYNCING)
-               goto out;
+               return;
 
        if (psmouse->state == PSMOUSE_ACTIVATED &&
            psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
@@ -379,7 +381,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
                psmouse->badbyte = psmouse->packet[0];
                __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
                psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
-               goto out;
+               return;
        }
 
        psmouse->packet[psmouse->pktcnt++] = data;
@@ -388,21 +390,21 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
        if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
                if (psmouse->pktcnt == 1) {
                        psmouse->last = jiffies;
-                       goto out;
+                       return;
                }
 
                if (psmouse->packet[1] == PSMOUSE_RET_ID ||
                    (psmouse->protocol->type == PSMOUSE_HGPK &&
                     psmouse->packet[1] == PSMOUSE_RET_BAT)) {
                        __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
-                       serio_reconnect(serio);
-                       goto out;
+                       serio_reconnect(ps2dev->serio);
+                       return;
                }
 
                /* Not a new device, try processing first byte normally */
                psmouse->pktcnt = 1;
                if (psmouse_handle_byte(psmouse))
-                       goto out;
+                       return;
 
                psmouse->packet[psmouse->pktcnt++] = data;
        }
@@ -417,14 +419,11 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
                psmouse->badbyte = psmouse->packet[0];
                __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
                psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
-               goto out;
+               return;
        }
 
        psmouse->last = jiffies;
        psmouse_handle_byte(psmouse);
-
- out:
-       return IRQ_HANDLED;
 }
 
 /*
@@ -1344,7 +1343,7 @@ static void psmouse_resync(struct work_struct *work)
                goto out;
 
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-               parent = serio_get_drvdata(serio->parent);
+               parent = psmouse_from_serio(serio->parent);
                psmouse_deactivate(parent);
        }
 
@@ -1428,13 +1427,13 @@ static void psmouse_resync(struct work_struct *work)
  */
 static void psmouse_cleanup(struct serio *serio)
 {
-       struct psmouse *psmouse = serio_get_drvdata(serio);
+       struct psmouse *psmouse = psmouse_from_serio(serio);
        struct psmouse *parent = NULL;
 
        mutex_lock(&psmouse_mutex);
 
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-               parent = serio_get_drvdata(serio->parent);
+               parent = psmouse_from_serio(serio->parent);
                psmouse_deactivate(parent);
        }
 
@@ -1476,7 +1475,7 @@ static void psmouse_cleanup(struct serio *serio)
  */
 static void psmouse_disconnect(struct serio *serio)
 {
-       struct psmouse *psmouse = serio_get_drvdata(serio);
+       struct psmouse *psmouse = psmouse_from_serio(serio);
        struct psmouse *parent = NULL;
 
        mutex_lock(&psmouse_mutex);
@@ -1489,7 +1488,7 @@ static void psmouse_disconnect(struct serio *serio)
        mutex_lock(&psmouse_mutex);
 
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-               parent = serio_get_drvdata(serio->parent);
+               parent = psmouse_from_serio(serio->parent);
                psmouse_deactivate(parent);
        }
 
@@ -1588,7 +1587,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
         * connected to this port can be successfully identified
         */
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-               parent = serio_get_drvdata(serio->parent);
+               parent = psmouse_from_serio(serio->parent);
                psmouse_deactivate(parent);
        }
 
@@ -1597,15 +1596,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
        if (!psmouse || !input_dev)
                goto err_free;
 
-       ps2_init(&psmouse->ps2dev, serio);
+       ps2_init(&psmouse->ps2dev, serio,
+                psmouse_pre_receive_byte, psmouse_receive_byte);
        INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
        psmouse->dev = input_dev;
        snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
 
        psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 
-       serio_set_drvdata(serio, psmouse);
-
        error = serio_open(serio, drv);
        if (error)
                goto err_clear_drvdata;
@@ -1676,7 +1674,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 
 static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect)
 {
-       struct psmouse *psmouse = serio_get_drvdata(serio);
+       struct psmouse *psmouse = psmouse_from_serio(serio);
        struct psmouse *parent = NULL;
        int (*reconnect_handler)(struct psmouse *);
        enum psmouse_type type;
@@ -1695,7 +1693,7 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect)
        }
 
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-               parent = serio_get_drvdata(serio->parent);
+               parent = psmouse_from_serio(serio->parent);
                psmouse_deactivate(parent);
        }
 
@@ -1781,7 +1779,7 @@ static struct serio_driver psmouse_drv = {
        },
        .description    = DRIVER_DESC,
        .id_table       = psmouse_serio_ids,
-       .interrupt      = psmouse_interrupt,
+       .interrupt      = ps2_interrupt,
        .connect        = psmouse_connect,
        .reconnect      = psmouse_reconnect,
        .fast_reconnect = psmouse_fast_reconnect,
@@ -1794,7 +1792,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de
 {
        struct serio *serio = to_serio_port(dev);
        struct psmouse_attribute *attr = to_psmouse_attr(devattr);
-       struct psmouse *psmouse = serio_get_drvdata(serio);
+       struct psmouse *psmouse = psmouse_from_serio(serio);
 
        if (psmouse->protocol->smbus_companion &&
                        devattr != &psmouse_attr_protocol.dattr)
@@ -1815,7 +1813,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
        if (retval)
                goto out;
 
-       psmouse = serio_get_drvdata(serio);
+       psmouse = psmouse_from_serio(serio);
 
        if (psmouse->protocol->smbus_companion &&
                        devattr != &psmouse_attr_protocol.dattr) {
@@ -1830,7 +1828,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
                }
 
                if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-                       parent = serio_get_drvdata(serio->parent);
+                       parent = psmouse_from_serio(serio->parent);
                        psmouse_deactivate(parent);
                }
 
@@ -1925,7 +1923,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
        }
 
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
-               parent = serio_get_drvdata(serio->parent);
+               parent = psmouse_from_serio(serio->parent);
                if (parent->pt_deactivate)
                        parent->pt_deactivate(parent);
        }
index 64c3a5d..4d8acfe 100644 (file)
@@ -130,6 +130,8 @@ struct psmouse {
        void (*pt_deactivate)(struct psmouse *psmouse);
 };
 
+struct psmouse *psmouse_from_serio(struct serio *serio);
+
 void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
                unsigned long delay);
 int psmouse_reset(struct psmouse *psmouse);
index fa021af..ada299e 100644 (file)
@@ -628,7 +628,7 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
  ****************************************************************************/
 static int synaptics_pt_write(struct serio *serio, u8 c)
 {
-       struct psmouse *parent = serio_get_drvdata(serio->parent);
+       struct psmouse *parent = psmouse_from_serio(serio->parent);
        u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
        int error;
 
@@ -645,7 +645,7 @@ static int synaptics_pt_write(struct serio *serio, u8 c)
 
 static int synaptics_pt_start(struct serio *serio)
 {
-       struct psmouse *parent = serio_get_drvdata(serio->parent);
+       struct psmouse *parent = psmouse_from_serio(serio->parent);
        struct synaptics_data *priv = parent->private;
 
        serio_pause_rx(parent->ps2dev.serio);
@@ -657,7 +657,7 @@ static int synaptics_pt_start(struct serio *serio)
 
 static void synaptics_pt_stop(struct serio *serio)
 {
-       struct psmouse *parent = serio_get_drvdata(serio->parent);
+       struct psmouse *parent = psmouse_from_serio(serio->parent);
        struct synaptics_data *priv = parent->private;
 
        serio_pause_rx(parent->ps2dev.serio);
@@ -672,7 +672,7 @@ static int synaptics_is_pt_packet(u8 *buf)
 
 static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet)
 {
-       struct psmouse *child = serio_get_drvdata(ptport);
+       struct psmouse *child = psmouse_from_serio(ptport);
 
        if (child && child->state == PSMOUSE_ACTIVATED) {
                serio_interrupt(ptport, packet[1], 0);
@@ -688,7 +688,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet)
 static void synaptics_pt_activate(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
-       struct psmouse *child = serio_get_drvdata(priv->pt_port);
+       struct psmouse *child = psmouse_from_serio(priv->pt_port);
 
        /* adjust the touchpad to child's choice of protocol */
        if (child) {
index 068692a..af5cc64 100644 (file)
@@ -650,7 +650,7 @@ static struct i2c_driver synaptics_i2c_driver = {
                .pm     = pm_sleep_ptr(&synaptics_i2c_pm),
        },
 
-       .probe_new      = synaptics_i2c_probe,
+       .probe          = synaptics_i2c_probe,
        .remove         = synaptics_i2c_remove,
 
        .id_table       = synaptics_i2c_id_table,
index 4a86b3e..5f6643b 100644 (file)
@@ -216,7 +216,7 @@ static umode_t trackpoint_is_attr_visible(struct kobject *kobj,
 {
        struct device *dev = kobj_to_dev(kobj);
        struct serio *serio = to_serio_port(dev);
-       struct psmouse *psmouse = serio_get_drvdata(serio);
+       struct psmouse *psmouse = psmouse_from_serio(serio);
 
        return trackpoint_is_attr_available(psmouse, attr) ? attr->mode : 0;
 }
index d69569c..091d4e2 100644 (file)
@@ -377,7 +377,7 @@ static struct i2c_driver rmi_i2c_driver = {
                .of_match_table = of_match_ptr(rmi_i2c_of_match),
        },
        .id_table       = rmi_id,
-       .probe_new      = rmi_i2c_probe,
+       .probe          = rmi_i2c_probe,
 };
 
 module_i2c_driver(rmi_i2c_driver);
index 4bf0e1d..7059a27 100644 (file)
@@ -418,7 +418,7 @@ static struct i2c_driver rmi_smb_driver = {
                .pm     = pm_ptr(&rmi_smb_pm),
        },
        .id_table       = rmi_id,
-       .probe_new      = rmi_smb_probe,
+       .probe          = rmi_smb_probe,
        .remove         = rmi_smb_remove,
 };
 
index f39b7b3..17edc15 100644 (file)
@@ -148,6 +148,7 @@ config HIL_MLC
 config SERIO_PCIPS2
        tristate "PCI PS/2 keyboard and PS/2 mouse controller"
        depends on PCI
+       depends on HAS_IOPORT
        help
          Say Y here if you have a Mobility Docking station with PS/2
          keyboard and mice ports.
index 3e19344..6d78a1f 100644 (file)
 
 #define DRIVER_DESC    "PS/2 driver library"
 
-MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
-MODULE_DESCRIPTION("PS/2 driver library");
-MODULE_LICENSE("GPL");
+#define PS2_CMD_SETSCALE11     0x00e6
+#define PS2_CMD_SETRES         0x10e8
+#define PS2_CMD_EX_SETLEDS     0x20eb
+#define PS2_CMD_SETLEDS                0x10ed
+#define PS2_CMD_GETID          0x02f2
+#define PS2_CMD_SETREP         0x10f3 /* Set repeat rate/set report rate */
+#define PS2_CMD_RESET_BAT      0x02ff
+
+#define PS2_RET_BAT            0xaa
+#define PS2_RET_ID             0x00
+#define PS2_RET_ACK            0xfa
+#define PS2_RET_NAK            0xfe
+#define PS2_RET_ERR            0xfc
+
+#define PS2_FLAG_ACK           BIT(0)  /* Waiting for ACK/NAK */
+#define PS2_FLAG_CMD           BIT(1)  /* Waiting for a command to finish */
+#define PS2_FLAG_CMD1          BIT(2)  /* Waiting for the first byte of command response */
+#define PS2_FLAG_WAITID                BIT(3)  /* Command executing is GET ID */
+#define PS2_FLAG_NAK           BIT(4)  /* Last transmission was NAKed */
+#define PS2_FLAG_PASS_NOACK    BIT(5)  /* Pass non-ACK byte to receive handler */
 
 static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
                           unsigned int timeout, unsigned int max_attempts)
@@ -76,14 +93,17 @@ static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
        return error;
 }
 
-/*
- * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
- * It doesn't handle retransmission, the caller is expected to handle
+/**
+ * ps2_sendbyte - sends a byte to the device and wait for acknowledgement
+ * @ps2dev: a PS/2 device to send the data to
+ * @byte: data to be sent to the device
+ * @timeout: timeout for sending the data and receiving an acknowledge
+ *
+ * The function doesn't handle retransmission, the caller is expected to handle
  * it when needed.
  *
  * ps2_sendbyte() can only be called from a process context.
  */
-
 int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
 {
        int retval;
@@ -99,6 +119,13 @@ int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
 }
 EXPORT_SYMBOL(ps2_sendbyte);
 
+/**
+ * ps2_begin_command - mark beginning of execution of a complex command
+ * @ps2dev: a PS/2 device executing the command
+ *
+ * Serializes a complex/compound command. Once command is finished
+ * ps2_end_command() should be called.
+ */
 void ps2_begin_command(struct ps2dev *ps2dev)
 {
        struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
@@ -107,6 +134,10 @@ void ps2_begin_command(struct ps2dev *ps2dev)
 }
 EXPORT_SYMBOL(ps2_begin_command);
 
+/**
+ * ps2_end_command - mark end of execution of a complex command
+ * @ps2dev: a PS/2 device executing the command
+ */
 void ps2_end_command(struct ps2dev *ps2dev)
 {
        struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
@@ -115,11 +146,13 @@ void ps2_end_command(struct ps2dev *ps2dev)
 }
 EXPORT_SYMBOL(ps2_end_command);
 
-/*
- * ps2_drain() waits for device to transmit requested number of bytes
- * and discards them.
+/**
+ * ps2_drain - waits for device to transmit requested number of bytes
+ * and discards them
+ * @ps2dev: the PS/2 device that should be drained
+ * @maxbytes: maximum number of bytes to be drained
+ * @timeout: time to drain the device
  */
-
 void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
 {
        if (maxbytes > sizeof(ps2dev->cmdbuf)) {
@@ -142,11 +175,11 @@ void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
 }
 EXPORT_SYMBOL(ps2_drain);
 
-/*
- * ps2_is_keyboard_id() checks received ID byte against the list of
- * known keyboard IDs.
+/**
+ * ps2_is_keyboard_id - checks received ID byte against the list of
+ *   known keyboard IDs
+ * @id_byte: data byte that should be checked
  */
-
 bool ps2_is_keyboard_id(u8 id_byte)
 {
        static const u8 keyboard_ids[] = {
@@ -167,7 +200,6 @@ EXPORT_SYMBOL(ps2_is_keyboard_id);
  * response and tries to reduce remaining timeout to speed up command
  * completion.
  */
-
 static int ps2_adjust_timeout(struct ps2dev *ps2dev,
                              unsigned int command, unsigned int timeout)
 {
@@ -217,13 +249,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev,
        return timeout;
 }
 
-/*
- * ps2_command() sends a command and its parameters to the mouse,
- * then waits for the response and puts it in the param array.
+/**
+ * __ps2_command - send a command to PS/2 device
+ * @ps2dev: the PS/2 device that should execute the command
+ * @param: a buffer containing parameters to be sent along with the command,
+ *   or place where the results of the command execution will be deposited,
+ *   or both
+ * @command: command word that encodes the command itself, as well as number of
+ *   additional parameter bytes that should be sent to the device and expected
+ *   length of the command response
  *
- * ps2_command() can only be called from a process context
+ * Not serialized. Callers should use ps2_begin_command() and ps2_end_command()
+ * to ensure proper serialization for complex commands.
  */
-
 int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 {
        unsigned int timeout;
@@ -247,17 +285,38 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 
        serio_pause_rx(ps2dev->serio);
 
-       ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
        ps2dev->cmdcnt = receive;
-       if (receive && param)
-               for (i = 0; i < receive; i++)
-                       ps2dev->cmdbuf[(receive - 1) - i] = param[i];
 
-       /* Signal that we are sending the command byte */
-       ps2dev->flags |= PS2_FLAG_ACK_CMD;
+       switch (command) {
+       case PS2_CMD_GETID:
+               /*
+                * Some mice do not ACK the "get ID" command, prepare to
+                * handle this.
+                */
+               ps2dev->flags = PS2_FLAG_WAITID;
+               break;
+
+       case PS2_CMD_SETLEDS:
+       case PS2_CMD_EX_SETLEDS:
+       case PS2_CMD_SETREP:
+               ps2dev->flags = PS2_FLAG_PASS_NOACK;
+               break;
+
+       default:
+               ps2dev->flags = 0;
+               break;
+       }
+
+       if (receive) {
+               /* Indicate that we expect response to the command. */
+               ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
+               if (param)
+                       for (i = 0; i < receive; i++)
+                               ps2dev->cmdbuf[(receive - 1) - i] = param[i];
+       }
 
        /*
-        * Some devices (Synaptics) peform the reset before
+        * Some devices (Synaptics) perform the reset before
         * ACKing the reset command, and so it can take a long
         * time before the ACK arrives.
         */
@@ -267,9 +326,7 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
        if (rc)
                goto out_reset_flags;
 
-       /* Now we are sending command parameters, if any */
-       ps2dev->flags &= ~PS2_FLAG_ACK_CMD;
-
+       /* Send command parameters, if any. */
        for (i = 0; i < send; i++) {
                rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2);
                if (rc)
@@ -327,6 +384,20 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 }
 EXPORT_SYMBOL(__ps2_command);
 
+/**
+ * ps2_command - send a command to PS/2 device
+ * @ps2dev: the PS/2 device that should execute the command
+ * @param: a buffer containing parameters to be sent along with the command,
+ *   or place where the results of the command execution will be deposited,
+ *   or both
+ * @command: command word that encodes the command itself, as well as number of
+ *   additional parameter bytes that should be sent to the device and expected
+ *   length of the command response
+ *
+ * Note: ps2_command() serializes the command execution so that only one
+ * command can be executed at a time for either individual port or the entire
+ * 8042 controller.
+ */
 int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 {
        int rc;
@@ -339,14 +410,16 @@ int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 }
 EXPORT_SYMBOL(ps2_command);
 
-/*
- * ps2_sliced_command() sends an extended PS/2 command to the mouse
- * using sliced syntax, understood by advanced devices, such as Logitech
- * or Synaptics touchpads. The command is encoded as:
+/**
+ * ps2_sliced_command - sends an extended PS/2 command to a mouse
+ * @ps2dev: the PS/2 device that should execute the command
+ * @command: command byte
+ *
+ * The command is sent using "sliced" syntax understood by advanced devices,
+ * such as Logitech or Synaptics touchpads. The command is encoded as:
  * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
  * is the command.
  */
-
 int ps2_sliced_command(struct ps2dev *ps2dev, u8 command)
 {
        int i;
@@ -372,25 +445,60 @@ out:
 }
 EXPORT_SYMBOL(ps2_sliced_command);
 
-/*
- * ps2_init() initializes ps2dev structure
+/**
+ * ps2_init - initializes ps2dev structure
+ * @ps2dev: structure to be initialized
+ * @serio: serio port associated with the PS/2 device
+ * @pre_receive_handler: validation handler to check basic communication state
+ * @receive_handler: main protocol handler
+ *
+ * Prepares ps2dev structure for use in drivers for PS/2 devices.
  */
-
-void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio,
+             ps2_pre_receive_handler_t pre_receive_handler,
+             ps2_receive_handler_t receive_handler)
 {
+       ps2dev->pre_receive_handler = pre_receive_handler;
+       ps2dev->receive_handler = receive_handler;
+
        mutex_init(&ps2dev->cmd_mutex);
        lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth);
        init_waitqueue_head(&ps2dev->wait);
        ps2dev->serio = serio;
+       serio_set_drvdata(serio, ps2dev);
 }
 EXPORT_SYMBOL(ps2_init);
 
 /*
- * ps2_handle_ack() is supposed to be used in interrupt handler
- * to properly process ACK/NAK of a command from a PS/2 device.
+ * ps2_handle_response() stores device's response to a command and notifies
+ * the process waiting for completion of the command. Note that there is a
+ * distinction between waiting for the first byte of the response, and
+ * waiting for subsequent bytes. It is done so that callers could shorten
+ * timeouts once first byte of response is received.
  */
+static void ps2_handle_response(struct ps2dev *ps2dev, u8 data)
+{
+       if (ps2dev->cmdcnt)
+               ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
+
+       if (ps2dev->flags & PS2_FLAG_CMD1) {
+               ps2dev->flags &= ~PS2_FLAG_CMD1;
+               if (ps2dev->cmdcnt)
+                       wake_up(&ps2dev->wait);
+       }
+
+       if (!ps2dev->cmdcnt) {
+               ps2dev->flags &= ~PS2_FLAG_CMD;
+               wake_up(&ps2dev->wait);
+       }
+}
 
-bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
+/*
+ * ps2_handle_ack() processes ACK/NAK of a command from a PS/2 device,
+ * possibly applying workarounds for mice not acknowledging the "get ID"
+ * command.
+ */
+static void ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 {
        switch (data) {
        case PS2_RET_ACK:
@@ -427,68 +535,89 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
                 * Do not signal errors if we get unexpected reply while
                 * waiting for an ACK to the initial (first) command byte:
                 * the device might not be quiesced yet and continue
-                * delivering data.
+                * delivering data. For certain commands (such as set leds and
+                * set repeat rate) that can be used during normal device
+                * operation, we even pass this data byte to the normal receive
+                * handler.
                 * Note that we reset PS2_FLAG_WAITID flag, so the workaround
                 * for mice not acknowledging the Get ID command only triggers
                 * on the 1st byte; if device spews data we really want to see
                 * a real ACK from it.
                 */
                dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data);
-               ps2dev->flags &= ~PS2_FLAG_WAITID;
-               return ps2dev->flags & PS2_FLAG_ACK_CMD;
+               if (ps2dev->flags & PS2_FLAG_PASS_NOACK)
+                       ps2dev->receive_handler(ps2dev, data);
+               ps2dev->flags &= ~(PS2_FLAG_WAITID | PS2_FLAG_PASS_NOACK);
+               return;
        }
 
-       if (!ps2dev->nak) {
+       if (!ps2dev->nak)
                ps2dev->flags &= ~PS2_FLAG_NAK;
-               if (ps2dev->cmdcnt)
-                       ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
-       }
 
        ps2dev->flags &= ~PS2_FLAG_ACK;
-       wake_up(&ps2dev->wait);
 
-       if (data != PS2_RET_ACK)
+       if (!ps2dev->nak && data != PS2_RET_ACK)
                ps2_handle_response(ps2dev, data);
-
-       return true;
+       else
+               wake_up(&ps2dev->wait);
 }
-EXPORT_SYMBOL(ps2_handle_ack);
 
 /*
- * ps2_handle_response() is supposed to be used in interrupt handler
- * to properly store device's response to a command and notify process
- * waiting for completion of the command.
+ * Clears state of PS/2 device after communication error by resetting majority
+ * of flags and waking up waiters, if any.
  */
-
-bool ps2_handle_response(struct ps2dev *ps2dev, u8 data)
+static void ps2_cleanup(struct ps2dev *ps2dev)
 {
-       if (ps2dev->cmdcnt)
-               ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
+       unsigned long old_flags = ps2dev->flags;
 
-       if (ps2dev->flags & PS2_FLAG_CMD1) {
-               ps2dev->flags &= ~PS2_FLAG_CMD1;
-               if (ps2dev->cmdcnt)
-                       wake_up(&ps2dev->wait);
-       }
+       /* reset all flags except last nak */
+       ps2dev->flags &= PS2_FLAG_NAK;
 
-       if (!ps2dev->cmdcnt) {
-               ps2dev->flags &= ~PS2_FLAG_CMD;
-               wake_up(&ps2dev->wait);
-       }
+       if (old_flags & PS2_FLAG_ACK)
+               ps2dev->nak = 1;
 
-       return true;
+       if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
+               wake_up(&ps2dev->wait);
 }
-EXPORT_SYMBOL(ps2_handle_response);
 
-void ps2_cmd_aborted(struct ps2dev *ps2dev)
-{
-       if (ps2dev->flags & PS2_FLAG_ACK)
-               ps2dev->nak = 1;
+/**
+ * ps2_interrupt - common interrupt handler for PS/2 devices
+ * @serio: serio port for the device
+ * @data: a data byte received from the device
+ * @flags: flags such as %SERIO_PARITY or %SERIO_TIMEOUT indicating state of
+ *   the data transfer
+ *
+ * ps2_interrupt() invokes pre-receive handler, optionally handles command
+ * acknowledgement and response from the device, and finally passes the data
+ * to the main protocol handler for future processing.
+ */
+irqreturn_t ps2_interrupt(struct serio *serio, u8 data, unsigned int flags) {
+       struct ps2dev *ps2dev = serio_get_drvdata(serio);
+       enum ps2_disposition rc;
+
+       rc = ps2dev->pre_receive_handler(ps2dev, data, flags);
+       switch (rc) {
+       case PS2_ERROR:
+               ps2_cleanup(ps2dev);
+               break;
 
-       if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
-               wake_up(&ps2dev->wait);
+       case PS2_IGNORE:
+               break;
 
-       /* reset all flags except last nack */
-       ps2dev->flags &= PS2_FLAG_NAK;
+       case PS2_PROCESS:
+               if (ps2dev->flags & PS2_FLAG_ACK)
+                       ps2_handle_ack(ps2dev, data);
+               else if (ps2dev->flags & PS2_FLAG_CMD)
+                       ps2_handle_response(ps2dev, data);
+               else
+                       ps2dev->receive_handler(ps2dev, data);
+               break;
+       }
+
+       return IRQ_HANDLED;
 }
-EXPORT_SYMBOL(ps2_cmd_aborted);
+EXPORT_SYMBOL(ps2_interrupt);
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("PS/2 driver library");
+MODULE_LICENSE("GPL");
index e5a6c1a..2fa5b72 100644 (file)
@@ -43,8 +43,8 @@ static void input_test_exit(struct kunit *test)
 {
        struct input_dev *input_dev = test->priv;
 
-       input_unregister_device(input_dev);
-       input_free_device(input_dev);
+       if (input_dev)
+               input_unregister_device(input_dev);
 }
 
 static void input_test_poll(struct input_dev *input) { }
@@ -87,7 +87,7 @@ static void input_test_timestamp(struct kunit *test)
 static void input_test_match_device_id(struct kunit *test)
 {
        struct input_dev *input_dev = test->priv;
-       struct input_device_id id;
+       struct input_device_id id = { 0 };
 
        /*
         * Must match when the input device bus, vendor, product, version
@@ -130,10 +130,42 @@ static void input_test_match_device_id(struct kunit *test)
        KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id));
 }
 
+static void input_test_grab(struct kunit *test)
+{
+       struct input_dev *input_dev = test->priv;
+       struct input_handle test_handle;
+       struct input_handler handler;
+       struct input_handle handle;
+       struct input_device_id id;
+       int res;
+
+       handler.name = "handler";
+       handler.id_table = &id;
+
+       handle.dev = input_get_device(input_dev);
+       handle.name = dev_name(&input_dev->dev);
+       handle.handler = &handler;
+       res = input_grab_device(&handle);
+       KUNIT_ASSERT_TRUE(test, res == 0);
+
+       test_handle.dev = input_get_device(input_dev);
+       test_handle.name = dev_name(&input_dev->dev);
+       test_handle.handler = &handler;
+       res = input_grab_device(&test_handle);
+       KUNIT_ASSERT_EQ(test, res, -EBUSY);
+
+       input_release_device(&handle);
+       input_put_device(input_dev);
+       res = input_grab_device(&test_handle);
+       KUNIT_ASSERT_TRUE(test, res == 0);
+       input_put_device(input_dev);
+}
+
 static struct kunit_case input_tests[] = {
        KUNIT_CASE(input_test_polling),
        KUNIT_CASE(input_test_timestamp),
        KUNIT_CASE(input_test_match_device_id),
+       KUNIT_CASE(input_test_grab),
        { /* sentinel */ }
 };
 
index 143ff43..e3e2324 100644 (file)
@@ -655,10 +655,10 @@ config TOUCHSCREEN_MTOUCH
          module will be called mtouch.
 
 config TOUCHSCREEN_NOVATEK_NVT_TS
-       tristate "Novatek NVT-ts touchscreen support"
+       tristate "Novatek NT11205 touchscreen support"
        depends on I2C
        help
-         Say Y here if you have a Novatek NVT-ts touchscreen.
+         Say Y here if you have a Novatek NT11205 touchscreen.
          If unsure, say N.
 
          To compile this driver as a module, choose M here: the
@@ -700,6 +700,7 @@ config TOUCHSCREEN_INEXIO
 
 config TOUCHSCREEN_MK712
        tristate "ICS MicroClock MK712 touchscreen"
+       depends on ISA
        help
          Say Y here if you have the ICS MicroClock MK712 touchscreen
          controller chip in your system.
@@ -1364,6 +1365,16 @@ config TOUCHSCREEN_IQS5XX
          To compile this driver as a module, choose M here: the
          module will be called iqs5xx.
 
+config TOUCHSCREEN_IQS7211
+       tristate "Azoteq IQS7210A/7211A/E trackpad/touchscreen controller"
+       depends on I2C
+       help
+         Say Y to enable support for the Azoteq IQS7210A/7211A/E
+         family of trackpad/touchscreen controllers.
+
+         To compile this driver as a module, choose M here: the
+         module will be called iqs7211.
+
 config TOUCHSCREEN_ZINITIX
        tristate "Zinitix touchscreen support"
        depends on I2C
index 159cd51..62bd24f 100644 (file)
@@ -115,5 +115,6 @@ 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_IQS7211)      += iqs7211.o
 obj-$(CONFIG_TOUCHSCREEN_ZINITIX)      += zinitix.o
 obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX83112B)       += himax_hx83112b.o
index dd8f317..feaa6f8 100644 (file)
@@ -62,7 +62,7 @@ static struct i2c_driver ad7879_i2c_driver = {
                .pm     = &ad7879_pm_ops,
                .of_match_table = of_match_ptr(ad7879_i2c_dt_ids),
        },
-       .probe_new      = ad7879_i2c_probe,
+       .probe          = ad7879_i2c_probe,
        .id_table       = ad7879_id,
 };
 
index 3a5b65c..64dfb74 100644 (file)
@@ -182,7 +182,7 @@ static struct i2c_driver ar1021_i2c_driver = {
                .of_match_table = ar1021_i2c_of_match,
        },
 
-       .probe_new      = ar1021_i2c_probe,
+       .probe          = ar1021_i2c_probe,
        .id_table       = ar1021_i2c_id,
 };
 module_i2c_driver(ar1021_i2c_driver);
index 996bf43..20094b9 100644 (file)
@@ -55,6 +55,7 @@
 #define MXT_TOUCH_KEYARRAY_T15         15
 #define MXT_TOUCH_PROXIMITY_T23                23
 #define MXT_TOUCH_PROXKEY_T52          52
+#define MXT_TOUCH_PTC_KEYS_T97         97
 #define MXT_PROCI_GRIPFACE_T20         20
 #define MXT_PROCG_NOISE_T22            22
 #define MXT_PROCI_ONETOUCH_T24         24
@@ -326,9 +327,13 @@ struct mxt_data {
        u16 T71_address;
        u8 T9_reportid_min;
        u8 T9_reportid_max;
+       u8 T15_reportid_min;
+       u8 T15_reportid_max;
        u16 T18_address;
        u8 T19_reportid;
        u16 T44_address;
+       u8 T97_reportid_min;
+       u8 T97_reportid_max;
        u8 T100_reportid_min;
        u8 T100_reportid_max;
 
@@ -344,6 +349,9 @@ struct mxt_data {
        u32 *t19_keymap;
        unsigned int t19_num_keys;
 
+       u32 *t15_keymap;
+       unsigned int t15_num_keys;
+
        enum mxt_suspend_mode suspend_mode;
 
        u32 wakeup_method;
@@ -375,6 +383,7 @@ static bool mxt_object_readable(unsigned int type)
        case MXT_TOUCH_KEYARRAY_T15:
        case MXT_TOUCH_PROXIMITY_T23:
        case MXT_TOUCH_PROXKEY_T52:
+       case MXT_TOUCH_PTC_KEYS_T97:
        case MXT_TOUCH_MULTITOUCHSCREEN_T100:
        case MXT_PROCI_GRIPFACE_T20:
        case MXT_PROCG_NOISE_T22:
@@ -891,6 +900,24 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
        data->update_input = true;
 }
 
+static void mxt_proc_t15_messages(struct mxt_data *data, u8 *message)
+{
+       struct input_dev *input_dev = data->input_dev;
+       unsigned long keystates = get_unaligned_le32(&message[2]);
+       int key;
+
+       for (key = 0; key < data->t15_num_keys; key++)
+               input_report_key(input_dev, data->t15_keymap[key],
+                                keystates & BIT(key));
+
+       data->update_input = true;
+}
+
+static void mxt_proc_t97_messages(struct mxt_data *data, u8 *message)
+{
+       mxt_proc_t15_messages(data, message);
+}
+
 static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
 {
        struct device *dev = &data->client->dev;
@@ -1017,6 +1044,12 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
        } else if (report_id >= data->T9_reportid_min &&
                   report_id <= data->T9_reportid_max) {
                mxt_proc_t9_message(data, message);
+       } else if (report_id >= data->T15_reportid_min &&
+                  report_id <= data->T15_reportid_max) {
+               mxt_proc_t15_messages(data, message);
+       } else if (report_id >= data->T97_reportid_min &&
+                  report_id <= data->T97_reportid_max) {
+               mxt_proc_t97_messages(data, message);
        } else if (report_id >= data->T100_reportid_min &&
                   report_id <= data->T100_reportid_max) {
                mxt_proc_t100_message(data, message);
@@ -1689,9 +1722,13 @@ static void mxt_free_object_table(struct mxt_data *data)
        data->T71_address = 0;
        data->T9_reportid_min = 0;
        data->T9_reportid_max = 0;
+       data->T15_reportid_min = 0;
+       data->T15_reportid_max = 0;
        data->T18_address = 0;
        data->T19_reportid = 0;
        data->T44_address = 0;
+       data->T97_reportid_min = 0;
+       data->T97_reportid_max = 0;
        data->T100_reportid_min = 0;
        data->T100_reportid_max = 0;
        data->max_reportid = 0;
@@ -1764,6 +1801,10 @@ static int mxt_parse_object_table(struct mxt_data *data,
                                                object->num_report_ids - 1;
                        data->num_touchids = object->num_report_ids;
                        break;
+               case MXT_TOUCH_KEYARRAY_T15:
+                       data->T15_reportid_min = min_id;
+                       data->T15_reportid_max = max_id;
+                       break;
                case MXT_SPT_COMMSCONFIG_T18:
                        data->T18_address = object->start_address;
                        break;
@@ -1773,6 +1814,10 @@ static int mxt_parse_object_table(struct mxt_data *data,
                case MXT_SPT_GPIOPWM_T19:
                        data->T19_reportid = min_id;
                        break;
+               case MXT_TOUCH_PTC_KEYS_T97:
+                       data->T97_reportid_min = min_id;
+                       data->T97_reportid_max = max_id;
+                       break;
                case MXT_TOUCH_MULTITOUCHSCREEN_T100:
                        data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
                        data->T100_reportid_min = min_id;
@@ -2050,6 +2095,7 @@ static int mxt_initialize_input_device(struct mxt_data *data)
        int error;
        unsigned int num_mt_slots;
        unsigned int mt_flags = 0;
+       int i;
 
        switch (data->multitouch) {
        case MXT_TOUCH_MULTI_T9:
@@ -2095,6 +2141,10 @@ static int mxt_initialize_input_device(struct mxt_data *data)
        input_dev->open = mxt_input_open;
        input_dev->close = mxt_input_close;
 
+       input_dev->keycode = data->t15_keymap;
+       input_dev->keycodemax = data->t15_num_keys;
+       input_dev->keycodesize = sizeof(data->t15_keymap[0]);
+
        input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
 
        /* For single touch */
@@ -2162,6 +2212,13 @@ static int mxt_initialize_input_device(struct mxt_data *data)
                                     0, 255, 0, 0);
        }
 
+       /* For T15 and T97 Key Array */
+       if (data->T15_reportid_min || data->T97_reportid_min) {
+               for (i = 0; i < data->t15_num_keys; i++)
+                       input_set_capability(input_dev,
+                                            EV_KEY, data->t15_keymap[i]);
+       }
+
        input_set_drvdata(input_dev, data);
 
        error = input_register_device(input_dev);
@@ -3080,8 +3137,10 @@ static void mxt_input_close(struct input_dev *dev)
 static int mxt_parse_device_properties(struct mxt_data *data)
 {
        static const char keymap_property[] = "linux,gpio-keymap";
+       static const char buttons_property[] = "linux,keycodes";
        struct device *dev = &data->client->dev;
        u32 *keymap;
+       u32 *buttonmap;
        int n_keys;
        int error;
 
@@ -3111,6 +3170,32 @@ static int mxt_parse_device_properties(struct mxt_data *data)
                data->t19_num_keys = n_keys;
        }
 
+       if (device_property_present(dev, buttons_property)) {
+               n_keys = device_property_count_u32(dev, buttons_property);
+               if (n_keys <= 0) {
+                       error = n_keys < 0 ? n_keys : -EINVAL;
+                       dev_err(dev, "invalid/malformed '%s' property: %d\n",
+                               buttons_property, error);
+                       return error;
+               }
+
+               buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap),
+                                              GFP_KERNEL);
+               if (!buttonmap)
+                       return -ENOMEM;
+
+               error = device_property_read_u32_array(dev, buttons_property,
+                                                      buttonmap, n_keys);
+               if (error) {
+                       dev_err(dev, "failed to parse '%s' property: %d\n",
+                               buttons_property, error);
+                       return error;
+               }
+
+               data->t15_keymap = buttonmap;
+               data->t15_num_keys = n_keys;
+       }
+
        return 0;
 }
 
@@ -3377,7 +3462,7 @@ static struct i2c_driver mxt_driver = {
                .acpi_match_table = ACPI_PTR(mxt_acpi_id),
                .pm     = pm_sleep_ptr(&mxt_pm_ops),
        },
-       .probe_new      = mxt_probe,
+       .probe          = mxt_probe,
        .remove         = mxt_remove,
        .id_table       = mxt_id,
 };
index 5359efc..90c682e 100644 (file)
@@ -636,7 +636,7 @@ static struct i2c_driver auo_pixcir_driver = {
                .pm     = pm_sleep_ptr(&auo_pixcir_pm_ops),
                .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable),
        },
-       .probe_new      = auo_pixcir_probe,
+       .probe          = auo_pixcir_probe,
        .id_table       = auo_pixcir_idtable,
 };
 
index c994ab6..652439a 100644 (file)
@@ -410,31 +410,32 @@ static int bu21013_probe(struct i2c_client *client)
        struct input_dev *in_dev;
        struct input_absinfo *info;
        u32 max_x = 0, max_y = 0;
+       struct device *dev = &client->dev;
        int error;
 
        if (!i2c_check_functionality(client->adapter,
                                     I2C_FUNC_SMBUS_BYTE_DATA)) {
-               dev_err(&client->dev, "i2c smbus byte data not supported\n");
+               dev_err(dev, "i2c smbus byte data not supported\n");
                return -EIO;
        }
 
        if (!client->irq) {
-               dev_err(&client->dev, "No IRQ set up\n");
+               dev_err(dev, "No IRQ set up\n");
                return -EINVAL;
        }
 
-       ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+       ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
        if (!ts)
                return -ENOMEM;
 
        ts->client = client;
 
-       ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x");
-       ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y");
+       ts->x_flip = device_property_read_bool(dev, "rohm,flip-x");
+       ts->y_flip = device_property_read_bool(dev, "rohm,flip-y");
 
-       in_dev = devm_input_allocate_device(&client->dev);
+       in_dev = devm_input_allocate_device(dev);
        if (!in_dev) {
-               dev_err(&client->dev, "device memory alloc failed\n");
+               dev_err(dev, "device memory alloc failed\n");
                return -ENOMEM;
        }
        ts->in_dev = in_dev;
@@ -444,8 +445,8 @@ static int bu21013_probe(struct i2c_client *client)
        in_dev->name = DRIVER_TP;
        in_dev->id.bustype = BUS_I2C;
 
-       device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x);
-       device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y);
+       device_property_read_u32(dev, "rohm,touch-max-x", &max_x);
+       device_property_read_u32(dev, "rohm,touch-max-y", &max_y);
 
        input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0);
        input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
@@ -454,14 +455,14 @@ static int bu21013_probe(struct i2c_client *client)
 
        /* Adjust for the legacy "flip" properties, if present */
        if (!ts->props.invert_x &&
-           device_property_read_bool(&client->dev, "rohm,flip-x")) {
+           device_property_read_bool(dev, "rohm,flip-x")) {
                info = &in_dev->absinfo[ABS_MT_POSITION_X];
                info->maximum -= info->minimum;
                info->minimum = 0;
        }
 
        if (!ts->props.invert_y &&
-           device_property_read_bool(&client->dev, "rohm,flip-y")) {
+           device_property_read_bool(dev, "rohm,flip-y")) {
                info = &in_dev->absinfo[ABS_MT_POSITION_Y];
                info->maximum -= info->minimum;
                info->minimum = 0;
@@ -471,55 +472,46 @@ static int bu21013_probe(struct i2c_client *client)
                                    INPUT_MT_DIRECT | INPUT_MT_TRACK |
                                        INPUT_MT_DROP_UNUSED);
        if (error) {
-               dev_err(&client->dev, "failed to initialize MT slots");
+               dev_err(dev, "failed to initialize MT slots");
                return error;
        }
 
-       ts->regulator = devm_regulator_get(&client->dev, "avdd");
+       ts->regulator = devm_regulator_get(dev, "avdd");
        if (IS_ERR(ts->regulator)) {
-               dev_err(&client->dev, "regulator_get failed\n");
+               dev_err(dev, "regulator_get failed\n");
                return PTR_ERR(ts->regulator);
        }
 
        error = regulator_enable(ts->regulator);
        if (error) {
-               dev_err(&client->dev, "regulator enable failed\n");
+               dev_err(dev, "regulator enable failed\n");
                return error;
        }
 
-       error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts);
+       error = devm_add_action_or_reset(dev, bu21013_power_off, ts);
        if (error) {
-               dev_err(&client->dev, "failed to install power off handler\n");
+               dev_err(dev, "failed to install power off handler\n");
                return error;
        }
 
        /* Named "CS" on the chip, DT binding is "reset" */
-       ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
-       error = PTR_ERR_OR_ZERO(ts->cs_gpiod);
-       if (error) {
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev, "failed to get CS GPIO\n");
-               return error;
-       }
+       ts->cs_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(ts->cs_gpiod))
+               return dev_err_probe(dev, PTR_ERR(ts->cs_gpiod), "failed to get CS GPIO\n");
+
        gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS");
 
-       error = devm_add_action_or_reset(&client->dev,
-                                        bu21013_disable_chip, ts);
+       error = devm_add_action_or_reset(dev, bu21013_disable_chip, ts);
        if (error) {
-               dev_err(&client->dev,
-                       "failed to install chip disable handler\n");
+               dev_err(dev, "failed to install chip disable handler\n");
                return error;
        }
 
        /* Named "INT" on the chip, DT binding is "touch" */
-       ts->int_gpiod = devm_gpiod_get_optional(&client->dev,
-                                               "touch", GPIOD_IN);
+       ts->int_gpiod = devm_gpiod_get_optional(dev, "touch", GPIOD_IN);
        error = PTR_ERR_OR_ZERO(ts->int_gpiod);
-       if (error) {
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev, "failed to get INT GPIO\n");
-               return error;
-       }
+       if (error)
+               return dev_err_probe(dev, error, "failed to get INT GPIO\n");
 
        if (ts->int_gpiod)
                gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT");
@@ -527,22 +519,20 @@ static int bu21013_probe(struct i2c_client *client)
        /* configure the touch panel controller */
        error = bu21013_init_chip(ts);
        if (error) {
-               dev_err(&client->dev, "error in bu21013 config\n");
+               dev_err(dev, "error in bu21013 config\n");
                return error;
        }
 
-       error = devm_request_threaded_irq(&client->dev, client->irq,
-                                         NULL, bu21013_gpio_irq,
+       error = devm_request_threaded_irq(dev, client->irq, NULL, bu21013_gpio_irq,
                                          IRQF_ONESHOT, DRIVER_TP, ts);
        if (error) {
-               dev_err(&client->dev, "request irq %d failed\n",
-                       client->irq);
+               dev_err(dev, "request irq %d failed\n", client->irq);
                return error;
        }
 
        error = input_register_device(in_dev);
        if (error) {
-               dev_err(&client->dev, "failed to register input device\n");
+               dev_err(dev, "failed to register input device\n");
                return error;
        }
 
@@ -617,7 +607,7 @@ static struct i2c_driver bu21013_driver = {
                .name   =       DRIVER_TP,
                .pm     =       pm_sleep_ptr(&bu21013_dev_pm_ops),
        },
-       .probe_new      =       bu21013_probe,
+       .probe          =       bu21013_probe,
        .remove         =       bu21013_remove,
        .id_table       =       bu21013_id,
 };
index 8f14428..e1dfbd9 100644 (file)
@@ -333,6 +333,7 @@ static void bu21029_stop_chip(struct input_dev *dev)
 
 static int bu21029_probe(struct i2c_client *client)
 {
+       struct device *dev = &client->dev;
        struct bu21029_ts_data *bu21029;
        struct input_dev *in_dev;
        int error;
@@ -341,45 +342,33 @@ static int bu21029_probe(struct i2c_client *client)
                                     I2C_FUNC_SMBUS_WRITE_BYTE |
                                     I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
                                     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
-               dev_err(&client->dev,
-                       "i2c functionality support is not sufficient\n");
+               dev_err(dev, "i2c functionality support is not sufficient\n");
                return -EIO;
        }
 
-       bu21029 = devm_kzalloc(&client->dev, sizeof(*bu21029), GFP_KERNEL);
+       bu21029 = devm_kzalloc(dev, sizeof(*bu21029), GFP_KERNEL);
        if (!bu21029)
                return -ENOMEM;
 
-       error = device_property_read_u32(&client->dev, "rohm,x-plate-ohms",
-                                        &bu21029->x_plate_ohms);
+       error = device_property_read_u32(dev, "rohm,x-plate-ohms", &bu21029->x_plate_ohms);
        if (error) {
-               dev_err(&client->dev,
-                       "invalid 'x-plate-ohms' supplied: %d\n", error);
+               dev_err(dev, "invalid 'x-plate-ohms' supplied: %d\n", error);
                return error;
        }
 
-       bu21029->vdd = devm_regulator_get(&client->dev, "vdd");
-       if (IS_ERR(bu21029->vdd)) {
-               error = PTR_ERR(bu21029->vdd);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "failed to acquire 'vdd' supply: %d\n", error);
-               return error;
-       }
+       bu21029->vdd = devm_regulator_get(dev, "vdd");
+       if (IS_ERR(bu21029->vdd))
+               return dev_err_probe(dev, PTR_ERR(bu21029->vdd),
+                                    "failed to acquire 'vdd' supply\n");
 
-       bu21029->reset_gpios = devm_gpiod_get_optional(&client->dev,
-                                                      "reset", GPIOD_OUT_HIGH);
-       if (IS_ERR(bu21029->reset_gpios)) {
-               error = PTR_ERR(bu21029->reset_gpios);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "failed to acquire 'reset' gpio: %d\n", error);
-               return error;
-       }
+       bu21029->reset_gpios = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(bu21029->reset_gpios))
+               return dev_err_probe(dev, PTR_ERR(bu21029->reset_gpios),
+                                    "failed to acquire 'reset' gpio\n");
 
-       in_dev = devm_input_allocate_device(&client->dev);
+       in_dev = devm_input_allocate_device(dev);
        if (!in_dev) {
-               dev_err(&client->dev, "unable to allocate input device\n");
+               dev_err(dev, "unable to allocate input device\n");
                return -ENOMEM;
        }
 
@@ -400,20 +389,18 @@ static int bu21029_probe(struct i2c_client *client)
 
        input_set_drvdata(in_dev, bu21029);
 
-       error = devm_request_threaded_irq(&client->dev, client->irq,
-                                         NULL, bu21029_touch_soft_irq,
+       error = devm_request_threaded_irq(dev, client->irq, NULL,
+                                         bu21029_touch_soft_irq,
                                          IRQF_ONESHOT | IRQF_NO_AUTOEN,
                                          DRIVER_NAME, bu21029);
        if (error) {
-               dev_err(&client->dev,
-                       "unable to request touch irq: %d\n", error);
+               dev_err(dev, "unable to request touch irq: %d\n", error);
                return error;
        }
 
        error = input_register_device(in_dev);
        if (error) {
-               dev_err(&client->dev,
-                       "unable to register input device: %d\n", error);
+               dev_err(dev, "unable to register input device: %d\n", error);
                return error;
        }
 
@@ -474,7 +461,7 @@ static struct i2c_driver bu21029_driver = {
                .pm             = pm_sleep_ptr(&bu21029_pm_ops),
        },
        .id_table       = bu21029_ids,
-       .probe_new      = bu21029_probe,
+       .probe          = bu21029_probe,
 };
 module_i2c_driver(bu21029_driver);
 
index 32b714a..d6876d1 100644 (file)
@@ -191,12 +191,8 @@ static int icn8318_probe(struct i2c_client *client)
                return -ENOMEM;
 
        data->wake_gpio = devm_gpiod_get(dev, "wake", GPIOD_OUT_LOW);
-       if (IS_ERR(data->wake_gpio)) {
-               error = PTR_ERR(data->wake_gpio);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Error getting wake gpio: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(data->wake_gpio))
+               return dev_err_probe(dev, PTR_ERR(data->wake_gpio), "Error getting wake gpio\n");
 
        input = devm_input_allocate_device(dev);
        if (!input)
@@ -264,7 +260,7 @@ static struct i2c_driver icn8318_driver = {
                .pm     = pm_sleep_ptr(&icn8318_pm_ops),
                .of_match_table = icn8318_of_match,
        },
-       .probe_new = icn8318_probe,
+       .probe = icn8318_probe,
        .id_table = icn8318_i2c_id,
 };
 
index 246bee0..b569548 100644 (file)
@@ -498,7 +498,7 @@ static struct i2c_driver icn8505_driver = {
                .pm     = pm_sleep_ptr(&icn8505_pm_ops),
                .acpi_match_table = icn8505_acpi_match,
        },
-       .probe_new = icn8505_probe,
+       .probe = icn8505_probe,
 };
 
 module_i2c_driver(icn8505_driver);
index cd86477..ea38951 100644 (file)
@@ -258,12 +258,8 @@ static int cy8ctma140_probe(struct i2c_client *client)
        ts->regulators[1].supply = "vdd";
        error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators),
                                      ts->regulators);
-       if (error) {
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get regulators %d\n",
-                               error);
-               return error;
-       }
+       if (error)
+               return dev_err_probe(dev, error, "Failed to get regulators\n");
 
        error = cy8ctma140_power_up(ts);
        if (error)
@@ -344,7 +340,7 @@ static struct i2c_driver cy8ctma140_driver = {
                .of_match_table = cy8ctma140_of_match,
        },
        .id_table       = cy8ctma140_idtable,
-       .probe_new      = cy8ctma140_probe,
+       .probe          = cy8ctma140_probe,
 };
 module_i2c_driver(cy8ctma140_driver);
 
index dcf50fb..54d6c48 100644 (file)
@@ -279,7 +279,7 @@ static struct i2c_driver cy8ctmg110_driver = {
                .pm     = pm_sleep_ptr(&cy8ctmg110_pm),
        },
        .id_table       = cy8ctmg110_idtable,
-       .probe_new      = cy8ctmg110_probe,
+       .probe          = cy8ctmg110_probe,
 };
 
 module_i2c_driver(cy8ctmg110_driver);
index 0cd6f62..7cb2692 100644 (file)
@@ -1263,9 +1263,8 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
         * Ensure we wait until the watchdog timer
         * running on a different CPU finishes
         */
-       del_timer_sync(&cd->watchdog_timer);
+       timer_shutdown_sync(&cd->watchdog_timer);
        cancel_work_sync(&cd->watchdog_work);
-       del_timer_sync(&cd->watchdog_timer);
 }
 
 static void cyttsp4_watchdog_timer(struct timer_list *t)
index ec7a477..80a6890 100644 (file)
@@ -60,7 +60,7 @@ static struct i2c_driver cyttsp4_i2c_driver = {
                .name   = CYTTSP4_I2C_NAME,
                .pm     = pm_ptr(&cyttsp4_pm_ops),
        },
-       .probe_new      = cyttsp4_i2c_probe,
+       .probe          = cyttsp4_i2c_probe,
        .remove         = cyttsp4_i2c_remove,
        .id_table       = cyttsp4_i2c_id,
 };
index 3c9d072..b461ded 100644 (file)
@@ -43,6 +43,7 @@
 #define HID_DESC_REG                           0x1
 #define HID_INPUT_REG                          0x3
 #define HID_OUTPUT_REG                         0x4
+#define HID_COMMAND_REG                                0x5
 
 #define REPORT_ID_TOUCH                                0x1
 #define REPORT_ID_BTN                          0x3
@@ -68,6 +69,7 @@
 #define HID_APP_OUTPUT_REPORT_ID               0x2F
 #define HID_BL_RESPONSE_REPORT_ID              0x30
 #define HID_BL_OUTPUT_REPORT_ID                        0x40
+#define HID_RESPONSE_REPORT_ID                 0xF0
 
 #define HID_OUTPUT_RESPONSE_REPORT_OFFSET      2
 #define HID_OUTPUT_RESPONSE_CMD_OFFSET         4
 #define HID_SYSINFO_BTN_MASK                   GENMASK(7, 0)
 #define HID_SYSINFO_MAX_BTN                    8
 
+#define HID_CMD_SET_POWER                      0x8
+
+#define HID_POWER_ON                           0x0
+#define HID_POWER_SLEEP                                0x1
+
 #define CY_HID_OUTPUT_TIMEOUT_MS               200
 #define CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS   3000
 #define CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS   4000
+#define CY_HID_SET_POWER_TIMEOUT               500
 
 /* maximum number of concurrent tracks */
 #define TOUCH_REPORT_SIZE                      10
 #define TOUCH_REPORT_USAGE_PG_MIN              0xFF010063
 #define TOUCH_COL_USAGE_PG                     0x000D0022
 
+#define SET_CMD_LOW(byte, bits) \
+       ((byte) = (((byte) & 0xF0) | ((bits) & 0x0F)))
+#define SET_CMD_HIGH(byte, bits)\
+       ((byte) = (((byte) & 0x0F) | ((bits) & 0xF0)))
+#define SET_CMD_OPCODE(byte, opcode) SET_CMD_LOW(byte, opcode)
+#define SET_CMD_REPORT_TYPE(byte, type) SET_CMD_HIGH(byte, ((type) << 4))
+#define SET_CMD_REPORT_ID(byte, id) SET_CMD_LOW(byte, id)
+
 /* System Information interface definitions */
 struct cyttsp5_sensing_conf_data_dev {
        u8 electrodes_x;
@@ -557,6 +573,40 @@ static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5 *ts)
        return cyttsp5_get_sysinfo_regs(ts);
 }
 
+static int cyttsp5_power_control(struct cyttsp5 *ts, bool on)
+{
+       u8 state = on ? HID_POWER_ON : HID_POWER_SLEEP;
+       u8 cmd[2] = { 0 };
+       int rc;
+
+       SET_CMD_REPORT_TYPE(cmd[0], 0);
+       SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP);
+       SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER);
+
+       rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd));
+       if (rc) {
+               dev_err(ts->dev, "Failed to write power command %d", rc);
+               return rc;
+       }
+
+       rc = wait_for_completion_interruptible_timeout(&ts->cmd_done,
+                               msecs_to_jiffies(CY_HID_SET_POWER_TIMEOUT));
+       if (rc <= 0) {
+               dev_err(ts->dev, "HID power cmd execution timed out\n");
+               return -ETIMEDOUT;
+       }
+
+       if (ts->response_buf[2] != HID_RESPONSE_REPORT_ID ||
+           (ts->response_buf[3] & 0x03) != state ||
+           (ts->response_buf[4] & 0x0f) != HID_CMD_SET_POWER) {
+               dev_err(ts->dev, "Validation of the %s response failed\n",
+                       on ? "wakeup" : "sleep");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts)
 {
        int rc;
@@ -601,12 +651,7 @@ static int cyttsp5_get_hid_descriptor(struct cyttsp5 *ts,
                                      struct cyttsp5_hid_desc *desc)
 {
        struct device *dev = ts->dev;
-       __le16 hid_desc_register = cpu_to_le16(HID_DESC_REG);
        int rc;
-       u8 cmd[2];
-
-       /* Set HID descriptor register */
-       memcpy(cmd, &hid_desc_register, sizeof(hid_desc_register));
 
        rc = cyttsp5_write(ts, HID_DESC_REG, NULL, 0);
        if (rc) {
@@ -675,6 +720,10 @@ static irqreturn_t cyttsp5_handle_irq(int irq, void *handle)
        case HID_BTN_REPORT_ID:
                cyttsp5_btn_attention(ts->dev);
                break;
+       case HID_RESPONSE_REPORT_ID:
+               memcpy(ts->response_buf, ts->input_buf, size);
+               complete(&ts->cmd_done);
+               break;
        default:
                /* It is not an input but a command response */
                memcpy(ts->response_buf, ts->input_buf, size);
@@ -886,12 +935,35 @@ static const struct i2c_device_id cyttsp5_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
 
+static int __maybe_unused cyttsp5_suspend(struct device *dev)
+{
+       struct cyttsp5 *ts = dev_get_drvdata(dev);
+
+       if (!device_may_wakeup(dev))
+               cyttsp5_power_control(ts, false);
+
+       return 0;
+}
+
+static int __maybe_unused cyttsp5_resume(struct device *dev)
+{
+       struct cyttsp5 *ts = dev_get_drvdata(dev);
+
+       if (!device_may_wakeup(dev))
+               cyttsp5_power_control(ts, true);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cyttsp5_pm, cyttsp5_suspend, cyttsp5_resume);
+
 static struct i2c_driver cyttsp5_i2c_driver = {
        .driver = {
                .name = CYTTSP5_NAME,
                .of_match_table = cyttsp5_of_match,
+               .pm = &cyttsp5_pm,
        },
-       .probe_new = cyttsp5_i2c_probe,
+       .probe = cyttsp5_i2c_probe,
        .id_table = cyttsp5_i2c_id,
 };
 module_i2c_driver(cyttsp5_i2c_driver);
index 3f91cb4..127a8fd 100644 (file)
@@ -66,7 +66,7 @@ static struct i2c_driver cyttsp_i2c_driver = {
                .pm     = pm_sleep_ptr(&cyttsp_pm_ops),
                .of_match_table = cyttsp_of_i2c_match,
        },
-       .probe_new      = cyttsp_i2c_probe,
+       .probe          = cyttsp_i2c_probe,
        .id_table       = cyttsp_i2c_id,
 };
 
index 24ab9e9..457d533 100644 (file)
@@ -1168,13 +1168,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
        tsdata->max_support_points = chip_data->max_support_points;
 
        tsdata->vcc = devm_regulator_get(&client->dev, "vcc");
-       if (IS_ERR(tsdata->vcc)) {
-               error = PTR_ERR(tsdata->vcc);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "failed to request regulator: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(tsdata->vcc))
+               return dev_err_probe(&client->dev, PTR_ERR(tsdata->vcc),
+                                    "failed to request regulator\n");
 
        tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc");
        if (IS_ERR(tsdata->iovcc)) {
@@ -1241,6 +1237,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
        if (tsdata->wake_gpio) {
                usleep_range(5000, 6000);
                gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
+               usleep_range(5000, 6000);
        }
 
        if (tsdata->reset_gpio) {
@@ -1510,7 +1507,7 @@ static struct i2c_driver edt_ft5x06_ts_driver = {
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
        .id_table = edt_ft5x06_ts_id,
-       .probe_new = edt_ft5x06_ts_probe,
+       .probe    = edt_ft5x06_ts_probe,
        .remove   = edt_ft5x06_ts_remove,
 };
 
index 56fa216..5e4167f 100644 (file)
@@ -291,7 +291,7 @@ static struct i2c_driver eeti_ts_driver = {
                .pm = pm_sleep_ptr(&eeti_ts_pm),
                .of_match_table = of_match_ptr(of_eeti_ts_match),
        },
-       .probe_new = eeti_ts_probe,
+       .probe = eeti_ts_probe,
        .id_table = eeti_ts_id,
 };
 
index 1a98059..a7f7e73 100644 (file)
@@ -264,7 +264,7 @@ static struct i2c_driver egalax_ts_driver = {
                .of_match_table = egalax_ts_dt_ids,
        },
        .id_table       = egalax_ts_id,
-       .probe_new      = egalax_ts_probe,
+       .probe          = egalax_ts_probe,
 };
 
 module_i2c_driver(egalax_ts_driver);
index e6f1e46..cc3103b 100644 (file)
@@ -264,12 +264,8 @@ static int ektf2127_probe(struct i2c_client *client)
 
        /* This requests the gpio *and* turns on the touchscreen controller */
        ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH);
-       if (IS_ERR(ts->power_gpios)) {
-               error = PTR_ERR(ts->power_gpios);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Error getting power gpio: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(ts->power_gpios))
+               return dev_err_probe(dev, PTR_ERR(ts->power_gpios), "Error getting power gpio\n");
 
        input = devm_input_allocate_device(dev);
        if (!input)
@@ -351,7 +347,7 @@ static struct i2c_driver ektf2127_driver = {
                .pm     = pm_sleep_ptr(&ektf2127_pm_ops),
                .of_match_table = of_match_ptr(ektf2127_of_match),
        },
-       .probe_new = ektf2127_probe,
+       .probe = ektf2127_probe,
        .id_table = ektf2127_i2c_id,
 };
 module_i2c_driver(ektf2127_driver);
index 8a16eb5..a1af3de 100644 (file)
@@ -1438,24 +1438,14 @@ static int elants_i2c_probe(struct i2c_client *client)
        i2c_set_clientdata(client, ts);
 
        ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
-       if (IS_ERR(ts->vcc33)) {
-               error = PTR_ERR(ts->vcc33);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "Failed to get 'vcc33' regulator: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(ts->vcc33))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->vcc33),
+                                    "Failed to get 'vcc33' regulator\n");
 
        ts->vccio = devm_regulator_get(&client->dev, "vccio");
-       if (IS_ERR(ts->vccio)) {
-               error = PTR_ERR(ts->vccio);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "Failed to get 'vccio' regulator: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(ts->vccio))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->vccio),
+                                    "Failed to get 'vccio' regulator\n");
 
        ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
        if (IS_ERR(ts->reset_gpio)) {
@@ -1673,7 +1663,7 @@ MODULE_DEVICE_TABLE(of, elants_of_match);
 #endif
 
 static struct i2c_driver elants_i2c_driver = {
-       .probe_new = elants_i2c_probe,
+       .probe = elants_i2c_probe,
        .id_table = elants_i2c_id,
        .driver = {
                .name = DEVICE_NAME,
index 69eae79..e3f6d21 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/regulator/consumer.h>
 #include <linux/sizes.h>
 #include <linux/timer.h>
 #include <asm/unaligned.h>
@@ -360,6 +361,12 @@ static int exc3000_probe(struct i2c_client *client)
        if (IS_ERR(data->reset))
                return PTR_ERR(data->reset);
 
+       /* For proper reset sequence, enable power while reset asserted */
+       error = devm_regulator_get_enable(&client->dev, "vdd");
+       if (error && error != -ENODEV)
+               return dev_err_probe(&client->dev, error,
+                                    "failed to request vdd regulator\n");
+
        if (data->reset) {
                msleep(EXC3000_RESET_MS);
                gpiod_set_value_cansleep(data->reset, 0);
@@ -460,7 +467,7 @@ static struct i2c_driver exc3000_driver = {
                .of_match_table = of_match_ptr(exc3000_of_match),
        },
        .id_table       = exc3000_id,
-       .probe_new      = exc3000_probe,
+       .probe          = exc3000_probe,
 };
 
 module_i2c_driver(exc3000_driver);
index d77f116..85d4249 100644 (file)
@@ -935,7 +935,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
  */
 static int goodix_get_gpio_config(struct goodix_ts_data *ts)
 {
-       int error;
        struct device *dev;
        struct gpio_desc *gpiod;
        bool added_acpi_mappings = false;
@@ -951,33 +950,20 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
        ts->gpiod_rst_flags = GPIOD_IN;
 
        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;
-       }
+       if (IS_ERR(ts->avdd28))
+               return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n");
 
        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;
-       }
+       if (IS_ERR(ts->vddio))
+               return dev_err_probe(dev, PTR_ERR(ts->vddio), "Failed to get VDDIO regulator\n");
 
 retry_get_irq_gpio:
        /* Get the interrupt GPIO pin number */
        gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
-       if (IS_ERR(gpiod)) {
-               error = PTR_ERR(gpiod);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get %s GPIO: %d\n",
-                               GOODIX_GPIO_INT_NAME, error);
-               return error;
-       }
+       if (IS_ERR(gpiod))
+               return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
+                                    GOODIX_GPIO_INT_NAME);
+
        if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) {
                added_acpi_mappings = true;
                if (goodix_add_acpi_gpio_mappings(ts) == 0)
@@ -988,13 +974,9 @@ retry_get_irq_gpio:
 
        /* Get the reset line GPIO pin number */
        gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
-       if (IS_ERR(gpiod)) {
-               error = PTR_ERR(gpiod);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get %s GPIO: %d\n",
-                               GOODIX_GPIO_RST_NAME, error);
-               return error;
-       }
+       if (IS_ERR(gpiod))
+               return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
+                                    GOODIX_GPIO_RST_NAME);
 
        ts->gpiod_rst = gpiod;
 
@@ -1544,7 +1526,7 @@ MODULE_DEVICE_TABLE(of, goodix_of_match);
 #endif
 
 static struct i2c_driver goodix_ts_driver = {
-       .probe_new = goodix_ts_probe,
+       .probe = goodix_ts_probe,
        .remove = goodix_ts_remove,
        .id_table = goodix_ts_id,
        .driver = {
index 7c70200..4041533 100644 (file)
@@ -1136,7 +1136,7 @@ static struct i2c_driver hideep_driver = {
                .pm                     = pm_sleep_ptr(&hideep_pm_ops),
        },
        .id_table       = hideep_i2c_id,
-       .probe_new      = hideep_probe,
+       .probe          = hideep_probe,
 };
 
 module_i2c_driver(hideep_driver);
index e96150d..4f6609d 100644 (file)
@@ -349,7 +349,7 @@ MODULE_DEVICE_TABLE(of, himax_of_match);
 #endif
 
 static struct i2c_driver himax_ts_driver = {
-       .probe_new = himax_probe,
+       .probe = himax_probe,
        .id_table = himax_ts_id,
        .driver = {
                .name = "Himax-hx83112b-TS",
index 8f4989a..2450cfa 100644 (file)
@@ -580,7 +580,7 @@ static struct i2c_driver hycon_hy46xx_driver = {
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
        .id_table = hycon_hy46xx_id,
-       .probe_new = hycon_hy46xx_probe,
+       .probe = hycon_hy46xx_probe,
 };
 
 module_i2c_driver(hycon_hy46xx_driver);
index e86c85a..05946fe 100644 (file)
@@ -488,7 +488,7 @@ static struct i2c_driver hynitron_i2c_driver = {
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
        .id_table = hyn_tpd_id,
-       .probe_new = hyn_probe,
+       .probe = hyn_probe,
 };
 
 module_i2c_driver(hynitron_i2c_driver);
index 4897faf..f7cd773 100644 (file)
@@ -370,22 +370,33 @@ static int ili251x_firmware_update_resolution(struct device *dev)
 
        /* The firmware update blob might have changed the resolution. */
        error = priv->chip->read_reg(client, REG_PANEL_INFO, &rs, sizeof(rs));
-       if (error)
-               return error;
+       if (!error) {
+               resx = le16_to_cpup((__le16 *)rs);
+               resy = le16_to_cpup((__le16 *)(rs + 2));
 
-       resx = le16_to_cpup((__le16 *)rs);
-       resy = le16_to_cpup((__le16 *)(rs + 2));
+               /* The value reported by the firmware is invalid. */
+               if (!resx || resx == 0xffff || !resy || resy == 0xffff)
+                       error = -EINVAL;
+       }
 
-       /* The value reported by the firmware is invalid. */
-       if (!resx || resx == 0xffff || !resy || resy == 0xffff)
-               return -EINVAL;
+       /*
+        * In case of error, the firmware might be stuck in bootloader mode,
+        * e.g. after a failed firmware update. Set maximum resolution, but
+        * do not fail to probe, so the user can re-trigger the firmware
+        * update and recover the touch controller.
+        */
+       if (error) {
+               dev_warn(dev, "Invalid resolution reported by controller.\n");
+               resx = 16384;
+               resy = 16384;
+       }
 
        input_abs_set_max(priv->input, ABS_X, resx - 1);
        input_abs_set_max(priv->input, ABS_Y, resy - 1);
        input_abs_set_max(priv->input, ABS_MT_POSITION_X, resx - 1);
        input_abs_set_max(priv->input, ABS_MT_POSITION_Y, resy - 1);
 
-       return 0;
+       return error;
 }
 
 static ssize_t ili251x_firmware_update_firmware_version(struct device *dev)
@@ -977,11 +988,10 @@ static int ili210x_i2c_probe(struct i2c_client *client)
        if (priv->chip->has_pressure_reg)
                input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0);
        error = ili251x_firmware_update_cached_state(dev);
-       if (error) {
-               dev_err(dev, "Unable to cache firmware information, err: %d\n",
-                       error);
-               return error;
-       }
+       if (error)
+               dev_warn(dev, "Unable to cache firmware information, err: %d\n",
+                        error);
+
        touchscreen_parse_properties(input, true, &priv->prop);
 
        error = input_mt_init_slots(input, priv->chip->max_touches,
@@ -1043,7 +1053,7 @@ static struct i2c_driver ili210x_ts_driver = {
                .of_match_table = ili210x_dt_ids,
        },
        .id_table = ili210x_i2c_id,
-       .probe_new = ili210x_i2c_probe,
+       .probe = ili210x_i2c_probe,
 };
 
 module_i2c_driver(ili210x_ts_driver);
index d698093..2f872e9 100644 (file)
@@ -679,7 +679,7 @@ static struct i2c_driver ilitek_ts_i2c_driver = {
                .of_match_table = of_match_ptr(ilitek_ts_i2c_match),
                .acpi_match_table = ACPI_PTR(ilitekts_acpi_id),
        },
-       .probe_new = ilitek_ts_i2c_probe,
+       .probe = ilitek_ts_i2c_probe,
        .id_table = ilitek_ts_i2c_id,
 };
 module_i2c_driver(ilitek_ts_i2c_driver);
index de1b16e..07111ca 100644 (file)
@@ -357,7 +357,7 @@ static struct i2c_driver imagis_ts_driver = {
                .pm = pm_sleep_ptr(&imagis_pm_ops),
                .of_match_table = of_match_ptr(imagis_of_match),
        },
-       .probe_new = imagis_probe,
+       .probe = imagis_probe,
 };
 
 module_i2c_driver(imagis_ts_driver);
index c73e9c5..0aa9d64 100644 (file)
@@ -1093,7 +1093,7 @@ static struct i2c_driver iqs5xx_i2c_driver = {
                .pm             = pm_sleep_ptr(&iqs5xx_pm),
        },
        .id_table       = iqs5xx_id,
-       .probe_new      = iqs5xx_probe,
+       .probe          = iqs5xx_probe,
 };
 module_i2c_driver(iqs5xx_i2c_driver);
 
diff --git a/drivers/input/touchscreen/iqs7211.c b/drivers/input/touchscreen/iqs7211.c
new file mode 100644 (file)
index 0000000..dc084f8
--- /dev/null
@@ -0,0 +1,2557 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller
+ *
+ * Copyright (C) 2023 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.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/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+
+#define IQS7211_PROD_NUM                       0x00
+
+#define IQS7211_EVENT_MASK_ALL                 GENMASK(14, 8)
+#define IQS7211_EVENT_MASK_ALP                 BIT(13)
+#define IQS7211_EVENT_MASK_BTN                 BIT(12)
+#define IQS7211_EVENT_MASK_ATI                 BIT(11)
+#define IQS7211_EVENT_MASK_MOVE                        BIT(10)
+#define IQS7211_EVENT_MASK_GSTR                        BIT(9)
+#define IQS7211_EVENT_MODE                     BIT(8)
+
+#define IQS7211_COMMS_ERROR                    0xEEEE
+#define IQS7211_COMMS_RETRY_MS                 50
+#define IQS7211_COMMS_SLEEP_US                 100
+#define IQS7211_COMMS_TIMEOUT_US               (100 * USEC_PER_MSEC)
+#define IQS7211_RESET_TIMEOUT_MS               150
+#define IQS7211_START_TIMEOUT_US               (1 * USEC_PER_SEC)
+
+#define IQS7211_NUM_RETRIES                    5
+#define IQS7211_NUM_CRX                                8
+#define IQS7211_MAX_CTX                                13
+
+#define IQS7211_MAX_CONTACTS                   2
+#define IQS7211_MAX_CYCLES                     21
+
+/*
+ * The following delay is used during instances that must wait for the open-
+ * drain RDY pin to settle. Its value is calculated as 5*R*C, where R and C
+ * represent typical datasheet values of 4.7k and 100 nF, respectively.
+ */
+#define iqs7211_irq_wait()                     usleep_range(2500, 2600)
+
+enum iqs7211_dev_id {
+       IQS7210A,
+       IQS7211A,
+       IQS7211E,
+};
+
+enum iqs7211_comms_mode {
+       IQS7211_COMMS_MODE_WAIT,
+       IQS7211_COMMS_MODE_FREE,
+       IQS7211_COMMS_MODE_FORCE,
+};
+
+struct iqs7211_reg_field_desc {
+       struct list_head list;
+       u8 addr;
+       u16 mask;
+       u16 val;
+};
+
+enum iqs7211_reg_key_id {
+       IQS7211_REG_KEY_NONE,
+       IQS7211_REG_KEY_PROX,
+       IQS7211_REG_KEY_TOUCH,
+       IQS7211_REG_KEY_TAP,
+       IQS7211_REG_KEY_HOLD,
+       IQS7211_REG_KEY_PALM,
+       IQS7211_REG_KEY_AXIAL_X,
+       IQS7211_REG_KEY_AXIAL_Y,
+       IQS7211_REG_KEY_RESERVED
+};
+
+enum iqs7211_reg_grp_id {
+       IQS7211_REG_GRP_TP,
+       IQS7211_REG_GRP_BTN,
+       IQS7211_REG_GRP_ALP,
+       IQS7211_REG_GRP_SYS,
+       IQS7211_NUM_REG_GRPS
+};
+
+static const char * const iqs7211_reg_grp_names[IQS7211_NUM_REG_GRPS] = {
+       [IQS7211_REG_GRP_TP] = "trackpad",
+       [IQS7211_REG_GRP_BTN] = "button",
+       [IQS7211_REG_GRP_ALP] = "alp",
+};
+
+static const u16 iqs7211_reg_grp_masks[IQS7211_NUM_REG_GRPS] = {
+       [IQS7211_REG_GRP_TP] = IQS7211_EVENT_MASK_GSTR,
+       [IQS7211_REG_GRP_BTN] = IQS7211_EVENT_MASK_BTN,
+       [IQS7211_REG_GRP_ALP] = IQS7211_EVENT_MASK_ALP,
+};
+
+struct iqs7211_event_desc {
+       const char *name;
+       u16 mask;
+       u16 enable;
+       enum iqs7211_reg_grp_id reg_grp;
+       enum iqs7211_reg_key_id reg_key;
+};
+
+static const struct iqs7211_event_desc iqs7210a_kp_events[] = {
+       {
+               .mask = BIT(10),
+               .enable = BIT(13) | BIT(12),
+               .reg_grp = IQS7211_REG_GRP_ALP,
+       },
+       {
+               .name = "event-prox",
+               .mask = BIT(2),
+               .enable = BIT(5) | BIT(4),
+               .reg_grp = IQS7211_REG_GRP_BTN,
+               .reg_key = IQS7211_REG_KEY_PROX,
+       },
+       {
+               .name = "event-touch",
+               .mask = BIT(3),
+               .enable = BIT(5) | BIT(4),
+               .reg_grp = IQS7211_REG_GRP_BTN,
+               .reg_key = IQS7211_REG_KEY_TOUCH,
+       },
+       {
+               .name = "event-tap",
+               .mask = BIT(0),
+               .enable = BIT(0),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_TAP,
+       },
+       {
+               .name = "event-hold",
+               .mask = BIT(1),
+               .enable = BIT(1),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_HOLD,
+       },
+       {
+               .name = "event-swipe-x-neg",
+               .mask = BIT(2),
+               .enable = BIT(2),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+       },
+       {
+               .name = "event-swipe-x-pos",
+               .mask = BIT(3),
+               .enable = BIT(3),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+       },
+       {
+               .name = "event-swipe-y-pos",
+               .mask = BIT(4),
+               .enable = BIT(4),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+       },
+       {
+               .name = "event-swipe-y-neg",
+               .mask = BIT(5),
+               .enable = BIT(5),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+       },
+};
+
+static const struct iqs7211_event_desc iqs7211a_kp_events[] = {
+       {
+               .mask = BIT(14),
+               .reg_grp = IQS7211_REG_GRP_ALP,
+       },
+       {
+               .name = "event-tap",
+               .mask = BIT(0),
+               .enable = BIT(0),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_TAP,
+       },
+       {
+               .name = "event-hold",
+               .mask = BIT(1),
+               .enable = BIT(1),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_HOLD,
+       },
+       {
+               .name = "event-swipe-x-neg",
+               .mask = BIT(2),
+               .enable = BIT(2),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+       },
+       {
+               .name = "event-swipe-x-pos",
+               .mask = BIT(3),
+               .enable = BIT(3),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+       },
+       {
+               .name = "event-swipe-y-pos",
+               .mask = BIT(4),
+               .enable = BIT(4),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+       },
+       {
+               .name = "event-swipe-y-neg",
+               .mask = BIT(5),
+               .enable = BIT(5),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+       },
+};
+
+static const struct iqs7211_event_desc iqs7211e_kp_events[] = {
+       {
+               .mask = BIT(14),
+               .reg_grp = IQS7211_REG_GRP_ALP,
+       },
+       {
+               .name = "event-tap",
+               .mask = BIT(0),
+               .enable = BIT(0),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_TAP,
+       },
+       {
+               .name = "event-tap-double",
+               .mask = BIT(1),
+               .enable = BIT(1),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_TAP,
+       },
+       {
+               .name = "event-tap-triple",
+               .mask = BIT(2),
+               .enable = BIT(2),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_TAP,
+       },
+       {
+               .name = "event-hold",
+               .mask = BIT(3),
+               .enable = BIT(3),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_HOLD,
+       },
+       {
+               .name = "event-palm",
+               .mask = BIT(4),
+               .enable = BIT(4),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_PALM,
+       },
+       {
+               .name = "event-swipe-x-pos",
+               .mask = BIT(8),
+               .enable = BIT(8),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+       },
+       {
+               .name = "event-swipe-x-neg",
+               .mask = BIT(9),
+               .enable = BIT(9),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+       },
+       {
+               .name = "event-swipe-y-pos",
+               .mask = BIT(10),
+               .enable = BIT(10),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+       },
+       {
+               .name = "event-swipe-y-neg",
+               .mask = BIT(11),
+               .enable = BIT(11),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+       },
+       {
+               .name = "event-swipe-x-pos-hold",
+               .mask = BIT(12),
+               .enable = BIT(12),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_HOLD,
+       },
+       {
+               .name = "event-swipe-x-neg-hold",
+               .mask = BIT(13),
+               .enable = BIT(13),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_HOLD,
+       },
+       {
+               .name = "event-swipe-y-pos-hold",
+               .mask = BIT(14),
+               .enable = BIT(14),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_HOLD,
+       },
+       {
+               .name = "event-swipe-y-neg-hold",
+               .mask = BIT(15),
+               .enable = BIT(15),
+               .reg_grp = IQS7211_REG_GRP_TP,
+               .reg_key = IQS7211_REG_KEY_HOLD,
+       },
+};
+
+struct iqs7211_dev_desc {
+       const char *tp_name;
+       const char *kp_name;
+       u16 prod_num;
+       u16 show_reset;
+       u16 ati_error[IQS7211_NUM_REG_GRPS];
+       u16 ati_start[IQS7211_NUM_REG_GRPS];
+       u16 suspend;
+       u16 ack_reset;
+       u16 comms_end;
+       u16 comms_req;
+       int charge_shift;
+       int info_offs;
+       int gesture_offs;
+       int contact_offs;
+       u8 sys_stat;
+       u8 sys_ctrl;
+       u8 alp_config;
+       u8 tp_config;
+       u8 exp_file;
+       u8 kp_enable[IQS7211_NUM_REG_GRPS];
+       u8 gesture_angle;
+       u8 rx_tx_map;
+       u8 cycle_alloc[2];
+       u8 cycle_limit[2];
+       const struct iqs7211_event_desc *kp_events;
+       int num_kp_events;
+       int min_crx_alp;
+       int num_ctx;
+};
+
+static const struct iqs7211_dev_desc iqs7211_devs[] = {
+       [IQS7210A] = {
+               .tp_name = "iqs7210a_trackpad",
+               .kp_name = "iqs7210a_keys",
+               .prod_num = 944,
+               .show_reset = BIT(15),
+               .ati_error = {
+                       [IQS7211_REG_GRP_TP] = BIT(12),
+                       [IQS7211_REG_GRP_BTN] = BIT(0),
+                       [IQS7211_REG_GRP_ALP] = BIT(8),
+               },
+               .ati_start = {
+                       [IQS7211_REG_GRP_TP] = BIT(13),
+                       [IQS7211_REG_GRP_BTN] = BIT(1),
+                       [IQS7211_REG_GRP_ALP] = BIT(9),
+               },
+               .suspend = BIT(11),
+               .ack_reset = BIT(7),
+               .comms_end = BIT(2),
+               .comms_req = BIT(1),
+               .charge_shift = 4,
+               .info_offs = 0,
+               .gesture_offs = 1,
+               .contact_offs = 4,
+               .sys_stat = 0x0A,
+               .sys_ctrl = 0x35,
+               .alp_config = 0x39,
+               .tp_config = 0x4E,
+               .exp_file = 0x57,
+               .kp_enable = {
+                       [IQS7211_REG_GRP_TP] = 0x58,
+                       [IQS7211_REG_GRP_BTN] = 0x37,
+                       [IQS7211_REG_GRP_ALP] = 0x37,
+               },
+               .gesture_angle = 0x5F,
+               .rx_tx_map = 0x60,
+               .cycle_alloc = { 0x66, 0x75, },
+               .cycle_limit = { 10, 6, },
+               .kp_events = iqs7210a_kp_events,
+               .num_kp_events = ARRAY_SIZE(iqs7210a_kp_events),
+               .min_crx_alp = 4,
+               .num_ctx = IQS7211_MAX_CTX - 1,
+       },
+       [IQS7211A] = {
+               .tp_name = "iqs7211a_trackpad",
+               .kp_name = "iqs7211a_keys",
+               .prod_num = 763,
+               .show_reset = BIT(7),
+               .ati_error = {
+                       [IQS7211_REG_GRP_TP] = BIT(3),
+                       [IQS7211_REG_GRP_ALP] = BIT(5),
+               },
+               .ati_start = {
+                       [IQS7211_REG_GRP_TP] = BIT(5),
+                       [IQS7211_REG_GRP_ALP] = BIT(6),
+               },
+               .ack_reset = BIT(7),
+               .comms_req = BIT(4),
+               .charge_shift = 0,
+               .info_offs = 0,
+               .gesture_offs = 1,
+               .contact_offs = 4,
+               .sys_stat = 0x10,
+               .sys_ctrl = 0x50,
+               .tp_config = 0x60,
+               .alp_config = 0x72,
+               .exp_file = 0x74,
+               .kp_enable = {
+                       [IQS7211_REG_GRP_TP] = 0x80,
+               },
+               .gesture_angle = 0x87,
+               .rx_tx_map = 0x90,
+               .cycle_alloc = { 0xA0, 0xB0, },
+               .cycle_limit = { 10, 8, },
+               .kp_events = iqs7211a_kp_events,
+               .num_kp_events = ARRAY_SIZE(iqs7211a_kp_events),
+               .num_ctx = IQS7211_MAX_CTX - 1,
+       },
+       [IQS7211E] = {
+               .tp_name = "iqs7211e_trackpad",
+               .kp_name = "iqs7211e_keys",
+               .prod_num = 1112,
+               .show_reset = BIT(7),
+               .ati_error = {
+                       [IQS7211_REG_GRP_TP] = BIT(3),
+                       [IQS7211_REG_GRP_ALP] = BIT(5),
+               },
+               .ati_start = {
+                       [IQS7211_REG_GRP_TP] = BIT(5),
+                       [IQS7211_REG_GRP_ALP] = BIT(6),
+               },
+               .suspend = BIT(11),
+               .ack_reset = BIT(7),
+               .comms_end = BIT(6),
+               .comms_req = BIT(4),
+               .charge_shift = 0,
+               .info_offs = 1,
+               .gesture_offs = 0,
+               .contact_offs = 2,
+               .sys_stat = 0x0E,
+               .sys_ctrl = 0x33,
+               .tp_config = 0x41,
+               .alp_config = 0x36,
+               .exp_file = 0x4A,
+               .kp_enable = {
+                       [IQS7211_REG_GRP_TP] = 0x4B,
+               },
+               .gesture_angle = 0x55,
+               .rx_tx_map = 0x56,
+               .cycle_alloc = { 0x5D, 0x6C, },
+               .cycle_limit = { 10, 11, },
+               .kp_events = iqs7211e_kp_events,
+               .num_kp_events = ARRAY_SIZE(iqs7211e_kp_events),
+               .num_ctx = IQS7211_MAX_CTX,
+       },
+};
+
+struct iqs7211_prop_desc {
+       const char *name;
+       enum iqs7211_reg_key_id reg_key;
+       u8 reg_addr[IQS7211_NUM_REG_GRPS][ARRAY_SIZE(iqs7211_devs)];
+       int reg_shift;
+       int reg_width;
+       int val_pitch;
+       int val_min;
+       int val_max;
+       const char *label;
+};
+
+static const struct iqs7211_prop_desc iqs7211_props[] = {
+       {
+               .name = "azoteq,ati-frac-div-fine",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x1E,
+                               [IQS7211A] = 0x30,
+                               [IQS7211E] = 0x21,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x22,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x23,
+                               [IQS7211A] = 0x36,
+                               [IQS7211E] = 0x25,
+                       },
+               },
+               .reg_shift = 9,
+               .reg_width = 5,
+               .label = "ATI fine fractional divider",
+       },
+       {
+               .name = "azoteq,ati-frac-mult-coarse",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x1E,
+                               [IQS7211A] = 0x30,
+                               [IQS7211E] = 0x21,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x22,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x23,
+                               [IQS7211A] = 0x36,
+                               [IQS7211E] = 0x25,
+                       },
+               },
+               .reg_shift = 5,
+               .reg_width = 4,
+               .label = "ATI coarse fractional multiplier",
+       },
+       {
+               .name = "azoteq,ati-frac-div-coarse",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x1E,
+                               [IQS7211A] = 0x30,
+                               [IQS7211E] = 0x21,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x22,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x23,
+                               [IQS7211A] = 0x36,
+                               [IQS7211E] = 0x25,
+                       },
+               },
+               .reg_shift = 0,
+               .reg_width = 5,
+               .label = "ATI coarse fractional divider",
+       },
+       {
+               .name = "azoteq,ati-comp-div",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x1F,
+                               [IQS7211E] = 0x22,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x24,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7211E] = 0x26,
+                       },
+               },
+               .reg_shift = 0,
+               .reg_width = 8,
+               .val_max = 31,
+               .label = "ATI compensation divider",
+       },
+       {
+               .name = "azoteq,ati-comp-div",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x24,
+                       },
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .val_max = 31,
+               .label = "ATI compensation divider",
+       },
+       {
+               .name = "azoteq,ati-comp-div",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7211A] = 0x31,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7211A] = 0x37,
+                       },
+               },
+               .val_max = 31,
+               .label = "ATI compensation divider",
+       },
+       {
+               .name = "azoteq,ati-target",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x20,
+                               [IQS7211A] = 0x32,
+                               [IQS7211E] = 0x23,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x27,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x28,
+                               [IQS7211A] = 0x38,
+                               [IQS7211E] = 0x27,
+                       },
+               },
+               .label = "ATI target",
+       },
+       {
+               .name = "azoteq,ati-base",
+               .reg_addr[IQS7211_REG_GRP_ALP] = {
+                       [IQS7210A] = 0x26,
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .val_pitch = 8,
+               .label = "ATI base",
+       },
+       {
+               .name = "azoteq,ati-base",
+               .reg_addr[IQS7211_REG_GRP_BTN] = {
+                       [IQS7210A] = 0x26,
+               },
+               .reg_shift = 0,
+               .reg_width = 8,
+               .val_pitch = 8,
+               .label = "ATI base",
+       },
+       {
+               .name = "azoteq,rate-active-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x29,
+                       [IQS7211A] = 0x40,
+                       [IQS7211E] = 0x28,
+               },
+               .label = "active mode report rate",
+       },
+       {
+               .name = "azoteq,rate-touch-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x2A,
+                       [IQS7211A] = 0x41,
+                       [IQS7211E] = 0x29,
+               },
+               .label = "idle-touch mode report rate",
+       },
+       {
+               .name = "azoteq,rate-idle-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x2B,
+                       [IQS7211A] = 0x42,
+                       [IQS7211E] = 0x2A,
+               },
+               .label = "idle mode report rate",
+       },
+       {
+               .name = "azoteq,rate-lp1-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x2C,
+                       [IQS7211A] = 0x43,
+                       [IQS7211E] = 0x2B,
+               },
+               .label = "low-power mode 1 report rate",
+       },
+       {
+               .name = "azoteq,rate-lp2-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x2D,
+                       [IQS7211A] = 0x44,
+                       [IQS7211E] = 0x2C,
+               },
+               .label = "low-power mode 2 report rate",
+       },
+       {
+               .name = "azoteq,timeout-active-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x2E,
+                       [IQS7211A] = 0x45,
+                       [IQS7211E] = 0x2D,
+               },
+               .val_pitch = 1000,
+               .label = "active mode timeout",
+       },
+       {
+               .name = "azoteq,timeout-touch-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x2F,
+                       [IQS7211A] = 0x46,
+                       [IQS7211E] = 0x2E,
+               },
+               .val_pitch = 1000,
+               .label = "idle-touch mode timeout",
+       },
+       {
+               .name = "azoteq,timeout-idle-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x30,
+                       [IQS7211A] = 0x47,
+                       [IQS7211E] = 0x2F,
+               },
+               .val_pitch = 1000,
+               .label = "idle mode timeout",
+       },
+       {
+               .name = "azoteq,timeout-lp1-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x31,
+                       [IQS7211A] = 0x48,
+                       [IQS7211E] = 0x30,
+               },
+               .val_pitch = 1000,
+               .label = "low-power mode 1 timeout",
+       },
+       {
+               .name = "azoteq,timeout-lp2-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x32,
+                       [IQS7211E] = 0x31,
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .val_pitch = 1000,
+               .val_max = 60000,
+               .label = "trackpad reference value update rate",
+       },
+       {
+               .name = "azoteq,timeout-lp2-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7211A] = 0x49,
+               },
+               .val_pitch = 1000,
+               .val_max = 60000,
+               .label = "trackpad reference value update rate",
+       },
+       {
+               .name = "azoteq,timeout-ati-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x32,
+                       [IQS7211E] = 0x31,
+               },
+               .reg_width = 8,
+               .val_pitch = 1000,
+               .val_max = 60000,
+               .label = "ATI error timeout",
+       },
+       {
+               .name = "azoteq,timeout-ati-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7211A] = 0x35,
+               },
+               .val_pitch = 1000,
+               .val_max = 60000,
+               .label = "ATI error timeout",
+       },
+       {
+               .name = "azoteq,timeout-comms-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x33,
+                       [IQS7211A] = 0x4A,
+                       [IQS7211E] = 0x32,
+               },
+               .label = "communication timeout",
+       },
+       {
+               .name = "azoteq,timeout-press-ms",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x34,
+               },
+               .reg_width = 8,
+               .val_pitch = 1000,
+               .val_max = 60000,
+               .label = "press timeout",
+       },
+       {
+               .name = "azoteq,ati-mode",
+               .reg_addr[IQS7211_REG_GRP_ALP] = {
+                       [IQS7210A] = 0x37,
+               },
+               .reg_shift = 15,
+               .reg_width = 1,
+               .label = "ATI mode",
+       },
+       {
+               .name = "azoteq,ati-mode",
+               .reg_addr[IQS7211_REG_GRP_BTN] = {
+                       [IQS7210A] = 0x37,
+               },
+               .reg_shift = 7,
+               .reg_width = 1,
+               .label = "ATI mode",
+       },
+       {
+               .name = "azoteq,sense-mode",
+               .reg_addr[IQS7211_REG_GRP_ALP] = {
+                       [IQS7210A] = 0x37,
+                       [IQS7211A] = 0x72,
+                       [IQS7211E] = 0x36,
+               },
+               .reg_shift = 8,
+               .reg_width = 1,
+               .label = "sensing mode",
+       },
+       {
+               .name = "azoteq,sense-mode",
+               .reg_addr[IQS7211_REG_GRP_BTN] = {
+                       [IQS7210A] = 0x37,
+               },
+               .reg_shift = 0,
+               .reg_width = 2,
+               .val_max = 2,
+               .label = "sensing mode",
+       },
+       {
+               .name = "azoteq,fosc-freq",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x38,
+                       [IQS7211A] = 0x52,
+                       [IQS7211E] = 0x35,
+               },
+               .reg_shift = 4,
+               .reg_width = 1,
+               .label = "core clock frequency selection",
+       },
+       {
+               .name = "azoteq,fosc-trim",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x38,
+                       [IQS7211A] = 0x52,
+                       [IQS7211E] = 0x35,
+               },
+               .reg_shift = 0,
+               .reg_width = 4,
+               .label = "core clock frequency trim",
+       },
+       {
+               .name = "azoteq,touch-exit",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x3B,
+                               [IQS7211A] = 0x53,
+                               [IQS7211E] = 0x38,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x3E,
+                       },
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .label = "touch exit factor",
+       },
+       {
+               .name = "azoteq,touch-enter",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x3B,
+                               [IQS7211A] = 0x53,
+                               [IQS7211E] = 0x38,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x3E,
+                       },
+               },
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "touch entrance factor",
+       },
+       {
+               .name = "azoteq,thresh",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x3C,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x3D,
+                               [IQS7211A] = 0x54,
+                               [IQS7211E] = 0x39,
+                       },
+               },
+               .label = "threshold",
+       },
+       {
+               .name = "azoteq,debounce-exit",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x3F,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x40,
+                               [IQS7211A] = 0x56,
+                               [IQS7211E] = 0x3A,
+                       },
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .label = "debounce exit factor",
+       },
+       {
+               .name = "azoteq,debounce-enter",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x3F,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x40,
+                               [IQS7211A] = 0x56,
+                               [IQS7211E] = 0x3A,
+                       },
+               },
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "debounce entrance factor",
+       },
+       {
+               .name = "azoteq,conv-frac",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x48,
+                               [IQS7211A] = 0x58,
+                               [IQS7211E] = 0x3D,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x49,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x4A,
+                               [IQS7211A] = 0x59,
+                               [IQS7211E] = 0x3E,
+                       },
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .label = "conversion frequency fractional divider",
+       },
+       {
+               .name = "azoteq,conv-period",
+               .reg_addr = {
+                       [IQS7211_REG_GRP_TP] = {
+                               [IQS7210A] = 0x48,
+                               [IQS7211A] = 0x58,
+                               [IQS7211E] = 0x3D,
+                       },
+                       [IQS7211_REG_GRP_BTN] = {
+                               [IQS7210A] = 0x49,
+                       },
+                       [IQS7211_REG_GRP_ALP] = {
+                               [IQS7210A] = 0x4A,
+                               [IQS7211A] = 0x59,
+                               [IQS7211E] = 0x3E,
+                       },
+               },
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "conversion period",
+       },
+       {
+               .name = "azoteq,thresh",
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x55,
+                       [IQS7211A] = 0x67,
+                       [IQS7211E] = 0x48,
+               },
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "threshold",
+       },
+       {
+               .name = "azoteq,contact-split",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x55,
+                       [IQS7211A] = 0x67,
+                       [IQS7211E] = 0x48,
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .label = "contact split factor",
+       },
+       {
+               .name = "azoteq,trim-x",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x56,
+                       [IQS7211E] = 0x49,
+               },
+               .reg_shift = 0,
+               .reg_width = 8,
+               .label = "horizontal trim width",
+       },
+       {
+               .name = "azoteq,trim-x",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7211A] = 0x68,
+               },
+               .label = "horizontal trim width",
+       },
+       {
+               .name = "azoteq,trim-y",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7210A] = 0x56,
+                       [IQS7211E] = 0x49,
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .label = "vertical trim height",
+       },
+       {
+               .name = "azoteq,trim-y",
+               .reg_addr[IQS7211_REG_GRP_SYS] = {
+                       [IQS7211A] = 0x69,
+               },
+               .label = "vertical trim height",
+       },
+       {
+               .name = "azoteq,gesture-max-ms",
+               .reg_key = IQS7211_REG_KEY_TAP,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x59,
+                       [IQS7211A] = 0x81,
+                       [IQS7211E] = 0x4C,
+               },
+               .label = "maximum gesture time",
+       },
+       {
+               .name = "azoteq,gesture-mid-ms",
+               .reg_key = IQS7211_REG_KEY_TAP,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7211E] = 0x4D,
+               },
+               .label = "repeated gesture time",
+       },
+       {
+               .name = "azoteq,gesture-dist",
+               .reg_key = IQS7211_REG_KEY_TAP,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x5A,
+                       [IQS7211A] = 0x82,
+                       [IQS7211E] = 0x4E,
+               },
+               .label = "gesture distance",
+       },
+       {
+               .name = "azoteq,gesture-dist",
+               .reg_key = IQS7211_REG_KEY_HOLD,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x5A,
+                       [IQS7211A] = 0x82,
+                       [IQS7211E] = 0x4E,
+               },
+               .label = "gesture distance",
+       },
+       {
+               .name = "azoteq,gesture-min-ms",
+               .reg_key = IQS7211_REG_KEY_HOLD,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x5B,
+                       [IQS7211A] = 0x83,
+                       [IQS7211E] = 0x4F,
+               },
+               .label = "minimum gesture time",
+       },
+       {
+               .name = "azoteq,gesture-max-ms",
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x5C,
+                       [IQS7211A] = 0x84,
+                       [IQS7211E] = 0x50,
+               },
+               .label = "maximum gesture time",
+       },
+       {
+               .name = "azoteq,gesture-max-ms",
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x5C,
+                       [IQS7211A] = 0x84,
+                       [IQS7211E] = 0x50,
+               },
+               .label = "maximum gesture time",
+       },
+       {
+               .name = "azoteq,gesture-dist",
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x5D,
+                       [IQS7211A] = 0x85,
+                       [IQS7211E] = 0x51,
+               },
+               .label = "gesture distance",
+       },
+       {
+               .name = "azoteq,gesture-dist",
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7210A] = 0x5E,
+                       [IQS7211A] = 0x86,
+                       [IQS7211E] = 0x52,
+               },
+               .label = "gesture distance",
+       },
+       {
+               .name = "azoteq,gesture-dist-rep",
+               .reg_key = IQS7211_REG_KEY_AXIAL_X,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7211E] = 0x53,
+               },
+               .label = "repeated gesture distance",
+       },
+       {
+               .name = "azoteq,gesture-dist-rep",
+               .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7211E] = 0x54,
+               },
+               .label = "repeated gesture distance",
+       },
+       {
+               .name = "azoteq,thresh",
+               .reg_key = IQS7211_REG_KEY_PALM,
+               .reg_addr[IQS7211_REG_GRP_TP] = {
+                       [IQS7211E] = 0x55,
+               },
+               .reg_shift = 8,
+               .reg_width = 8,
+               .val_max = 42,
+               .label = "threshold",
+       },
+};
+
+static const u8 iqs7211_gesture_angle[] = {
+       0x00, 0x01, 0x02, 0x03,
+       0x04, 0x06, 0x07, 0x08,
+       0x09, 0x0A, 0x0B, 0x0C,
+       0x0E, 0x0F, 0x10, 0x11,
+       0x12, 0x14, 0x15, 0x16,
+       0x17, 0x19, 0x1A, 0x1B,
+       0x1C, 0x1E, 0x1F, 0x21,
+       0x22, 0x23, 0x25, 0x26,
+       0x28, 0x2A, 0x2B, 0x2D,
+       0x2E, 0x30, 0x32, 0x34,
+       0x36, 0x38, 0x3A, 0x3C,
+       0x3E, 0x40, 0x42, 0x45,
+       0x47, 0x4A, 0x4C, 0x4F,
+       0x52, 0x55, 0x58, 0x5B,
+       0x5F, 0x63, 0x66, 0x6B,
+       0x6F, 0x73, 0x78, 0x7E,
+       0x83, 0x89, 0x90, 0x97,
+       0x9E, 0xA7, 0xB0, 0xBA,
+       0xC5, 0xD1, 0xDF, 0xEF,
+};
+
+struct iqs7211_ver_info {
+       __le16 prod_num;
+       __le16 major;
+       __le16 minor;
+       __le32 patch;
+} __packed;
+
+struct iqs7211_touch_data {
+       __le16 abs_x;
+       __le16 abs_y;
+       __le16 pressure;
+       __le16 area;
+} __packed;
+
+struct iqs7211_tp_config {
+       u8 tp_settings;
+       u8 total_rx;
+       u8 total_tx;
+       u8 num_contacts;
+       __le16 max_x;
+       __le16 max_y;
+} __packed;
+
+struct iqs7211_private {
+       const struct iqs7211_dev_desc *dev_desc;
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *irq_gpio;
+       struct i2c_client *client;
+       struct input_dev *tp_idev;
+       struct input_dev *kp_idev;
+       struct iqs7211_ver_info ver_info;
+       struct iqs7211_tp_config tp_config;
+       struct touchscreen_properties prop;
+       struct list_head reg_field_head;
+       enum iqs7211_comms_mode comms_init;
+       enum iqs7211_comms_mode comms_mode;
+       unsigned int num_contacts;
+       unsigned int kp_code[ARRAY_SIZE(iqs7211e_kp_events)];
+       u8 rx_tx_map[IQS7211_MAX_CTX + 1];
+       u8 cycle_alloc[2][33];
+       u8 exp_file[2];
+       u16 event_mask;
+       u16 ati_start;
+       u16 gesture_cache;
+};
+
+static int iqs7211_irq_poll(struct iqs7211_private *iqs7211, u64 timeout_us)
+{
+       int error, val;
+
+       error = readx_poll_timeout(gpiod_get_value_cansleep, iqs7211->irq_gpio,
+                                  val, val, IQS7211_COMMS_SLEEP_US, timeout_us);
+
+       return val < 0 ? val : error;
+}
+
+static int iqs7211_hard_reset(struct iqs7211_private *iqs7211)
+{
+       if (!iqs7211->reset_gpio)
+               return 0;
+
+       gpiod_set_value_cansleep(iqs7211->reset_gpio, 1);
+
+       /*
+        * The following delay ensures the shared RDY/MCLR pin is sampled in
+        * between periodic assertions by the device and assumes the default
+        * communication timeout has not been overwritten in OTP memory.
+        */
+       if (iqs7211->reset_gpio == iqs7211->irq_gpio)
+               msleep(IQS7211_RESET_TIMEOUT_MS);
+       else
+               usleep_range(1000, 1100);
+
+       gpiod_set_value_cansleep(iqs7211->reset_gpio, 0);
+       if (iqs7211->reset_gpio == iqs7211->irq_gpio)
+               iqs7211_irq_wait();
+
+       return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US);
+}
+
+static int iqs7211_force_comms(struct iqs7211_private *iqs7211)
+{
+       u8 msg_buf[] = { 0xFF, };
+       int ret;
+
+       switch (iqs7211->comms_mode) {
+       case IQS7211_COMMS_MODE_WAIT:
+               return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US);
+
+       case IQS7211_COMMS_MODE_FREE:
+               return 0;
+
+       case IQS7211_COMMS_MODE_FORCE:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * The device cannot communicate until it asserts its interrupt (RDY)
+        * pin. Attempts to do so while RDY is deasserted return an ACK; how-
+        * ever all write data is ignored, and all read data returns 0xEE.
+        *
+        * Unsolicited communication must be preceded by a special force com-
+        * munication command, after which the device eventually asserts its
+        * RDY pin and agrees to communicate.
+        *
+        * Regardless of whether communication is forced or the result of an
+        * interrupt, the device automatically deasserts its RDY pin once it
+        * detects an I2C stop condition, or a timeout expires.
+        */
+       ret = gpiod_get_value_cansleep(iqs7211->irq_gpio);
+       if (ret < 0)
+               return ret;
+       else if (ret > 0)
+               return 0;
+
+       ret = i2c_master_send(iqs7211->client, msg_buf, sizeof(msg_buf));
+       if (ret < (int)sizeof(msg_buf)) {
+               if (ret >= 0)
+                       ret = -EIO;
+
+               msleep(IQS7211_COMMS_RETRY_MS);
+               return ret;
+       }
+
+       iqs7211_irq_wait();
+
+       return iqs7211_irq_poll(iqs7211, IQS7211_COMMS_TIMEOUT_US);
+}
+
+static int iqs7211_read_burst(struct iqs7211_private *iqs7211,
+                             u8 reg, void *val, u16 val_len)
+{
+       int ret, i;
+       struct i2c_client *client = iqs7211->client;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = sizeof(reg),
+                       .buf = &reg,
+               },
+               {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = val_len,
+                       .buf = (u8 *)val,
+               },
+       };
+
+       /*
+        * The following loop protects against an edge case in which the RDY
+        * pin is automatically deasserted just as the read is initiated. In
+        * that case, the read must be retried using forced communication.
+        */
+       for (i = 0; i < IQS7211_NUM_RETRIES; i++) {
+               ret = iqs7211_force_comms(iqs7211);
+               if (ret < 0)
+                       continue;
+
+               ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+               if (ret < (int)ARRAY_SIZE(msg)) {
+                       if (ret >= 0)
+                               ret = -EIO;
+
+                       msleep(IQS7211_COMMS_RETRY_MS);
+                       continue;
+               }
+
+               if (get_unaligned_le16(msg[1].buf) == IQS7211_COMMS_ERROR) {
+                       ret = -ENODATA;
+                       continue;
+               }
+
+               ret = 0;
+               break;
+       }
+
+       iqs7211_irq_wait();
+
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "Failed to read from address 0x%02X: %d\n", reg, ret);
+
+       return ret;
+}
+
+static int iqs7211_read_word(struct iqs7211_private *iqs7211, u8 reg, u16 *val)
+{
+       __le16 val_buf;
+       int error;
+
+       error = iqs7211_read_burst(iqs7211, reg, &val_buf, sizeof(val_buf));
+       if (error)
+               return error;
+
+       *val = le16_to_cpu(val_buf);
+
+       return 0;
+}
+
+static int iqs7211_write_burst(struct iqs7211_private *iqs7211,
+                              u8 reg, const void *val, u16 val_len)
+{
+       int msg_len = sizeof(reg) + val_len;
+       int ret, i;
+       struct i2c_client *client = iqs7211->client;
+       u8 *msg_buf;
+
+       msg_buf = kzalloc(msg_len, GFP_KERNEL);
+       if (!msg_buf)
+               return -ENOMEM;
+
+       *msg_buf = reg;
+       memcpy(msg_buf + sizeof(reg), val, val_len);
+
+       /*
+        * The following loop protects against an edge case in which the RDY
+        * pin is automatically asserted just before the force communication
+        * command is sent.
+        *
+        * In that case, the subsequent I2C stop condition tricks the device
+        * into preemptively deasserting the RDY pin and the command must be
+        * sent again.
+        */
+       for (i = 0; i < IQS7211_NUM_RETRIES; i++) {
+               ret = iqs7211_force_comms(iqs7211);
+               if (ret < 0)
+                       continue;
+
+               ret = i2c_master_send(client, msg_buf, msg_len);
+               if (ret < msg_len) {
+                       if (ret >= 0)
+                               ret = -EIO;
+
+                       msleep(IQS7211_COMMS_RETRY_MS);
+                       continue;
+               }
+
+               ret = 0;
+               break;
+       }
+
+       kfree(msg_buf);
+
+       iqs7211_irq_wait();
+
+       if (ret < 0)
+               dev_err(&client->dev,
+                       "Failed to write to address 0x%02X: %d\n", reg, ret);
+
+       return ret;
+}
+
+static int iqs7211_write_word(struct iqs7211_private *iqs7211, u8 reg, u16 val)
+{
+       __le16 val_buf = cpu_to_le16(val);
+
+       return iqs7211_write_burst(iqs7211, reg, &val_buf, sizeof(val_buf));
+}
+
+static int iqs7211_start_comms(struct iqs7211_private *iqs7211)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct i2c_client *client = iqs7211->client;
+       bool forced_comms;
+       unsigned int val;
+       u16 comms_setup;
+       int error;
+
+       /*
+        * Until forced communication can be enabled, the host must wait for a
+        * communication window each time it intends to elicit a response from
+        * the device.
+        *
+        * Forced communication is not necessary, however, if the host adapter
+        * can support clock stretching. In that case, the device freely clock
+        * stretches until all pending conversions are complete.
+        */
+       forced_comms = device_property_present(&client->dev,
+                                              "azoteq,forced-comms");
+
+       error = device_property_read_u32(&client->dev,
+                                        "azoteq,forced-comms-default", &val);
+       if (error == -EINVAL) {
+               iqs7211->comms_init = IQS7211_COMMS_MODE_WAIT;
+       } else if (error) {
+               dev_err(&client->dev,
+                       "Failed to read default communication mode: %d\n",
+                       error);
+               return error;
+       } else if (val) {
+               iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_FORCE
+                                                  : IQS7211_COMMS_MODE_WAIT;
+       } else {
+               iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_WAIT
+                                                  : IQS7211_COMMS_MODE_FREE;
+       }
+
+       iqs7211->comms_mode = iqs7211->comms_init;
+
+       error = iqs7211_hard_reset(iqs7211);
+       if (error) {
+               dev_err(&client->dev, "Failed to reset device: %d\n", error);
+               return error;
+       }
+
+       error = iqs7211_read_burst(iqs7211, IQS7211_PROD_NUM,
+                                  &iqs7211->ver_info,
+                                  sizeof(iqs7211->ver_info));
+       if (error)
+               return error;
+
+       if (le16_to_cpu(iqs7211->ver_info.prod_num) != dev_desc->prod_num) {
+               dev_err(&client->dev, "Invalid product number: %u\n",
+                       le16_to_cpu(iqs7211->ver_info.prod_num));
+               return -EINVAL;
+       }
+
+       error = iqs7211_read_word(iqs7211, dev_desc->sys_ctrl + 1,
+                                 &comms_setup);
+       if (error)
+               return error;
+
+       if (forced_comms)
+               comms_setup |= dev_desc->comms_req;
+       else
+               comms_setup &= ~dev_desc->comms_req;
+
+       error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
+                                  comms_setup | dev_desc->comms_end);
+       if (error)
+               return error;
+
+       if (forced_comms)
+               iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE;
+       else
+               iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE;
+
+       error = iqs7211_read_burst(iqs7211, dev_desc->exp_file,
+                                  iqs7211->exp_file,
+                                  sizeof(iqs7211->exp_file));
+       if (error)
+               return error;
+
+       error = iqs7211_read_burst(iqs7211, dev_desc->tp_config,
+                                  &iqs7211->tp_config,
+                                  sizeof(iqs7211->tp_config));
+       if (error)
+               return error;
+
+       error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
+                                  comms_setup);
+       if (error)
+               return error;
+
+       iqs7211->event_mask = comms_setup & ~IQS7211_EVENT_MASK_ALL;
+       iqs7211->event_mask |= (IQS7211_EVENT_MASK_ATI | IQS7211_EVENT_MODE);
+
+       return 0;
+}
+
+static int iqs7211_init_device(struct iqs7211_private *iqs7211)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct iqs7211_reg_field_desc *reg_field;
+       __le16 sys_ctrl[] = {
+               cpu_to_le16(dev_desc->ack_reset),
+               cpu_to_le16(iqs7211->event_mask),
+       };
+       int error, i;
+
+       /*
+        * Acknowledge reset before writing any registers in case the device
+        * suffers a spurious reset during initialization. The communication
+        * mode is configured at this time as well.
+        */
+       error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
+                                   sizeof(sys_ctrl));
+       if (error)
+               return error;
+
+       if (iqs7211->event_mask & dev_desc->comms_req)
+               iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE;
+       else
+               iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE;
+
+       /*
+        * Take advantage of the stop-bit disable function, if available, to
+        * save the trouble of having to reopen a communication window after
+        * each read or write.
+        */
+       error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
+                                  iqs7211->event_mask | dev_desc->comms_end);
+       if (error)
+               return error;
+
+       list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) {
+               u16 new_val = reg_field->val;
+
+               if (reg_field->mask < U16_MAX) {
+                       u16 old_val;
+
+                       error = iqs7211_read_word(iqs7211, reg_field->addr,
+                                                 &old_val);
+                       if (error)
+                               return error;
+
+                       new_val = old_val & ~reg_field->mask;
+                       new_val |= reg_field->val;
+
+                       if (new_val == old_val)
+                               continue;
+               }
+
+               error = iqs7211_write_word(iqs7211, reg_field->addr, new_val);
+               if (error)
+                       return error;
+       }
+
+       error = iqs7211_write_burst(iqs7211, dev_desc->tp_config,
+                                   &iqs7211->tp_config,
+                                   sizeof(iqs7211->tp_config));
+       if (error)
+               return error;
+
+       if (**iqs7211->cycle_alloc) {
+               error = iqs7211_write_burst(iqs7211, dev_desc->rx_tx_map,
+                                           &iqs7211->rx_tx_map,
+                                           dev_desc->num_ctx);
+               if (error)
+                       return error;
+
+               for (i = 0; i < sizeof(dev_desc->cycle_limit); i++) {
+                       error = iqs7211_write_burst(iqs7211,
+                                                   dev_desc->cycle_alloc[i],
+                                                   iqs7211->cycle_alloc[i],
+                                                   dev_desc->cycle_limit[i] * 3);
+                       if (error)
+                               return error;
+               }
+       }
+
+       *sys_ctrl = cpu_to_le16(iqs7211->ati_start);
+
+       return iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
+                                  sizeof(sys_ctrl));
+}
+
+static int iqs7211_add_field(struct iqs7211_private *iqs7211,
+                            struct iqs7211_reg_field_desc new_field)
+{
+       struct i2c_client *client = iqs7211->client;
+       struct iqs7211_reg_field_desc *reg_field;
+
+       if (!new_field.addr)
+               return 0;
+
+       list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) {
+               if (reg_field->addr != new_field.addr)
+                       continue;
+
+               reg_field->mask |= new_field.mask;
+               reg_field->val |= new_field.val;
+               return 0;
+       }
+
+       reg_field = devm_kzalloc(&client->dev, sizeof(*reg_field), GFP_KERNEL);
+       if (!reg_field)
+               return -ENOMEM;
+
+       reg_field->addr = new_field.addr;
+       reg_field->mask = new_field.mask;
+       reg_field->val = new_field.val;
+
+       list_add(&reg_field->list, &iqs7211->reg_field_head);
+
+       return 0;
+}
+
+static int iqs7211_parse_props(struct iqs7211_private *iqs7211,
+                              struct fwnode_handle *reg_grp_node,
+                              enum iqs7211_reg_grp_id reg_grp,
+                              enum iqs7211_reg_key_id reg_key)
+{
+       struct i2c_client *client = iqs7211->client;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(iqs7211_props); i++) {
+               const char *name = iqs7211_props[i].name;
+               u8 reg_addr = iqs7211_props[i].reg_addr[reg_grp]
+                                                      [iqs7211->dev_desc -
+                                                       iqs7211_devs];
+               int reg_shift = iqs7211_props[i].reg_shift;
+               int reg_width = iqs7211_props[i].reg_width ? : 16;
+               int val_pitch = iqs7211_props[i].val_pitch ? : 1;
+               int val_min = iqs7211_props[i].val_min;
+               int val_max = iqs7211_props[i].val_max;
+               const char *label = iqs7211_props[i].label ? : name;
+               struct iqs7211_reg_field_desc reg_field;
+               unsigned int val;
+               int error;
+
+               if (iqs7211_props[i].reg_key != reg_key)
+                       continue;
+
+               if (!reg_addr)
+                       continue;
+
+               error = fwnode_property_read_u32(reg_grp_node, name, &val);
+               if (error == -EINVAL) {
+                       continue;
+               } else if (error) {
+                       dev_err(&client->dev, "Failed to read %s %s: %d\n",
+                               fwnode_get_name(reg_grp_node), label, error);
+                       return error;
+               }
+
+               if (!val_max)
+                       val_max = GENMASK(reg_width - 1, 0) * val_pitch;
+
+               if (val < val_min || val > val_max) {
+                       dev_err(&client->dev, "Invalid %s: %u\n", label, val);
+                       return -EINVAL;
+               }
+
+               reg_field.addr = reg_addr;
+               reg_field.mask = GENMASK(reg_shift + reg_width - 1, reg_shift);
+               reg_field.val = val / val_pitch << reg_shift;
+
+               error = iqs7211_add_field(iqs7211, reg_field);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int iqs7211_parse_event(struct iqs7211_private *iqs7211,
+                              struct fwnode_handle *event_node,
+                              enum iqs7211_reg_grp_id reg_grp,
+                              enum iqs7211_reg_key_id reg_key,
+                              unsigned int *event_code)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct i2c_client *client = iqs7211->client;
+       struct iqs7211_reg_field_desc reg_field;
+       unsigned int val;
+       int error;
+
+       error = iqs7211_parse_props(iqs7211, event_node, reg_grp, reg_key);
+       if (error)
+               return error;
+
+       if (reg_key == IQS7211_REG_KEY_AXIAL_X ||
+           reg_key == IQS7211_REG_KEY_AXIAL_Y) {
+               error = fwnode_property_read_u32(event_node,
+                                                "azoteq,gesture-angle", &val);
+               if (!error) {
+                       if (val >= ARRAY_SIZE(iqs7211_gesture_angle)) {
+                               dev_err(&client->dev,
+                                       "Invalid %s gesture angle: %u\n",
+                                       fwnode_get_name(event_node), val);
+                               return -EINVAL;
+                       }
+
+                       reg_field.addr = dev_desc->gesture_angle;
+                       reg_field.mask = U8_MAX;
+                       reg_field.val = iqs7211_gesture_angle[val];
+
+                       error = iqs7211_add_field(iqs7211, reg_field);
+                       if (error)
+                               return error;
+               } else if (error != -EINVAL) {
+                       dev_err(&client->dev,
+                               "Failed to read %s gesture angle: %d\n",
+                               fwnode_get_name(event_node), error);
+                       return error;
+               }
+       }
+
+       error = fwnode_property_read_u32(event_node, "linux,code", event_code);
+       if (error == -EINVAL)
+               error = 0;
+       else if (error)
+               dev_err(&client->dev, "Failed to read %s code: %d\n",
+                       fwnode_get_name(event_node), error);
+
+       return error;
+}
+
+static int iqs7211_parse_cycles(struct iqs7211_private *iqs7211,
+                               struct fwnode_handle *tp_node)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct i2c_client *client = iqs7211->client;
+       int num_cycles = dev_desc->cycle_limit[0] + dev_desc->cycle_limit[1];
+       int error, count, i, j, k, cycle_start;
+       unsigned int cycle_alloc[IQS7211_MAX_CYCLES][2];
+       u8 total_rx = iqs7211->tp_config.total_rx;
+       u8 total_tx = iqs7211->tp_config.total_tx;
+
+       for (i = 0; i < IQS7211_MAX_CYCLES * 2; i++)
+               *(cycle_alloc[0] + i) = U8_MAX;
+
+       count = fwnode_property_count_u32(tp_node, "azoteq,channel-select");
+       if (count == -EINVAL) {
+               /*
+                * Assign each sensing cycle's slots (0 and 1) to a channel,
+                * defined as the intersection between two CRx and CTx pins.
+                * A channel assignment of 255 means the slot is unused.
+                */
+               for (i = 0, cycle_start = 0; i < total_tx; i++) {
+                       int cycle_stop = 0;
+
+                       for (j = 0; j < total_rx; j++) {
+                               /*
+                                * Channels formed by CRx0-3 and CRx4-7 are
+                                * bound to slots 0 and 1, respectively.
+                                */
+                               int slot = iqs7211->rx_tx_map[j] < 4 ? 0 : 1;
+                               int chan = i * total_rx + j;
+
+                               for (k = cycle_start; k < num_cycles; k++) {
+                                       if (cycle_alloc[k][slot] < U8_MAX)
+                                               continue;
+
+                                       cycle_alloc[k][slot] = chan;
+                                       break;
+                               }
+
+                               if (k < num_cycles) {
+                                       cycle_stop = max(k, cycle_stop);
+                                       continue;
+                               }
+
+                               dev_err(&client->dev,
+                                       "Insufficient number of cycles\n");
+                               return -EINVAL;
+                       }
+
+                       /*
+                        * Sensing cycles cannot straddle more than one CTx
+                        * pin. As such, the next row's starting cycle must
+                        * be greater than the previous row's highest cycle.
+                        */
+                       cycle_start = cycle_stop + 1;
+               }
+       } else if (count < 0) {
+               dev_err(&client->dev, "Failed to count channels: %d\n", count);
+               return count;
+       } else if (count > num_cycles * 2) {
+               dev_err(&client->dev, "Insufficient number of cycles\n");
+               return -EINVAL;
+       } else if (count > 0) {
+               error = fwnode_property_read_u32_array(tp_node,
+                                                      "azoteq,channel-select",
+                                                      cycle_alloc[0], count);
+               if (error) {
+                       dev_err(&client->dev, "Failed to read channels: %d\n",
+                               error);
+                       return error;
+               }
+
+               for (i = 0; i < count; i++) {
+                       int chan = *(cycle_alloc[0] + i);
+
+                       if (chan == U8_MAX)
+                               continue;
+
+                       if (chan >= total_rx * total_tx) {
+                               dev_err(&client->dev, "Invalid channel: %d\n",
+                                       chan);
+                               return -EINVAL;
+                       }
+
+                       for (j = 0; j < count; j++) {
+                               if (j == i || *(cycle_alloc[0] + j) != chan)
+                                       continue;
+
+                               dev_err(&client->dev, "Duplicate channel: %d\n",
+                                       chan);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       /*
+        * Once the raw channel assignments have been derived, they must be
+        * packed according to the device's register map.
+        */
+       for (i = 0, cycle_start = 0; i < sizeof(dev_desc->cycle_limit); i++) {
+               int offs = 0;
+
+               for (j = cycle_start;
+                    j < cycle_start + dev_desc->cycle_limit[i]; j++) {
+                       iqs7211->cycle_alloc[i][offs++] = 0x05;
+                       iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][0];
+                       iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][1];
+               }
+
+               cycle_start += dev_desc->cycle_limit[i];
+       }
+
+       return 0;
+}
+
+static int iqs7211_parse_tp(struct iqs7211_private *iqs7211,
+                           struct fwnode_handle *tp_node)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct i2c_client *client = iqs7211->client;
+       unsigned int pins[IQS7211_MAX_CTX];
+       int error, count, i, j;
+
+       count = fwnode_property_count_u32(tp_node, "azoteq,rx-enable");
+       if (count == -EINVAL) {
+               return 0;
+       } else if (count < 0) {
+               dev_err(&client->dev, "Failed to count CRx pins: %d\n", count);
+               return count;
+       } else if (count > IQS7211_NUM_CRX) {
+               dev_err(&client->dev, "Invalid number of CRx pins\n");
+               return -EINVAL;
+       }
+
+       error = fwnode_property_read_u32_array(tp_node, "azoteq,rx-enable",
+                                              pins, count);
+       if (error) {
+               dev_err(&client->dev, "Failed to read CRx pins: %d\n", error);
+               return error;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (pins[i] >= IQS7211_NUM_CRX) {
+                       dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]);
+                       return -EINVAL;
+               }
+
+               iqs7211->rx_tx_map[i] = pins[i];
+       }
+
+       iqs7211->tp_config.total_rx = count;
+
+       count = fwnode_property_count_u32(tp_node, "azoteq,tx-enable");
+       if (count < 0) {
+               dev_err(&client->dev, "Failed to count CTx pins: %d\n", count);
+               return count;
+       } else if (count > dev_desc->num_ctx) {
+               dev_err(&client->dev, "Invalid number of CTx pins\n");
+               return -EINVAL;
+       }
+
+       error = fwnode_property_read_u32_array(tp_node, "azoteq,tx-enable",
+                                              pins, count);
+       if (error) {
+               dev_err(&client->dev, "Failed to read CTx pins: %d\n", error);
+               return error;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (pins[i] >= dev_desc->num_ctx) {
+                       dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]);
+                       return -EINVAL;
+               }
+
+               for (j = 0; j < iqs7211->tp_config.total_rx; j++) {
+                       if (iqs7211->rx_tx_map[j] != pins[i])
+                               continue;
+
+                       dev_err(&client->dev, "Conflicting CTx pin: %u\n",
+                               pins[i]);
+                       return -EINVAL;
+               }
+
+               iqs7211->rx_tx_map[iqs7211->tp_config.total_rx + i] = pins[i];
+       }
+
+       iqs7211->tp_config.total_tx = count;
+
+       return iqs7211_parse_cycles(iqs7211, tp_node);
+}
+
+static int iqs7211_parse_alp(struct iqs7211_private *iqs7211,
+                            struct fwnode_handle *alp_node)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct i2c_client *client = iqs7211->client;
+       struct iqs7211_reg_field_desc reg_field;
+       int error, count, i;
+
+       count = fwnode_property_count_u32(alp_node, "azoteq,rx-enable");
+       if (count < 0 && count != -EINVAL) {
+               dev_err(&client->dev, "Failed to count CRx pins: %d\n", count);
+               return count;
+       } else if (count > IQS7211_NUM_CRX) {
+               dev_err(&client->dev, "Invalid number of CRx pins\n");
+               return -EINVAL;
+       } else if (count >= 0) {
+               unsigned int pins[IQS7211_NUM_CRX];
+
+               error = fwnode_property_read_u32_array(alp_node,
+                                                      "azoteq,rx-enable",
+                                                      pins, count);
+               if (error) {
+                       dev_err(&client->dev, "Failed to read CRx pins: %d\n",
+                               error);
+                       return error;
+               }
+
+               reg_field.addr = dev_desc->alp_config;
+               reg_field.mask = GENMASK(IQS7211_NUM_CRX - 1, 0);
+               reg_field.val = 0;
+
+               for (i = 0; i < count; i++) {
+                       if (pins[i] < dev_desc->min_crx_alp ||
+                           pins[i] >= IQS7211_NUM_CRX) {
+                               dev_err(&client->dev, "Invalid CRx pin: %u\n",
+                                       pins[i]);
+                               return -EINVAL;
+                       }
+
+                       reg_field.val |= BIT(pins[i]);
+               }
+
+               error = iqs7211_add_field(iqs7211, reg_field);
+               if (error)
+                       return error;
+       }
+
+       count = fwnode_property_count_u32(alp_node, "azoteq,tx-enable");
+       if (count < 0 && count != -EINVAL) {
+               dev_err(&client->dev, "Failed to count CTx pins: %d\n", count);
+               return count;
+       } else if (count > dev_desc->num_ctx) {
+               dev_err(&client->dev, "Invalid number of CTx pins\n");
+               return -EINVAL;
+       } else if (count >= 0) {
+               unsigned int pins[IQS7211_MAX_CTX];
+
+               error = fwnode_property_read_u32_array(alp_node,
+                                                      "azoteq,tx-enable",
+                                                      pins, count);
+               if (error) {
+                       dev_err(&client->dev, "Failed to read CTx pins: %d\n",
+                               error);
+                       return error;
+               }
+
+               reg_field.addr = dev_desc->alp_config + 1;
+               reg_field.mask = GENMASK(dev_desc->num_ctx - 1, 0);
+               reg_field.val = 0;
+
+               for (i = 0; i < count; i++) {
+                       if (pins[i] >= dev_desc->num_ctx) {
+                               dev_err(&client->dev, "Invalid CTx pin: %u\n",
+                                       pins[i]);
+                               return -EINVAL;
+                       }
+
+                       reg_field.val |= BIT(pins[i]);
+               }
+
+               error = iqs7211_add_field(iqs7211, reg_field);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int (*iqs7211_parse_extra[IQS7211_NUM_REG_GRPS])
+                               (struct iqs7211_private *iqs7211,
+                                struct fwnode_handle *reg_grp_node) = {
+       [IQS7211_REG_GRP_TP] = iqs7211_parse_tp,
+       [IQS7211_REG_GRP_ALP] = iqs7211_parse_alp,
+};
+
+static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211,
+                                struct fwnode_handle *reg_grp_node,
+                                enum iqs7211_reg_grp_id reg_grp)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct iqs7211_reg_field_desc reg_field;
+       int error, i;
+
+       error = iqs7211_parse_props(iqs7211, reg_grp_node, reg_grp,
+                                   IQS7211_REG_KEY_NONE);
+       if (error)
+               return error;
+
+       if (iqs7211_parse_extra[reg_grp]) {
+               error = iqs7211_parse_extra[reg_grp](iqs7211, reg_grp_node);
+               if (error)
+                       return error;
+       }
+
+       iqs7211->ati_start |= dev_desc->ati_start[reg_grp];
+
+       reg_field.addr = dev_desc->kp_enable[reg_grp];
+       reg_field.mask = 0;
+       reg_field.val = 0;
+
+       for (i = 0; i < dev_desc->num_kp_events; i++) {
+               const char *event_name = dev_desc->kp_events[i].name;
+               struct fwnode_handle *event_node;
+
+               if (dev_desc->kp_events[i].reg_grp != reg_grp)
+                       continue;
+
+               reg_field.mask |= dev_desc->kp_events[i].enable;
+
+               if (event_name)
+                       event_node = fwnode_get_named_child_node(reg_grp_node,
+                                                                event_name);
+               else
+                       event_node = fwnode_handle_get(reg_grp_node);
+
+               if (!event_node)
+                       continue;
+
+               error = iqs7211_parse_event(iqs7211, event_node,
+                                           dev_desc->kp_events[i].reg_grp,
+                                           dev_desc->kp_events[i].reg_key,
+                                           &iqs7211->kp_code[i]);
+               fwnode_handle_put(event_node);
+               if (error)
+                       return error;
+
+               reg_field.val |= dev_desc->kp_events[i].enable;
+
+               iqs7211->event_mask |= iqs7211_reg_grp_masks[reg_grp];
+       }
+
+       return iqs7211_add_field(iqs7211, reg_field);
+}
+
+static int iqs7211_register_kp(struct iqs7211_private *iqs7211)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct input_dev *kp_idev = iqs7211->kp_idev;
+       struct i2c_client *client = iqs7211->client;
+       int error, i;
+
+       for (i = 0; i < dev_desc->num_kp_events; i++)
+               if (iqs7211->kp_code[i])
+                       break;
+
+       if (i == dev_desc->num_kp_events)
+               return 0;
+
+       kp_idev = devm_input_allocate_device(&client->dev);
+       if (!kp_idev)
+               return -ENOMEM;
+
+       iqs7211->kp_idev = kp_idev;
+
+       kp_idev->name = dev_desc->kp_name;
+       kp_idev->id.bustype = BUS_I2C;
+
+       for (i = 0; i < dev_desc->num_kp_events; i++)
+               if (iqs7211->kp_code[i])
+                       input_set_capability(iqs7211->kp_idev, EV_KEY,
+                                            iqs7211->kp_code[i]);
+
+       error = input_register_device(kp_idev);
+       if (error)
+               dev_err(&client->dev, "Failed to register %s: %d\n",
+                       kp_idev->name, error);
+
+       return error;
+}
+
+static int iqs7211_register_tp(struct iqs7211_private *iqs7211)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct touchscreen_properties *prop = &iqs7211->prop;
+       struct input_dev *tp_idev = iqs7211->tp_idev;
+       struct i2c_client *client = iqs7211->client;
+       int error;
+
+       error = device_property_read_u32(&client->dev, "azoteq,num-contacts",
+                                        &iqs7211->num_contacts);
+       if (error == -EINVAL) {
+               return 0;
+       } else if (error) {
+               dev_err(&client->dev, "Failed to read number of contacts: %d\n",
+                       error);
+               return error;
+       } else if (iqs7211->num_contacts > IQS7211_MAX_CONTACTS) {
+               dev_err(&client->dev, "Invalid number of contacts: %u\n",
+                       iqs7211->num_contacts);
+               return -EINVAL;
+       }
+
+       iqs7211->tp_config.num_contacts = iqs7211->num_contacts ? : 1;
+
+       if (!iqs7211->num_contacts)
+               return 0;
+
+       iqs7211->event_mask |= IQS7211_EVENT_MASK_MOVE;
+
+       tp_idev = devm_input_allocate_device(&client->dev);
+       if (!tp_idev)
+               return -ENOMEM;
+
+       iqs7211->tp_idev = tp_idev;
+
+       tp_idev->name = dev_desc->tp_name;
+       tp_idev->id.bustype = BUS_I2C;
+
+       input_set_abs_params(tp_idev, ABS_MT_POSITION_X,
+                            0, le16_to_cpu(iqs7211->tp_config.max_x), 0, 0);
+
+       input_set_abs_params(tp_idev, ABS_MT_POSITION_Y,
+                            0, le16_to_cpu(iqs7211->tp_config.max_y), 0, 0);
+
+       input_set_abs_params(tp_idev, ABS_MT_PRESSURE, 0, U16_MAX, 0, 0);
+
+       touchscreen_parse_properties(tp_idev, true, prop);
+
+       /*
+        * The device reserves 0xFFFF for coordinates that correspond to slots
+        * which are not in a state of touch.
+        */
+       if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) {
+               dev_err(&client->dev, "Invalid trackpad size: %u*%u\n",
+                       prop->max_x, prop->max_y);
+               return -EINVAL;
+       }
+
+       iqs7211->tp_config.max_x = cpu_to_le16(prop->max_x);
+       iqs7211->tp_config.max_y = cpu_to_le16(prop->max_y);
+
+       error = input_mt_init_slots(tp_idev, iqs7211->num_contacts,
+                                   INPUT_MT_DIRECT);
+       if (error) {
+               dev_err(&client->dev, "Failed to initialize slots: %d\n",
+                       error);
+               return error;
+       }
+
+       error = input_register_device(tp_idev);
+       if (error)
+               dev_err(&client->dev, "Failed to register %s: %d\n",
+                       tp_idev->name, error);
+
+       return error;
+}
+
+static int iqs7211_report(struct iqs7211_private *iqs7211)
+{
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       struct i2c_client *client = iqs7211->client;
+       struct iqs7211_touch_data *touch_data;
+       u16 info_flags, charge_mode, gesture_flags;
+       __le16 status[12];
+       int error, i;
+
+       error = iqs7211_read_burst(iqs7211, dev_desc->sys_stat, status,
+                                  dev_desc->contact_offs * sizeof(__le16) +
+                                  iqs7211->num_contacts * sizeof(*touch_data));
+       if (error)
+               return error;
+
+       info_flags = le16_to_cpu(status[dev_desc->info_offs]);
+
+       if (info_flags & dev_desc->show_reset) {
+               dev_err(&client->dev, "Unexpected device reset\n");
+
+               /*
+                * The device may or may not expect forced communication after
+                * it exits hardware reset, so the corresponding state machine
+                * must be reset as well.
+                */
+               iqs7211->comms_mode = iqs7211->comms_init;
+
+               return iqs7211_init_device(iqs7211);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(dev_desc->ati_error); i++) {
+               if (!(info_flags & dev_desc->ati_error[i]))
+                       continue;
+
+               dev_err(&client->dev, "Unexpected %s ATI error\n",
+                       iqs7211_reg_grp_names[i]);
+               return 0;
+       }
+
+       for (i = 0; i < iqs7211->num_contacts; i++) {
+               u16 pressure;
+
+               touch_data = (struct iqs7211_touch_data *)
+                            &status[dev_desc->contact_offs] + i;
+               pressure = le16_to_cpu(touch_data->pressure);
+
+               input_mt_slot(iqs7211->tp_idev, i);
+               if (input_mt_report_slot_state(iqs7211->tp_idev, MT_TOOL_FINGER,
+                                              pressure != 0)) {
+                       touchscreen_report_pos(iqs7211->tp_idev, &iqs7211->prop,
+                                              le16_to_cpu(touch_data->abs_x),
+                                              le16_to_cpu(touch_data->abs_y),
+                                              true);
+                       input_report_abs(iqs7211->tp_idev, ABS_MT_PRESSURE,
+                                        pressure);
+               }
+       }
+
+       if (iqs7211->num_contacts) {
+               input_mt_sync_frame(iqs7211->tp_idev);
+               input_sync(iqs7211->tp_idev);
+       }
+
+       if (!iqs7211->kp_idev)
+               return 0;
+
+       charge_mode = info_flags & GENMASK(dev_desc->charge_shift + 2,
+                                          dev_desc->charge_shift);
+       charge_mode >>= dev_desc->charge_shift;
+
+       /*
+        * A charging mode higher than 2 (idle mode) indicates the device last
+        * operated in low-power mode and intends to express an ALP event.
+        */
+       if (info_flags & dev_desc->kp_events->mask && charge_mode > 2) {
+               input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 1);
+               input_sync(iqs7211->kp_idev);
+
+               input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 0);
+       }
+
+       for (i = 0; i < dev_desc->num_kp_events; i++) {
+               if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_BTN)
+                       continue;
+
+               input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i],
+                                info_flags & dev_desc->kp_events[i].mask);
+       }
+
+       gesture_flags = le16_to_cpu(status[dev_desc->gesture_offs]);
+
+       for (i = 0; i < dev_desc->num_kp_events; i++) {
+               enum iqs7211_reg_key_id reg_key = dev_desc->kp_events[i].reg_key;
+               u16 mask = dev_desc->kp_events[i].mask;
+
+               if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_TP)
+                       continue;
+
+               if ((gesture_flags ^ iqs7211->gesture_cache) & mask)
+                       input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i],
+                                        gesture_flags & mask);
+
+               iqs7211->gesture_cache &= ~mask;
+
+               /*
+                * Hold and palm gestures persist while the contact remains in
+                * place; all others are momentary and hence are followed by a
+                * complementary release event.
+                */
+               if (reg_key == IQS7211_REG_KEY_HOLD ||
+                   reg_key == IQS7211_REG_KEY_PALM) {
+                       iqs7211->gesture_cache |= gesture_flags & mask;
+                       gesture_flags &= ~mask;
+               }
+       }
+
+       if (gesture_flags) {
+               input_sync(iqs7211->kp_idev);
+
+               for (i = 0; i < dev_desc->num_kp_events; i++)
+                       if (dev_desc->kp_events[i].reg_grp == IQS7211_REG_GRP_TP &&
+                           gesture_flags & dev_desc->kp_events[i].mask)
+                               input_report_key(iqs7211->kp_idev,
+                                                iqs7211->kp_code[i], 0);
+       }
+
+       input_sync(iqs7211->kp_idev);
+
+       return 0;
+}
+
+static irqreturn_t iqs7211_irq(int irq, void *context)
+{
+       struct iqs7211_private *iqs7211 = context;
+
+       return iqs7211_report(iqs7211) ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static int iqs7211_suspend(struct device *dev)
+{
+       struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       int error;
+
+       if (!dev_desc->suspend || device_may_wakeup(dev))
+               return 0;
+
+       /*
+        * I2C communication prompts the device to assert its RDY pin if it is
+        * not already asserted. As such, the interrupt must be disabled so as
+        * to prevent reentrant interrupts.
+        */
+       disable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+       error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl,
+                                  dev_desc->suspend);
+
+       enable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+       return error;
+}
+
+static int iqs7211_resume(struct device *dev)
+{
+       struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
+       const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+       __le16 sys_ctrl[] = {
+               0,
+               cpu_to_le16(iqs7211->event_mask),
+       };
+       int error;
+
+       if (!dev_desc->suspend || device_may_wakeup(dev))
+               return 0;
+
+       disable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+       /*
+        * Forced communication, if in use, must be explicitly enabled as part
+        * of the wake-up command.
+        */
+       error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
+                                   sizeof(sys_ctrl));
+
+       enable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+       return error;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs7211_pm, iqs7211_suspend, iqs7211_resume);
+
+static ssize_t fw_info_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n",
+                        le16_to_cpu(iqs7211->ver_info.prod_num),
+                        le32_to_cpu(iqs7211->ver_info.patch),
+                        le16_to_cpu(iqs7211->ver_info.major),
+                        le16_to_cpu(iqs7211->ver_info.minor),
+                        iqs7211->exp_file[1], iqs7211->exp_file[0]);
+}
+
+static DEVICE_ATTR_RO(fw_info);
+
+static struct attribute *iqs7211_attrs[] = {
+       &dev_attr_fw_info.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(iqs7211);
+
+static const struct of_device_id iqs7211_of_match[] = {
+       {
+               .compatible = "azoteq,iqs7210a",
+               .data = &iqs7211_devs[IQS7210A],
+       },
+       {
+               .compatible = "azoteq,iqs7211a",
+               .data = &iqs7211_devs[IQS7211A],
+       },
+       {
+               .compatible = "azoteq,iqs7211e",
+               .data = &iqs7211_devs[IQS7211E],
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, iqs7211_of_match);
+
+static int iqs7211_probe(struct i2c_client *client)
+{
+       struct iqs7211_private *iqs7211;
+       enum iqs7211_reg_grp_id reg_grp;
+       unsigned long irq_flags;
+       bool shared_irq;
+       int error, irq;
+
+       iqs7211 = devm_kzalloc(&client->dev, sizeof(*iqs7211), GFP_KERNEL);
+       if (!iqs7211)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, iqs7211);
+       iqs7211->client = client;
+
+       INIT_LIST_HEAD(&iqs7211->reg_field_head);
+
+       iqs7211->dev_desc = device_get_match_data(&client->dev);
+       if (!iqs7211->dev_desc)
+               return -ENODEV;
+
+       shared_irq = iqs7211->dev_desc->num_ctx == IQS7211_MAX_CTX;
+
+       /*
+        * The RDY pin behaves as an interrupt, but must also be polled ahead
+        * of unsolicited I2C communication. As such, it is first opened as a
+        * GPIO and then passed to gpiod_to_irq() to register the interrupt.
+        *
+        * If an extra CTx pin is present, the RDY and MCLR pins are combined
+        * into a single bidirectional pin. In that case, the platform's GPIO
+        * must be configured as an open-drain output.
+        */
+       iqs7211->irq_gpio = devm_gpiod_get(&client->dev, "irq",
+                                          shared_irq ? GPIOD_OUT_LOW
+                                                     : GPIOD_IN);
+       if (IS_ERR(iqs7211->irq_gpio)) {
+               error = PTR_ERR(iqs7211->irq_gpio);
+               dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
+                       error);
+               return error;
+       }
+
+       if (shared_irq) {
+               iqs7211->reset_gpio = iqs7211->irq_gpio;
+       } else {
+               iqs7211->reset_gpio = devm_gpiod_get_optional(&client->dev,
+                                                             "reset",
+                                                             GPIOD_OUT_HIGH);
+               if (IS_ERR(iqs7211->reset_gpio)) {
+                       error = PTR_ERR(iqs7211->reset_gpio);
+                       dev_err(&client->dev,
+                               "Failed to request reset GPIO: %d\n", error);
+                       return error;
+               }
+       }
+
+       error = iqs7211_start_comms(iqs7211);
+       if (error)
+               return error;
+
+       for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) {
+               const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp];
+               struct fwnode_handle *reg_grp_node;
+
+               if (reg_grp_name)
+                       reg_grp_node = device_get_named_child_node(&client->dev,
+                                                                  reg_grp_name);
+               else
+                       reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
+
+               if (!reg_grp_node)
+                       continue;
+
+               error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp);
+               fwnode_handle_put(reg_grp_node);
+               if (error)
+                       return error;
+       }
+
+       error = iqs7211_register_kp(iqs7211);
+       if (error)
+               return error;
+
+       error = iqs7211_register_tp(iqs7211);
+       if (error)
+               return error;
+
+       error = iqs7211_init_device(iqs7211);
+       if (error)
+               return error;
+
+       irq = gpiod_to_irq(iqs7211->irq_gpio);
+       if (irq < 0)
+               return irq;
+
+       irq_flags = gpiod_is_active_low(iqs7211->irq_gpio) ? IRQF_TRIGGER_LOW
+                                                          : IRQF_TRIGGER_HIGH;
+       irq_flags |= IRQF_ONESHOT;
+
+       error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7211_irq,
+                                         irq_flags, client->name, iqs7211);
+       if (error)
+               dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+
+       return error;
+}
+
+static struct i2c_driver iqs7211_i2c_driver = {
+       .probe = iqs7211_probe,
+       .driver = {
+               .name = "iqs7211",
+               .of_match_table = iqs7211_of_match,
+               .dev_groups = iqs7211_groups,
+               .pm = pm_sleep_ptr(&iqs7211_pm),
+       },
+};
+module_i2c_driver(iqs7211_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller");
+MODULE_LICENSE("GPL");
index 15b5cb7..9bad8b9 100644 (file)
@@ -198,54 +198,36 @@ static void lpc32xx_ts_close(struct input_dev *dev)
 
 static int lpc32xx_ts_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct lpc32xx_tsc *tsc;
        struct input_dev *input;
-       struct resource *res;
-       resource_size_t size;
        int irq;
        int error;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Can't get memory resource\n");
-               return -ENOENT;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
 
-       tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
-       input = input_allocate_device();
-       if (!tsc || !input) {
-               dev_err(&pdev->dev, "failed allocating memory\n");
-               error = -ENOMEM;
-               goto err_free_mem;
-       }
+       tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
+       if (!tsc)
+               return -ENOMEM;
 
-       tsc->dev = input;
        tsc->irq = irq;
 
-       size = resource_size(res);
-
-       if (!request_mem_region(res->start, size, pdev->name)) {
-               dev_err(&pdev->dev, "TSC registers are not free\n");
-               error = -EBUSY;
-               goto err_free_mem;
-       }
+       tsc->tsc_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(tsc->tsc_base))
+               return PTR_ERR(tsc->tsc_base);
 
-       tsc->tsc_base = ioremap(res->start, size);
-       if (!tsc->tsc_base) {
-               dev_err(&pdev->dev, "Can't map memory\n");
-               error = -ENOMEM;
-               goto err_release_mem;
-       }
-
-       tsc->clk = clk_get(&pdev->dev, NULL);
+       tsc->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(tsc->clk)) {
                dev_err(&pdev->dev, "failed getting clock\n");
-               error = PTR_ERR(tsc->clk);
-               goto err_unmap;
+               return PTR_ERR(tsc->clk);
+       }
+
+       input = devm_input_allocate_device(dev);
+       if (!input) {
+               dev_err(&pdev->dev, "failed allocating input device\n");
+               return -ENOMEM;
        }
 
        input->name = MOD_NAME;
@@ -254,68 +236,33 @@ static int lpc32xx_ts_probe(struct platform_device *pdev)
        input->id.vendor = 0x0001;
        input->id.product = 0x0002;
        input->id.version = 0x0100;
-       input->dev.parent = &pdev->dev;
        input->open = lpc32xx_ts_open;
        input->close = lpc32xx_ts_close;
 
-       input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-       input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_set_capability(input, EV_KEY, BTN_TOUCH);
        input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
                             LPC32XX_TSC_MAX_XY_VAL, 0, 0);
        input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
                             LPC32XX_TSC_MAX_XY_VAL, 0, 0);
 
        input_set_drvdata(input, tsc);
+       tsc->dev = input;
 
-       error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
-                           0, pdev->name, tsc);
+       error = devm_request_irq(dev, tsc->irq, lpc32xx_ts_interrupt,
+                                0, pdev->name, tsc);
        if (error) {
                dev_err(&pdev->dev, "failed requesting interrupt\n");
-               goto err_put_clock;
+               return error;
        }
 
        error = input_register_device(input);
        if (error) {
                dev_err(&pdev->dev, "failed registering input device\n");
-               goto err_free_irq;
+               return error;
        }
 
        platform_set_drvdata(pdev, tsc);
-       device_init_wakeup(&pdev->dev, 1);
-
-       return 0;
-
-err_free_irq:
-       free_irq(tsc->irq, tsc);
-err_put_clock:
-       clk_put(tsc->clk);
-err_unmap:
-       iounmap(tsc->tsc_base);
-err_release_mem:
-       release_mem_region(res->start, size);
-err_free_mem:
-       input_free_device(input);
-       kfree(tsc);
-
-       return error;
-}
-
-static int lpc32xx_ts_remove(struct platform_device *pdev)
-{
-       struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
-       struct resource *res;
-
-       free_irq(tsc->irq, tsc);
-
-       input_unregister_device(tsc->dev);
-
-       clk_put(tsc->clk);
-
-       iounmap(tsc->tsc_base);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       kfree(tsc);
+       device_init_wakeup(&pdev->dev, true);
 
        return 0;
 }
@@ -384,7 +331,6 @@ MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
 
 static struct platform_driver lpc32xx_ts_driver = {
        .probe          = lpc32xx_ts_probe,
-       .remove         = lpc32xx_ts_remove,
        .driver         = {
                .name   = MOD_NAME,
                .pm     = LPC32XX_TS_PM_OPS,
index 461023f..8be6dad 100644 (file)
@@ -230,7 +230,7 @@ static struct i2c_driver max11801_ts_driver = {
                .of_match_table = max11801_ts_dt_ids,
        },
        .id_table       = max11801_ts_id,
-       .probe_new      = max11801_ts_probe,
+       .probe          = max11801_ts_probe,
 };
 
 module_i2c_driver(max11801_ts_driver);
index 704e360..ac28019 100644 (file)
@@ -272,7 +272,7 @@ static const struct i2c_device_id mcs5000_ts_id[] = {
 MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
 
 static struct i2c_driver mcs5000_ts_driver = {
-       .probe_new      = mcs5000_ts_probe,
+       .probe          = mcs5000_ts_probe,
        .driver = {
                .name = "mcs5000_ts",
                .pm   = pm_sleep_ptr(&mcs5000_ts_pm),
index 89b6020..2ac4483 100644 (file)
@@ -1451,13 +1451,8 @@ static int mip4_probe(struct i2c_client *client)
 
        ts->gpio_ce = devm_gpiod_get_optional(&client->dev,
                                              "ce", GPIOD_OUT_LOW);
-       if (IS_ERR(ts->gpio_ce)) {
-               error = PTR_ERR(ts->gpio_ce);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "Failed to get gpio: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(ts->gpio_ce))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->gpio_ce), "Failed to get gpio\n");
 
        error = mip4_power_on(ts);
        if (error)
@@ -1591,7 +1586,7 @@ MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids);
 
 static struct i2c_driver mip4_driver = {
        .id_table = mip4_i2c_ids,
-       .probe_new = mip4_probe,
+       .probe = mip4_probe,
        .driver = {
                .name = MIP4_DEVICE_NAME,
                .of_match_table = of_match_ptr(mip4_of_match),
index 69fcc88..2384ea6 100644 (file)
@@ -221,7 +221,7 @@ static struct i2c_driver migor_ts_driver = {
                .name = "migor_ts",
                .pm = pm_sleep_ptr(&migor_ts_pm),
        },
-       .probe_new = migor_ts_probe,
+       .probe = migor_ts_probe,
        .remove = migor_ts_remove,
        .id_table = migor_ts_id,
 };
index 4dbca1a..ac12494 100644 (file)
@@ -638,7 +638,7 @@ static struct i2c_driver mms114_driver = {
                .pm     = pm_sleep_ptr(&mms114_pm_ops),
                .of_match_table = of_match_ptr(mms114_dt_match),
        },
-       .probe_new      = mms114_probe,
+       .probe          = mms114_probe,
        .id_table       = mms114_id,
 };
 
index b23db68..a38af3f 100644 (file)
@@ -492,7 +492,7 @@ static const struct of_device_id msg2638_of_match[] = {
 MODULE_DEVICE_TABLE(of, msg2638_of_match);
 
 static struct i2c_driver msg2638_ts_driver = {
-       .probe_new = msg2638_ts_probe,
+       .probe = msg2638_ts_probe,
        .driver = {
                .name = "MStar-TS",
                .pm = pm_sleep_ptr(&msg2638_pm_ops),
index 3e551f9..1a797e4 100644 (file)
@@ -1,9 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Driver for Novatek i2c touchscreen controller as found on
- * the Acer Iconia One 7 B1-750 tablet. The Touchscreen controller
- * model-number is unknown. Android calls this a "NVT-ts" touchscreen,
- * but that may apply to other Novatek controller models too.
+ * Driver for Novatek NT11205 i2c touchscreen controller as found
+ * on the Acer Iconia One 7 B1-750 tablet.
  *
  * Copyright (c) 2023 Hans de Goede <hdegoede@redhat.com>
  */
@@ -272,7 +270,7 @@ static int nvt_ts_probe(struct i2c_client *client)
 
        error = input_register_device(input);
        if (error) {
-               dev_err(dev, "failed to request irq: %d\n", error);
+               dev_err(dev, "failed to register input device: %d\n", error);
                return error;
        }
 
@@ -290,12 +288,12 @@ static struct i2c_driver nvt_ts_driver = {
                .name   = "novatek-nvt-ts",
                .pm     = pm_sleep_ptr(&nvt_ts_pm_ops),
        },
-       .probe_new = nvt_ts_probe,
+       .probe = nvt_ts_probe,
        .id_table = nvt_ts_i2c_id,
 };
 
 module_i2c_driver(nvt_ts_driver);
 
-MODULE_DESCRIPTION("Novatek NVT-ts touchscreen driver");
+MODULE_DESCRIPTION("Novatek NT11205 touchscreen driver");
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_LICENSE("GPL");
index f09f483..0b45760 100644 (file)
@@ -515,41 +515,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client)
        input_set_drvdata(input, tsdata);
 
        tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN);
-       if (IS_ERR(tsdata->gpio_attb)) {
-               error = PTR_ERR(tsdata->gpio_attb);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to request ATTB gpio: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(tsdata->gpio_attb))
+               return dev_err_probe(dev, PTR_ERR(tsdata->gpio_attb),
+                                    "Failed to request ATTB gpio\n");
 
        tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset",
                                                     GPIOD_OUT_LOW);
-       if (IS_ERR(tsdata->gpio_reset)) {
-               error = PTR_ERR(tsdata->gpio_reset);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to request RESET gpio: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(tsdata->gpio_reset))
+               return dev_err_probe(dev, PTR_ERR(tsdata->gpio_reset),
+                                    "Failed to request RESET gpio\n");
 
        tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake",
                                                    GPIOD_OUT_HIGH);
-       if (IS_ERR(tsdata->gpio_wake)) {
-               error = PTR_ERR(tsdata->gpio_wake);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get wake gpio: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(tsdata->gpio_wake))
+               return dev_err_probe(dev, PTR_ERR(tsdata->gpio_wake),
+                                    "Failed to get wake gpio\n");
 
        tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable",
                                                      GPIOD_OUT_HIGH);
-       if (IS_ERR(tsdata->gpio_enable)) {
-               error = PTR_ERR(tsdata->gpio_enable);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "Failed to get enable gpio: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(tsdata->gpio_enable))
+               return dev_err_probe(dev, PTR_ERR(tsdata->gpio_enable),
+                                    "Failed to get enable gpio\n");
 
        if (tsdata->gpio_enable)
                msleep(100);
@@ -617,7 +603,7 @@ static struct i2c_driver pixcir_i2c_ts_driver = {
                .pm     = pm_sleep_ptr(&pixcir_dev_pm_ops),
                .of_match_table = of_match_ptr(pixcir_of_match),
        },
-       .probe_new      = pixcir_i2c_ts_probe,
+       .probe          = pixcir_i2c_ts_probe,
        .id_table       = pixcir_i2c_ts_id,
 };
 
index 49a06d3..78dd305 100644 (file)
@@ -1087,32 +1087,20 @@ static int raydium_i2c_probe(struct i2c_client *client)
        i2c_set_clientdata(client, ts);
 
        ts->avdd = devm_regulator_get(&client->dev, "avdd");
-       if (IS_ERR(ts->avdd)) {
-               error = PTR_ERR(ts->avdd);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "Failed to get 'avdd' regulator: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(ts->avdd))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->avdd),
+                                    "Failed to get 'avdd' regulator\n");
 
        ts->vccio = devm_regulator_get(&client->dev, "vccio");
-       if (IS_ERR(ts->vccio)) {
-               error = PTR_ERR(ts->vccio);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "Failed to get 'vccio' regulator: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(ts->vccio))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->vccio),
+                                    "Failed to get 'vccio' regulator\n");
 
        ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
                                                 GPIOD_OUT_LOW);
-       if (IS_ERR(ts->reset_gpio)) {
-               error = PTR_ERR(ts->reset_gpio);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "failed to get reset gpio: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(ts->reset_gpio))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio),
+                                    "Failed to get reset gpio\n");
 
        error = raydium_i2c_power_on(ts);
        if (error)
@@ -1273,7 +1261,7 @@ MODULE_DEVICE_TABLE(of, raydium_of_match);
 #endif
 
 static struct i2c_driver raydium_i2c_driver = {
-       .probe_new = raydium_i2c_probe,
+       .probe = raydium_i2c_probe,
        .id_table = raydium_i2c_id,
        .driver = {
                .name = "raydium_ts",
index 6f754a8..7e761ec 100644 (file)
@@ -210,12 +210,8 @@ static int grts_probe(struct platform_device *pdev)
 
        /* get the channels from IIO device */
        st->iio_chans = devm_iio_channel_get_all(dev);
-       if (IS_ERR(st->iio_chans)) {
-               error = PTR_ERR(st->iio_chans);
-               if (error != -EPROBE_DEFER)
-                       dev_err(dev, "can't get iio channels.\n");
-               return error;
-       }
+       if (IS_ERR(st->iio_chans))
+               return dev_err_probe(dev, PTR_ERR(st->iio_chans), "can't get iio channels\n");
 
        if (!device_property_present(dev, "io-channel-names"))
                return -ENODEV;
index 833422e..240424f 100644 (file)
@@ -1183,7 +1183,7 @@ static struct i2c_driver rohm_bu21023_i2c_driver = {
        .driver = {
                .name = BU21023_NAME,
        },
-       .probe_new = rohm_bu21023_i2c_probe,
+       .probe = rohm_bu21023_i2c_probe,
        .id_table = rohm_bu21023_i2c_id,
 };
 module_i2c_driver(rohm_bu21023_i2c_driver);
index 371cf48..998d99d 100644 (file)
@@ -538,7 +538,7 @@ static struct i2c_driver s6sy761_driver = {
                .of_match_table = of_match_ptr(s6sy761_of_match),
                .pm = pm_ptr(&s6sy761_pm_ops),
        },
-       .probe_new = s6sy761_probe,
+       .probe = s6sy761_probe,
        .remove = s6sy761_remove,
        .id_table = s6sy761_id,
 };
index a37fac0..62f562a 100644 (file)
@@ -706,11 +706,9 @@ static int silead_ts_probe(struct i2c_client *client)
 
        /* Power GPIO pin */
        data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
-       if (IS_ERR(data->gpio_power)) {
-               if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER)
-                       dev_err(dev, "Shutdown GPIO request failed\n");
-               return PTR_ERR(data->gpio_power);
-       }
+       if (IS_ERR(data->gpio_power))
+               return dev_err_probe(dev, PTR_ERR(data->gpio_power),
+                                    "Shutdown GPIO request failed\n");
 
        error = silead_ts_setup(client);
        if (error)
@@ -826,7 +824,7 @@ MODULE_DEVICE_TABLE(of, silead_ts_of_match);
 #endif
 
 static struct i2c_driver silead_ts_driver = {
-       .probe_new = silead_ts_probe,
+       .probe = silead_ts_probe,
        .id_table = silead_ts_id,
        .driver = {
                .name = SILEAD_TS_NAME,
index 5a493b1..ed56cb5 100644 (file)
@@ -310,23 +310,15 @@ static int sis_ts_probe(struct i2c_client *client)
 
        ts->attn_gpio = devm_gpiod_get_optional(&client->dev,
                                                "attn", GPIOD_IN);
-       if (IS_ERR(ts->attn_gpio)) {
-               error = PTR_ERR(ts->attn_gpio);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "Failed to get attention GPIO: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(ts->attn_gpio))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->attn_gpio),
+                                    "Failed to get attention GPIO\n");
 
        ts->reset_gpio = devm_gpiod_get_optional(&client->dev,
                                                 "reset", GPIOD_OUT_LOW);
-       if (IS_ERR(ts->reset_gpio)) {
-               error = PTR_ERR(ts->reset_gpio);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev,
-                               "Failed to get reset GPIO: %d\n", error);
-               return error;
-       }
+       if (IS_ERR(ts->reset_gpio))
+               return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio),
+                                    "Failed to get reset GPIO\n");
 
        sis_ts_reset(ts);
 
@@ -393,7 +385,7 @@ static struct i2c_driver sis_ts_driver = {
                .name   = SIS_I2C_NAME,
                .of_match_table = of_match_ptr(sis_ts_dt_ids),
        },
-       .probe_new      = sis_ts_probe,
+       .probe          = sis_ts_probe,
        .id_table       = sis_ts_id,
 };
 module_i2c_driver(sis_ts_driver);
index f49566d..6475084 100644 (file)
@@ -384,7 +384,7 @@ static const struct of_device_id st1232_ts_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
 
 static struct i2c_driver st1232_ts_driver = {
-       .probe_new      = st1232_ts_probe,
+       .probe          = st1232_ts_probe,
        .id_table       = st1232_ts_id,
        .driver = {
                .name   = ST1232_TS_NAME,
index fdbf5e6..56e371f 100644 (file)
@@ -808,7 +808,7 @@ static struct i2c_driver stmfts_driver = {
                .pm = pm_ptr(&stmfts_pm_ops),
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
-       .probe_new = stmfts_probe,
+       .probe = stmfts_probe,
        .remove = stmfts_remove,
        .id_table = stmfts_id,
 };
index 31d1402..7efbcd0 100644 (file)
@@ -221,7 +221,6 @@ static void surface3_spi_power(struct surface3_ts_data *data, bool on)
  */
 static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
 {
-       int error;
        struct device *dev;
        struct gpio_desc *gpiod;
        int i;
@@ -231,15 +230,9 @@ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
        /* Get the reset lines GPIO pin number */
        for (i = 0; i < 2; i++) {
                gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
-               if (IS_ERR(gpiod)) {
-                       error = PTR_ERR(gpiod);
-                       if (error != -EPROBE_DEFER)
-                               dev_err(dev,
-                                       "Failed to get power GPIO %d: %d\n",
-                                       i,
-                                       error);
-                       return error;
-               }
+               if (IS_ERR(gpiod))
+                       return dev_err_probe(dev, PTR_ERR(gpiod),
+                                            "Failed to get power GPIO %d\n", i);
 
                data->gpiod_rst[i] = gpiod;
        }
index 52ae730..f5c5881 100644 (file)
@@ -323,13 +323,9 @@ static int sx8654_probe(struct i2c_client *client)
 
        sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
                                                     GPIOD_OUT_HIGH);
-       if (IS_ERR(sx8654->gpio_reset)) {
-               error = PTR_ERR(sx8654->gpio_reset);
-               if (error != -EPROBE_DEFER)
-                       dev_err(&client->dev, "unable to get reset-gpio: %d\n",
-                               error);
-               return error;
-       }
+       if (IS_ERR(sx8654->gpio_reset))
+               return dev_err_probe(&client->dev, PTR_ERR(sx8654->gpio_reset),
+                                    "unable to get reset-gpio\n");
        dev_dbg(&client->dev, "got GPIO reset pin\n");
 
        sx8654->data = device_get_match_data(&client->dev);
@@ -470,7 +466,7 @@ static struct i2c_driver sx8654_driver = {
                .of_match_table = of_match_ptr(sx8654_of_match),
        },
        .id_table = sx8654_id_table,
-       .probe_new = sx8654_probe,
+       .probe = sx8654_probe,
 };
 module_i2c_driver(sx8654_driver);
 
index 45f39eb..b5e904c 100644 (file)
@@ -68,7 +68,7 @@ static struct i2c_driver tsc2004_driver = {
                .pm     = pm_sleep_ptr(&tsc200x_pm_ops),
        },
        .id_table       = tsc2004_idtable,
-       .probe_new      = tsc2004_probe,
+       .probe          = tsc2004_probe,
        .remove         = tsc2004_remove,
 };
 module_i2c_driver(tsc2004_driver);
index 21916a3..b365525 100644 (file)
@@ -418,7 +418,7 @@ static struct i2c_driver tsc2007_driver = {
                .of_match_table = tsc2007_of_match,
        },
        .id_table       = tsc2007_idtable,
-       .probe_new      = tsc2007_probe,
+       .probe          = tsc2007_probe,
 };
 
 module_i2c_driver(tsc2007_driver);
index a145b91..f389f9c 100644 (file)
@@ -264,7 +264,7 @@ static struct i2c_driver wacom_i2c_driver = {
                .pm     = pm_sleep_ptr(&wacom_i2c_pm),
        },
 
-       .probe_new      = wacom_i2c_probe,
+       .probe          = wacom_i2c_probe,
        .id_table       = wacom_i2c_id,
 };
 module_i2c_driver(wacom_i2c_driver);
index 771962a..cbc4750 100644 (file)
@@ -1169,7 +1169,7 @@ static const struct acpi_device_id wdt87xx_acpi_id[] = {
 MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
 
 static struct i2c_driver wdt87xx_driver = {
-       .probe_new      = wdt87xx_ts_probe,
+       .probe          = wdt87xx_ts_probe,
        .id_table       = wdt87xx_dev_id,
        .driver = {
                .name   = WDT87XX_NAME,
index bfa0c63..1a03447 100644 (file)
@@ -248,7 +248,7 @@ static struct i2c_driver zet6223_driver = {
                .name = "zet6223",
                .of_match_table = zet6223_of_match,
        },
-       .probe_new = zet6223_probe,
+       .probe = zet6223_probe,
        .id_table = zet6223_id
 };
 module_i2c_driver(zet6223_driver);
index 76b1942..5be5112 100644 (file)
@@ -944,7 +944,7 @@ static struct i2c_driver zforce_driver = {
                .pm     = pm_sleep_ptr(&zforce_pm_ops),
                .of_match_table = of_match_ptr(zforce_dt_idtable),
        },
-       .probe_new      = zforce_probe,
+       .probe          = zforce_probe,
        .id_table       = zforce_idtable,
 };
 
index b6ece47..1b4807b 100644 (file)
@@ -617,7 +617,7 @@ MODULE_DEVICE_TABLE(of, zinitix_of_match);
 #endif
 
 static struct i2c_driver zinitix_ts_driver = {
-       .probe_new = zinitix_ts_probe,
+       .probe = zinitix_ts_probe,
        .driver = {
                .name = "Zinitix-TS",
                .pm = pm_sleep_ptr(&zinitix_pm_ops),
index 8c2f000..07e3701 100644 (file)
@@ -5,7 +5,6 @@
 #ifndef _GAMEPORT_H
 #define _GAMEPORT_H
 
-#include <asm/io.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -64,7 +63,7 @@ struct gameport_driver {
 int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode);
 void gameport_close(struct gameport *gameport);
 
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
 
 void __gameport_register_port(struct gameport *gameport, struct module *owner);
 /* use a define to avoid include chaining to get THIS_MODULE */
@@ -165,18 +164,12 @@ void gameport_unregister_driver(struct gameport_driver *drv);
 
 static inline void gameport_trigger(struct gameport *gameport)
 {
-       if (gameport->trigger)
-               gameport->trigger(gameport);
-       else
-               outb(0xff, gameport->io);
+       gameport->trigger(gameport);
 }
 
 static inline unsigned char gameport_read(struct gameport *gameport)
 {
-       if (gameport->read)
-               return gameport->read(gameport);
-       else
-               return inb(gameport->io);
+       return gameport->read(gameport);
 }
 
 static inline int gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
index 0261e2f..95b07f8 100644 (file)
@@ -3,6 +3,7 @@
 #define _LINUX_I8042_H
 
 
+#include <linux/errno.h>
 #include <linux/types.h>
 
 /*
index 53f7e4d..9ca9ce4 100644 (file)
@@ -8,44 +8,59 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 #include <linux/wait.h>
 
-#define PS2_CMD_SETSCALE11     0x00e6
-#define PS2_CMD_SETRES         0x10e8
-#define PS2_CMD_GETID          0x02f2
-#define PS2_CMD_RESET_BAT      0x02ff
+struct ps2dev;
 
-#define PS2_RET_BAT            0xaa
-#define PS2_RET_ID             0x00
-#define PS2_RET_ACK            0xfa
-#define PS2_RET_NAK            0xfe
-#define PS2_RET_ERR            0xfc
+/**
+ * enum ps2_disposition - indicates how received byte should be handled
+ * @PS2_PROCESS: pass to the main protocol handler, process normally
+ * @PS2_IGNORE: skip the byte
+ * @PS2_ERROR: do not process the byte, abort command in progress
+ */
+enum ps2_disposition {
+       PS2_PROCESS,
+       PS2_IGNORE,
+       PS2_ERROR,
+};
 
-#define PS2_FLAG_ACK           BIT(0)  /* Waiting for ACK/NAK */
-#define PS2_FLAG_CMD           BIT(1)  /* Waiting for a command to finish */
-#define PS2_FLAG_CMD1          BIT(2)  /* Waiting for the first byte of command response */
-#define PS2_FLAG_WAITID                BIT(3)  /* Command executing is GET ID */
-#define PS2_FLAG_NAK           BIT(4)  /* Last transmission was NAKed */
-#define PS2_FLAG_ACK_CMD       BIT(5)  /* Waiting to ACK the command (first) byte */
+typedef enum ps2_disposition (*ps2_pre_receive_handler_t)(struct ps2dev *, u8,
+                                                         unsigned int);
+typedef void (*ps2_receive_handler_t)(struct ps2dev *, u8);
 
+/**
+ * struct ps2dev - represents a device using PS/2 protocol
+ * @serio: a serio port used by the PS/2 device
+ * @cmd_mutex: a mutex ensuring that only one command is executing at a time
+ * @wait: a waitqueue used to signal completion from the serio interrupt handler
+ * @flags: various internal flags indicating stages of PS/2 command execution
+ * @cmdbuf: buffer holding command response
+ * @cmdcnt: outstanding number of bytes of the command response
+ * @nak: a byte transmitted by the device when it refuses command
+ * @pre_receive_handler: checks communication errors and returns disposition
+ * (&enum ps2_disposition) of the received data byte
+ * @receive_handler: main handler of particular PS/2 protocol, such as keyboard
+ *   or mouse protocol
+ */
 struct ps2dev {
        struct serio *serio;
-
-       /* Ensures that only one command is executing at a time */
        struct mutex cmd_mutex;
-
-       /* Used to signal completion from interrupt handler */
        wait_queue_head_t wait;
-
        unsigned long flags;
        u8 cmdbuf[8];
        u8 cmdcnt;
        u8 nak;
+
+       ps2_pre_receive_handler_t pre_receive_handler;
+       ps2_receive_handler_t receive_handler;
 };
 
-void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio,
+             ps2_pre_receive_handler_t pre_receive_handler,
+             ps2_receive_handler_t receive_handler);
 int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout);
 void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout);
 void ps2_begin_command(struct ps2dev *ps2dev);
@@ -53,9 +68,8 @@ void ps2_end_command(struct ps2dev *ps2dev);
 int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
 int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
 int ps2_sliced_command(struct ps2dev *ps2dev, u8 command);
-bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data);
-bool ps2_handle_response(struct ps2dev *ps2dev, u8 data);
-void ps2_cmd_aborted(struct ps2dev *ps2dev);
 bool ps2_is_keyboard_id(u8 id);
 
+irqreturn_t ps2_interrupt(struct serio *serio, u8 data, unsigned int flags);
+
 #endif /* _LIBPS2_H */