Merge tag 'v6.5' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 5 Sep 2023 21:08:14 +0000 (14:08 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Tue, 5 Sep 2023 21:08:14 +0000 (14:08 -0700)
Sync up with mainline to bring in updates to the shared infrastructure.

78 files changed:
Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml
Documentation/devicetree/bindings/input/touchscreen/azoteq,iqs7211.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.yaml
Documentation/devicetree/bindings/input/touchscreen/eeti,exc3000.yaml
Documentation/devicetree/bindings/input/touchscreen/melfas,mms114.yaml
drivers/input/gameport/Kconfig
drivers/input/gameport/gameport.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/amikbd.c
drivers/input/keyboard/bcm-keypad.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/mcs_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/qt1070.c
drivers/input/keyboard/qt2160.c
drivers/input/keyboard/sun4i-lradc-keys.c
drivers/input/keyboard/tca6416-keypad.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/keyboard/tm2-touchkey.c
drivers/input/misc/Kconfig
drivers/input/misc/da9063_onkey.c
drivers/input/misc/gpio-vibra.c
drivers/input/misc/iqs269a.c
drivers/input/misc/iqs626a.c
drivers/input/misc/iqs7222.c
drivers/input/misc/mma8450.c
drivers/input/misc/pm8941-pwrkey.c
drivers/input/misc/pm8xxx-vibrator.c
drivers/input/misc/pmic8xxx-pwrkey.c
drivers/input/misc/pwm-beeper.c
drivers/input/misc/pwm-vibra.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/sparcspkr.c
drivers/input/mouse/elan_i2c_core.c
drivers/input/mouse/psmouse-smbus.c
drivers/input/serio/apbps2.c
drivers/input/serio/i8042-sparcio.h
drivers/input/serio/rpckbd.c
drivers/input/serio/xilinx_ps2.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/bu21029_ts.c
drivers/input/touchscreen/chipone_icn8318.c
drivers/input/touchscreen/cy8ctma140.c
drivers/input/touchscreen/cyttsp5.c
drivers/input/touchscreen/edt-ft5x06.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/ili210x.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/melfas_mip4.c
drivers/input/touchscreen/mms114.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/silead.c
drivers/input/touchscreen/sis_i2c.c
drivers/input/touchscreen/surface3_spi.c
drivers/input/touchscreen/sx8654.c
drivers/input/touchscreen/ti_am335x_tsc.c
include/linux/gameport.h
include/linux/tca6416_keypad.h

index 9ddba7f2e7aa619758c1eb0483cc284ebfd4e096..5b1769c19b1735e3bd70db002581e0693498ec07 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/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 ef4c841387bdd480c856eb729812b7b0372df27b..f2808cb4d99dfdab68755d3211b3e84b38f3b087 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 007adbc89c143c6fb124fb04c934383b9a1a475a..9dc25d30a0a8911d853ea6747a034ef6326345e9 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 fdd02898e2492543bcf3233c31f5feba558843a5..07f9dd6b1c9c44af761bb0cd4de9f3f201f940e0 100644 (file)
@@ -52,6 +52,11 @@ properties:
   touchscreen-swapped-x-y: true
   touchscreen-max-pressure: true
 
+  linux,keycodes:
+    description: Keycodes for the touch keys
+    minItems: 1
+    maxItems: 15
+
 additionalProperties: false
 
 required:
index 5a2c2fb3217d55ee75f069106fa50789af4a1604..fe73b26e647a17a422edb7b22fee9a786ee5b9fa 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 a1443320b419554a6199589e27ff634a28c15e05..34f416a3ebcb7c8af4cf0252e3235f41a97e7892 100644 (file)
@@ -519,12 +519,32 @@ 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;
 }
 
 /*
@@ -545,11 +565,7 @@ static void gameport_init_port(struct gameport *gameport)
        if (gameport->parent)
                gameport->dev.parent = &gameport->parent->dev;
 
-       if (!gameport->trigger)
-               gameport->trigger = gameport_default_trigger;
-       if (!gameport->read)
-               gameport->read = gameport_default_read;
-
+       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 cdb193317c3b6825af9b4f84317b4af52fa6684a..ede380551e55ca9f5fe1f9dab02fe9b50c2403e6 100644 (file)
@@ -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 }
@@ -499,6 +501,8 @@ static const struct usb_device_id xpad_table[] = {
        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 */
        { }
 };
 
@@ -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;
 }
index 896a5a989ddcecca26dd5348d1742269e32b6b9b..61e8e43e9c2bbd423445a4bff2ce7f15f6070366 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;
 
index a20a4e186639c05bf11004269a40a12b46263b63..e305c44cd0aa9045f4c62f2d3a42db05552ef224 100644 (file)
@@ -196,7 +196,7 @@ static int __init amikbd_probe(struct platform_device *pdev)
        struct input_dev *dev;
        int i, err;
 
-       dev = input_allocate_device();
+       dev = devm_input_allocate_device(&pdev->dev);
        if (!dev) {
                dev_err(&pdev->dev, "Not enough memory for input device\n");
                return -ENOMEM;
@@ -208,7 +208,6 @@ static int __init amikbd_probe(struct platform_device *pdev)
        dev->id.vendor = 0x0001;
        dev->id.product = 0x0001;
        dev->id.version = 0x0100;
-       dev->dev.parent = &pdev->dev;
 
        dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
 
@@ -218,35 +217,21 @@ static int __init amikbd_probe(struct platform_device *pdev)
        amikbd_init_console_keymaps();
 
        ciaa.cra &= ~0x41;       /* serial data in, turn off TA */
-       err = request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
-                         dev);
+       err = devm_request_irq(&pdev->dev, IRQ_AMIGA_CIAA_SP, amikbd_interrupt,
+                              0, "amikbd", dev);
        if (err)
-               goto fail2;
+               return err;
 
        err = input_register_device(dev);
        if (err)
-               goto fail3;
+               return err;
 
        platform_set_drvdata(pdev, dev);
 
        return 0;
-
- fail3:        free_irq(IRQ_AMIGA_CIAA_SP, dev);
- fail2:        input_free_device(dev);
-       return err;
-}
-
-static int __exit amikbd_remove(struct platform_device *pdev)
-{
-       struct input_dev *dev = platform_get_drvdata(pdev);
-
-       free_irq(IRQ_AMIGA_CIAA_SP, dev);
-       input_unregister_device(dev);
-       return 0;
 }
 
 static struct platform_driver amikbd_driver = {
-       .remove = __exit_p(amikbd_remove),
        .driver   = {
                .name   = "amiga-keyboard",
        },
index 56a919ec23b529149adfec91c268075fd53e0380..f3c3746acd4cf96a0ecdc905550bafb608cda4d9 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 c928829a8b0cea53b35899f2e6f99dec9b7773f7..2e7c2c046e675f8ae21a6fe668e9b7dfa23c1a9a 100644 (file)
@@ -523,18 +523,15 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                                                     NULL, GPIOD_IN, desc);
                if (IS_ERR(bdata->gpiod)) {
                        error = PTR_ERR(bdata->gpiod);
-                       if (error == -ENOENT) {
-                               /*
-                                * GPIO is optional, we may be dealing with
-                                * purely interrupt-driven setup.
-                                */
-                               bdata->gpiod = NULL;
-                       } else {
-                               if (error != -EPROBE_DEFER)
-                                       dev_err(dev, "failed to get gpio: %d\n",
-                                               error);
-                               return error;
-                       }
+                       if (error != -ENOENT)
+                               return dev_err_probe(dev, error,
+                                                    "failed to get gpio\n");
+
+                       /*
+                        * GPIO is optional, we may be dealing with
+                        * purely interrupt-driven setup.
+                        */
+                       bdata->gpiod = NULL;
                }
        } else if (gpio_is_valid(button->gpio)) {
                /*
index c3937d2fc7446e8b68e517cb4e5491809407fb06..ba00ecfbd343bc796fd48f77db92659a1c36bccc 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 3964f6e0f6afad9b59147a95035ea850ed760e5b..7bee93e9b0f5e8cfb78049916f8883ef7f399f10 100644 (file)
@@ -556,6 +556,7 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
                    const char *name)
 {
        struct lm8323_pwm *pwm;
+       int err;
 
        BUG_ON(id > 3);
 
@@ -575,9 +576,11 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
                pwm->cdev.name = name;
                pwm->cdev.brightness_set = lm8323_pwm_set_brightness;
                pwm->cdev.groups = lm8323_pwm_groups;
-               if (led_classdev_register(dev, &pwm->cdev) < 0) {
-                       dev_err(dev, "couldn't register PWM %d\n", id);
-                       return -1;
+
+               err = devm_led_classdev_register(dev, &pwm->cdev);
+               if (err) {
+                       dev_err(dev, "couldn't register PWM %d: %d\n", id, err);
+                       return err;
                }
                pwm->enabled = true;
        }
@@ -585,8 +588,6 @@ static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
        return 0;
 }
 
-static struct i2c_driver lm8323_i2c_driver;
-
 static ssize_t lm8323_show_disable(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
@@ -615,6 +616,12 @@ static ssize_t lm8323_set_disable(struct device *dev,
 }
 static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable);
 
+static struct attribute *lm8323_attrs[] = {
+       &dev_attr_disable_kp.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(lm8323);
+
 static int lm8323_probe(struct i2c_client *client)
 {
        struct lm8323_platform_data *pdata = dev_get_platdata(&client->dev);
@@ -642,12 +649,13 @@ static int lm8323_probe(struct i2c_client *client)
                return -EINVAL;
        }
 
-       lm = kzalloc(sizeof *lm, GFP_KERNEL);
-       idev = input_allocate_device();
-       if (!lm || !idev) {
-               err = -ENOMEM;
-               goto fail1;
-       }
+       lm = devm_kzalloc(&client->dev, sizeof(*lm), GFP_KERNEL);
+       if (!lm)
+               return -ENOMEM;
+
+       idev = devm_input_allocate_device(&client->dev);
+       if (!idev)
+               return -ENOMEM;
 
        lm->client = client;
        lm->idev = idev;
@@ -663,8 +671,10 @@ static int lm8323_probe(struct i2c_client *client)
 
        lm8323_reset(lm);
 
-       /* Nothing's set up to service the IRQ yet, so just spin for max.
-        * 100ms until we can configure. */
+       /*
+        * Nothing's set up to service the IRQ yet, so just spin for max.
+        * 100ms until we can configure.
+        */
        tmo = jiffies + msecs_to_jiffies(100);
        while (lm8323_read(lm, LM8323_CMD_READ_INT, data, 1) == 1) {
                if (data[0] & INT_NOINIT)
@@ -684,21 +694,17 @@ static int lm8323_probe(struct i2c_client *client)
        /* If a true probe check the device */
        if (lm8323_read_id(lm, data) != 0) {
                dev_err(&client->dev, "device not found\n");
-               err = -ENODEV;
-               goto fail1;
+               return -ENODEV;
        }
 
        for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) {
                err = init_pwm(lm, pwm + 1, &client->dev,
                               pdata->pwm_names[pwm]);
-               if (err < 0)
-                       goto fail2;
+               if (err)
+                       return err;
        }
 
        lm->kp_enabled = true;
-       err = device_create_file(&client->dev, &dev_attr_disable_kp);
-       if (err < 0)
-               goto fail2;
 
        idev->name = pdata->name ? : "LM8323 keypad";
        snprintf(lm->phys, sizeof(lm->phys),
@@ -719,14 +725,16 @@ static int lm8323_probe(struct i2c_client *client)
        err = input_register_device(idev);
        if (err) {
                dev_dbg(&client->dev, "error registering input device\n");
-               goto fail3;
+               return err;
        }
 
-       err = request_threaded_irq(client->irq, NULL, lm8323_irq,
-                         IRQF_TRIGGER_LOW|IRQF_ONESHOT, "lm8323", lm);
+       err = devm_request_threaded_irq(&client->dev, client->irq,
+                                       NULL, lm8323_irq,
+                                       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                       "lm8323", lm);
        if (err) {
                dev_err(&client->dev, "could not get IRQ %d\n", client->irq);
-               goto fail4;
+               return err;
        }
 
        i2c_set_clientdata(client, lm);
@@ -735,39 +743,6 @@ static int lm8323_probe(struct i2c_client *client)
        enable_irq_wake(client->irq);
 
        return 0;
-
-fail4:
-       input_unregister_device(idev);
-       idev = NULL;
-fail3:
-       device_remove_file(&client->dev, &dev_attr_disable_kp);
-fail2:
-       while (--pwm >= 0)
-               if (lm->pwm[pwm].enabled)
-                       led_classdev_unregister(&lm->pwm[pwm].cdev);
-fail1:
-       input_free_device(idev);
-       kfree(lm);
-       return err;
-}
-
-static void lm8323_remove(struct i2c_client *client)
-{
-       struct lm8323_chip *lm = i2c_get_clientdata(client);
-       int i;
-
-       disable_irq_wake(client->irq);
-       free_irq(client->irq, lm);
-
-       input_unregister_device(lm->idev);
-
-       device_remove_file(&lm->client->dev, &dev_attr_disable_kp);
-
-       for (i = 0; i < 3; i++)
-               if (lm->pwm[i].enabled)
-                       led_classdev_unregister(&lm->pwm[i].cdev);
-
-       kfree(lm);
 }
 
 /*
@@ -823,11 +798,11 @@ static const struct i2c_device_id lm8323_id[] = {
 
 static struct i2c_driver lm8323_i2c_driver = {
        .driver = {
-               .name   = "lm8323",
-               .pm     = pm_sleep_ptr(&lm8323_pm_ops),
+               .name           = "lm8323",
+               .pm             = pm_sleep_ptr(&lm8323_pm_ops),
+               .dev_groups     = lm8323_groups,
        },
        .probe          = lm8323_probe,
-       .remove         = lm8323_remove,
        .id_table       = lm8323_id,
 };
 MODULE_DEVICE_TABLE(i2c, lm8323_id);
index c9f05764e36df1049331fec9903639235085afb2..1c070c499c85ae9521a65c54869a318026b7db67 100644 (file)
@@ -142,18 +142,18 @@ static int lm8333_probe(struct i2c_client *client)
                return -EINVAL;
        }
 
-       lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL);
-       input = input_allocate_device();
-       if (!lm8333 || !input) {
-               err = -ENOMEM;
-               goto free_mem;
-       }
+       lm8333 = devm_kzalloc(&client->dev, sizeof(*lm8333), GFP_KERNEL);
+       if (!lm8333)
+               return -ENOMEM;
+
+       input = devm_input_allocate_device(&client->dev);
+       if (!input)
+               return -ENOMEM;
 
        lm8333->client = client;
        lm8333->input = input;
 
        input->name = client->name;
-       input->dev.parent = &client->dev;
        input->id.bustype = BUS_I2C;
 
        input_set_capability(input, EV_MSC, MSC_SCAN);
@@ -162,7 +162,7 @@ static int lm8333_probe(struct i2c_client *client)
                                         LM8333_NUM_ROWS, LM8333_NUM_COLS,
                                         lm8333->keycodes, input);
        if (err)
-               goto free_mem;
+               return err;
 
        if (pdata->debounce_time) {
                err = lm8333_write8(lm8333, LM8333_DEBOUNCE,
@@ -178,34 +178,19 @@ static int lm8333_probe(struct i2c_client *client)
                        dev_warn(&client->dev, "Unable to set active time\n");
        }
 
-       err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
-                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                  "lm8333", lm8333);
+       err = devm_request_threaded_irq(&client->dev, client->irq,
+                                       NULL, lm8333_irq_thread,
+                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                       "lm8333", lm8333);
        if (err)
-               goto free_mem;
+               return err;
 
        err = input_register_device(input);
        if (err)
-               goto free_irq;
+               return err;
 
        i2c_set_clientdata(client, lm8333);
        return 0;
-
- free_irq:
-       free_irq(client->irq, lm8333);
- free_mem:
-       input_free_device(input);
-       kfree(lm8333);
-       return err;
-}
-
-static void lm8333_remove(struct i2c_client *client)
-{
-       struct lm8333 *lm8333 = i2c_get_clientdata(client);
-
-       free_irq(client->irq, lm8333);
-       input_unregister_device(lm8333->input);
-       kfree(lm8333);
 }
 
 static const struct i2c_device_id lm8333_id[] = {
@@ -219,7 +204,6 @@ static struct i2c_driver lm8333_driver = {
                .name           = "lm8333",
        },
        .probe          = lm8333_probe,
-       .remove         = lm8333_remove,
        .id_table       = lm8333_id,
 };
 module_i2c_driver(lm8333_driver);
index 911e1181cd6fb7f55cfba8b51b91a983bec5904d..322a878071591dc11a470f9afc4b38f8c9cc3cde 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 de312d8eb974d543b44eb1a18ce60e908182c590..2410f676c7f95e9074afb7252cd86af6350a3259 100644 (file)
@@ -92,6 +92,13 @@ static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static void mcs_touchkey_poweroff(void *data)
+{
+       struct mcs_touchkey_data *touchkey = data;
+
+       touchkey->poweron(false);
+}
+
 static int mcs_touchkey_probe(struct i2c_client *client)
 {
        const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -109,13 +116,16 @@ static int mcs_touchkey_probe(struct i2c_client *client)
                return -EINVAL;
        }
 
-       data = kzalloc(struct_size(data, keycodes, pdata->key_maxval + 1),
-                      GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!data || !input_dev) {
-               dev_err(&client->dev, "Failed to allocate memory\n");
-               error = -ENOMEM;
-               goto err_free_mem;
+       data = devm_kzalloc(&client->dev,
+                           struct_size(data, keycodes, pdata->key_maxval + 1),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       input_dev = devm_input_allocate_device(&client->dev);
+       if (!input_dev) {
+               dev_err(&client->dev, "Failed to allocate input device\n");
+               return -ENOMEM;
        }
 
        data->client = client;
@@ -136,15 +146,13 @@ static int mcs_touchkey_probe(struct i2c_client *client)
 
        fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
        if (fw_ver < 0) {
-               error = fw_ver;
-               dev_err(&client->dev, "i2c read error[%d]\n", error);
-               goto err_free_mem;
+               dev_err(&client->dev, "i2c read error[%d]\n", fw_ver);
+               return fw_ver;
        }
        dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
 
        input_dev->name = "MELFAS MCS Touchkey";
        input_dev->id.bustype = BUS_I2C;
-       input_dev->dev.parent = &client->dev;
        input_dev->evbit[0] = BIT_MASK(EV_KEY);
        if (!pdata->no_autorepeat)
                input_dev->evbit[0] |= BIT_MASK(EV_REP);
@@ -169,40 +177,28 @@ static int mcs_touchkey_probe(struct i2c_client *client)
        if (pdata->poweron) {
                data->poweron = pdata->poweron;
                data->poweron(true);
+
+               error = devm_add_action_or_reset(&client->dev,
+                                                mcs_touchkey_poweroff, data);
+               if (error)
+                       return error;
        }
 
-       error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
-                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                    client->dev.driver->name, data);
+       error = devm_request_threaded_irq(&client->dev, client->irq,
+                                         NULL, mcs_touchkey_interrupt,
+                                         IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                         client->dev.driver->name, data);
        if (error) {
                dev_err(&client->dev, "Failed to register interrupt\n");
-               goto err_free_mem;
+               return error;
        }
 
        error = input_register_device(input_dev);
        if (error)
-               goto err_free_irq;
+               return error;
 
        i2c_set_clientdata(client, data);
        return 0;
-
-err_free_irq:
-       free_irq(client->irq, data);
-err_free_mem:
-       input_free_device(input_dev);
-       kfree(data);
-       return error;
-}
-
-static void mcs_touchkey_remove(struct i2c_client *client)
-{
-       struct mcs_touchkey_data *data = i2c_get_clientdata(client);
-
-       free_irq(client->irq, data);
-       if (data->poweron)
-               data->poweron(false);
-       input_unregister_device(data->input_dev);
-       kfree(data);
 }
 
 static void mcs_touchkey_shutdown(struct i2c_client *client)
@@ -259,7 +255,6 @@ static struct i2c_driver mcs_touchkey_driver = {
                .pm     = pm_sleep_ptr(&mcs_touchkey_pm_ops),
        },
        .probe          = mcs_touchkey_probe,
-       .remove         = mcs_touchkey_remove,
        .shutdown       = mcs_touchkey_shutdown,
        .id_table       = mcs_touchkey_id,
 };
index 970f2a671c2e6d8dfa7414e4666fad89ace994ea..b3ccc97f61e1fb2d21e3651bbc1490789ce00d51 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 e9fa1423f136090ebeabafb4e74810c56a558f92..096c18d7bca1158ce9abefb7292927274288ae91 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 9f085d5679dbbccb5dcf6b38e955e887add6ecea..773e55eed88b18353742107689d5c93e2aae4c16 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 b0ea387414c1e2069585842b21293151bbeba389..7ffe1a70c8566404b6ad14d23b9cb56d68850ad0 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 038ff3549a7ac999e99cf6a9dfb3c83de0ce4a1c..147b1f288a33443c609086e9ae8cd37ef743fc9d 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;
index 871f858d0ba78a5bb79b6f8aa9d78bcf7ebc0b44..3724363d140e5f99163dbe97da8fa4900700011d 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 91aaa9fc43a4a5774bfeea1b7079407c936d7a85..9b093b042bf1900ed5a99a09382a026f9468ce0a 100644 (file)
@@ -149,20 +149,20 @@ static int qt1070_probe(struct i2c_client *client)
        if (!qt1070_identify(client))
                return -ENODEV;
 
-       data = kzalloc(sizeof(struct qt1070_data), GFP_KERNEL);
-       input = input_allocate_device();
-       if (!data || !input) {
-               dev_err(&client->dev, "insufficient memory\n");
-               err = -ENOMEM;
-               goto err_free_mem;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct qt1070_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       input = devm_input_allocate_device(&client->dev);
+       if (!input)
+               return -ENOMEM;
 
        data->client = client;
        data->input = input;
        data->irq = client->irq;
 
        input->name = "AT42QT1070 QTouch Sensor";
-       input->dev.parent = &client->dev;
        input->id.bustype = BUS_I2C;
 
        /* Add the keycode */
@@ -185,19 +185,20 @@ static int qt1070_probe(struct i2c_client *client)
        qt1070_write(client, RESET, 1);
        msleep(QT1070_RESET_TIME);
 
-       err = request_threaded_irq(client->irq, NULL, qt1070_interrupt,
-                                  IRQF_TRIGGER_NONE | IRQF_ONESHOT,
-                                  client->dev.driver->name, data);
+       err = devm_request_threaded_irq(&client->dev, client->irq,
+                                       NULL, qt1070_interrupt,
+                                       IRQF_TRIGGER_NONE | IRQF_ONESHOT,
+                                       client->dev.driver->name, data);
        if (err) {
                dev_err(&client->dev, "fail to request irq\n");
-               goto err_free_mem;
+               return err;
        }
 
        /* Register the input device */
        err = input_register_device(data->input);
        if (err) {
                dev_err(&client->dev, "Failed to register input device\n");
-               goto err_free_irq;
+               return err;
        }
 
        i2c_set_clientdata(client, data);
@@ -206,24 +207,6 @@ static int qt1070_probe(struct i2c_client *client)
        qt1070_read(client, DET_STATUS);
 
        return 0;
-
-err_free_irq:
-       free_irq(client->irq, data);
-err_free_mem:
-       input_free_device(input);
-       kfree(data);
-       return err;
-}
-
-static void qt1070_remove(struct i2c_client *client)
-{
-       struct qt1070_data *data = i2c_get_clientdata(client);
-
-       /* Release IRQ */
-       free_irq(client->irq, data);
-
-       input_unregister_device(data->input);
-       kfree(data);
 }
 
 static int qt1070_suspend(struct device *dev)
@@ -272,7 +255,6 @@ static struct i2c_driver qt1070_driver = {
        },
        .id_table       = qt1070_id,
        .probe          = qt1070_probe,
-       .remove         = qt1070_remove,
 };
 
 module_i2c_driver(qt1070_driver);
index 599ea85cfd30c7c0f95def09593288e7f7bc5fb5..7e3b09642ab754db16952076bfd3dd1971b07e67 100644 (file)
@@ -32,7 +32,7 @@
 
 #define QT2160_NUM_LEDS_X      8
 
-#define QT2160_CYCLE_INTERVAL  (2*HZ)
+#define QT2160_CYCLE_INTERVAL  2000 /* msec - 2 sec */
 
 static unsigned char qt2160_key2code[] = {
        KEY_0, KEY_1, KEY_2, KEY_3,
@@ -54,7 +54,6 @@ struct qt2160_led {
 struct qt2160_data {
        struct i2c_client *client;
        struct input_dev *input;
-       struct delayed_work dwork;
        unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
        u16 key_matrix;
 #ifdef CONFIG_LEDS_CLASS
@@ -155,10 +154,10 @@ static int qt2160_read_block(struct i2c_client *client,
        return 0;
 }
 
-static int qt2160_get_key_matrix(struct qt2160_data *qt2160)
+static void qt2160_get_key_matrix(struct input_dev *input)
 {
+       struct qt2160_data *qt2160 = input_get_drvdata(input);
        struct i2c_client *client = qt2160->client;
-       struct input_dev *input = qt2160->input;
        u8 regs[6];
        u16 old_matrix, new_matrix;
        int ret, i, mask;
@@ -173,7 +172,7 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160)
        if (ret) {
                dev_err(&client->dev,
                        "could not perform chip read.\n");
-               return ret;
+               return;
        }
 
        old_matrix = qt2160->key_matrix;
@@ -191,37 +190,17 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160)
        }
 
        input_sync(input);
-
-       return 0;
 }
 
-static irqreturn_t qt2160_irq(int irq, void *_qt2160)
+static irqreturn_t qt2160_irq(int irq, void *data)
 {
-       struct qt2160_data *qt2160 = _qt2160;
+       struct input_dev *input = data;
 
-       mod_delayed_work(system_wq, &qt2160->dwork, 0);
+       qt2160_get_key_matrix(input);
 
        return IRQ_HANDLED;
 }
 
-static void qt2160_schedule_read(struct qt2160_data *qt2160)
-{
-       schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL);
-}
-
-static void qt2160_worker(struct work_struct *work)
-{
-       struct qt2160_data *qt2160 =
-               container_of(work, struct qt2160_data, dwork.work);
-
-       dev_dbg(&qt2160->client->dev, "worker\n");
-
-       qt2160_get_key_matrix(qt2160);
-
-       /* Avoid device lock up by checking every so often */
-       qt2160_schedule_read(qt2160);
-}
-
 static int qt2160_read(struct i2c_client *client, u8 reg)
 {
        int ret;
@@ -260,7 +239,7 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
 static int qt2160_register_leds(struct qt2160_data *qt2160)
 {
        struct i2c_client *client = qt2160->client;
-       int ret;
+       int error;
        int i;
 
        for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
@@ -273,9 +252,9 @@ static int qt2160_register_leds(struct qt2160_data *qt2160)
                led->id = i;
                led->qt2160 = qt2160;
 
-               ret = led_classdev_register(&client->dev, &led->cdev);
-               if (ret < 0)
-                       return ret;
+               error = devm_led_classdev_register(&client->dev, &led->cdev);
+               if (error)
+                       return error;
        }
 
        /* Tur off LEDs */
@@ -286,14 +265,6 @@ static int qt2160_register_leds(struct qt2160_data *qt2160)
        return 0;
 }
 
-static void qt2160_unregister_leds(struct qt2160_data *qt2160)
-{
-       int i;
-
-       for (i = 0; i < QT2160_NUM_LEDS_X; i++)
-               led_classdev_unregister(&qt2160->leds[i].cdev);
-}
-
 #else
 
 static inline int qt2160_register_leds(struct qt2160_data *qt2160)
@@ -301,10 +272,6 @@ static inline int qt2160_register_leds(struct qt2160_data *qt2160)
        return 0;
 }
 
-static inline void qt2160_unregister_leds(struct qt2160_data *qt2160)
-{
-}
-
 #endif
 
 static bool qt2160_identify(struct i2c_client *client)
@@ -345,12 +312,9 @@ static int qt2160_probe(struct i2c_client *client)
        int i;
        int error;
 
-       /* Check functionality */
-       error = i2c_check_functionality(client->adapter,
-                       I2C_FUNC_SMBUS_BYTE);
-       if (!error) {
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
                dev_err(&client->dev, "%s adapter not supported\n",
-                               dev_driver_string(&client->adapter->dev));
+                       dev_driver_string(&client->adapter->dev));
                return -ENODEV;
        }
 
@@ -358,17 +322,16 @@ static int qt2160_probe(struct i2c_client *client)
                return -ENODEV;
 
        /* Chip is valid and active. Allocate structure */
-       qt2160 = kzalloc(sizeof(struct qt2160_data), GFP_KERNEL);
-       input = input_allocate_device();
-       if (!qt2160 || !input) {
-               dev_err(&client->dev, "insufficient memory\n");
-               error = -ENOMEM;
-               goto err_free_mem;
-       }
+       qt2160 = devm_kzalloc(&client->dev, sizeof(*qt2160), GFP_KERNEL);
+       if (!qt2160)
+               return -ENOMEM;
+
+       input = devm_input_allocate_device(&client->dev);
+       if (!input)
+               return -ENOMEM;
 
        qt2160->client = client;
        qt2160->input = input;
-       INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker);
 
        input->name = "AT42QT2160 Touch Sense Keyboard";
        input->id.bustype = BUS_I2C;
@@ -385,66 +348,48 @@ static int qt2160_probe(struct i2c_client *client)
        }
        __clear_bit(KEY_RESERVED, input->keybit);
 
+       input_set_drvdata(input, qt2160);
+
        /* Calibrate device */
        error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1);
        if (error) {
                dev_err(&client->dev, "failed to calibrate device\n");
-               goto err_free_mem;
+               return error;
        }
 
        if (client->irq) {
-               error = request_irq(client->irq, qt2160_irq,
-                                   IRQF_TRIGGER_FALLING, "qt2160", qt2160);
+               error = devm_request_threaded_irq(&client->dev, client->irq,
+                                                 NULL, qt2160_irq,
+                                                 IRQF_ONESHOT,
+                                                 "qt2160", input);
                if (error) {
                        dev_err(&client->dev,
                                "failed to allocate irq %d\n", client->irq);
-                       goto err_free_mem;
+                       return error;
+               }
+       } else {
+               error = input_setup_polling(input, qt2160_get_key_matrix);
+               if (error) {
+                       dev_err(&client->dev, "Failed to setup polling\n");
+                       return error;
                }
+               input_set_poll_interval(input, QT2160_CYCLE_INTERVAL);
        }
 
        error = qt2160_register_leds(qt2160);
        if (error) {
                dev_err(&client->dev, "Failed to register leds\n");
-               goto err_free_irq;
+               return error;
        }
 
        error = input_register_device(qt2160->input);
        if (error) {
                dev_err(&client->dev,
                        "Failed to register input device\n");
-               goto err_unregister_leds;
+               return error;
        }
 
-       i2c_set_clientdata(client, qt2160);
-       qt2160_schedule_read(qt2160);
-
        return 0;
-
-err_unregister_leds:
-       qt2160_unregister_leds(qt2160);
-err_free_irq:
-       if (client->irq)
-               free_irq(client->irq, qt2160);
-err_free_mem:
-       input_free_device(input);
-       kfree(qt2160);
-       return error;
-}
-
-static void qt2160_remove(struct i2c_client *client)
-{
-       struct qt2160_data *qt2160 = i2c_get_clientdata(client);
-
-       qt2160_unregister_leds(qt2160);
-
-       /* Release IRQ so no queue will be scheduled */
-       if (client->irq)
-               free_irq(client->irq, qt2160);
-
-       cancel_delayed_work_sync(&qt2160->dwork);
-
-       input_unregister_device(qt2160->input);
-       kfree(qt2160);
 }
 
 static const struct i2c_device_id qt2160_idtable[] = {
@@ -461,7 +406,6 @@ static struct i2c_driver qt2160_driver = {
 
        .id_table       = qt2160_idtable,
        .probe          = qt2160_probe,
-       .remove         = qt2160_remove,
 };
 
 module_i2c_driver(qt2160_driver);
index 15c15c0958b00be87bce9ce0ea2f9fffe58f247e..f304cab0ebdb837484b4ce41bfb4227fc577ff76 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_wakeirq.h>
 #include <linux/pm_wakeup.h>
+#include <linux/property.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
@@ -307,8 +308,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 2f745cabf4f248aec628ef4422e1e1cd8d373254..8af59ced1ec2eda1365f5636ac91d48984da29da 100644 (file)
@@ -24,6 +24,8 @@
 #define TCA6416_INVERT         2
 #define TCA6416_DIRECTION      3
 
+#define TCA6416_POLL_INTERVAL  100 /* msec */
+
 static const struct i2c_device_id tca6416_id[] = {
        { "tca6416-keys", 16, },
        { "tca6408-keys", 8, },
@@ -43,7 +45,6 @@ struct tca6416_keypad_chip {
 
        struct i2c_client *client;
        struct input_dev *input;
-       struct delayed_work dwork;
        int io_size;
        int irqnum;
        u16 pinmask;
@@ -85,9 +86,9 @@ static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
        return 0;
 }
 
-static void tca6416_keys_scan(struct tca6416_keypad_chip *chip)
+static void tca6416_keys_scan(struct input_dev *input)
 {
-       struct input_dev *input = chip->input;
+       struct tca6416_keypad_chip *chip = input_get_drvdata(input);
        u16 reg_val, val;
        int error, i, pin_index;
 
@@ -122,33 +123,20 @@ static void tca6416_keys_scan(struct tca6416_keypad_chip *chip)
  */
 static irqreturn_t tca6416_keys_isr(int irq, void *dev_id)
 {
-       struct tca6416_keypad_chip *chip = dev_id;
-
-       tca6416_keys_scan(chip);
+       tca6416_keys_scan(dev_id);
 
        return IRQ_HANDLED;
 }
 
-static void tca6416_keys_work_func(struct work_struct *work)
-{
-       struct tca6416_keypad_chip *chip =
-               container_of(work, struct tca6416_keypad_chip, dwork.work);
-
-       tca6416_keys_scan(chip);
-       schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100));
-}
-
 static int tca6416_keys_open(struct input_dev *dev)
 {
        struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
 
-       /* Get initial device state in case it has switches */
-       tca6416_keys_scan(chip);
-
-       if (chip->use_polling)
-               schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100));
-       else
-               enable_irq(chip->irqnum);
+       if (!chip->use_polling) {
+               /* Get initial device state in case it has switches */
+               tca6416_keys_scan(dev);
+               enable_irq(chip->client->irq);
+       }
 
        return 0;
 }
@@ -157,10 +145,8 @@ static void tca6416_keys_close(struct input_dev *dev)
 {
        struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
 
-       if (chip->use_polling)
-               cancel_delayed_work_sync(&chip->dwork);
-       else
-               disable_irq(chip->irqnum);
+       if (!chip->use_polling)
+               disable_irq(chip->client->irq);
 }
 
 static int tca6416_setup_registers(struct tca6416_keypad_chip *chip)
@@ -216,12 +202,15 @@ static int tca6416_keypad_probe(struct i2c_client *client)
                return -EINVAL;
        }
 
-       chip = kzalloc(struct_size(chip, buttons, pdata->nbuttons), GFP_KERNEL);
-       input = input_allocate_device();
-       if (!chip || !input) {
-               error = -ENOMEM;
-               goto fail1;
-       }
+       chip = devm_kzalloc(&client->dev,
+                           struct_size(chip, buttons, pdata->nbuttons),
+                           GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       input = devm_input_allocate_device(&client->dev);
+       if (!input)
+               return -ENOMEM;
 
        chip->client = client;
        chip->input = input;
@@ -229,11 +218,8 @@ static int tca6416_keypad_probe(struct i2c_client *client)
        chip->pinmask = pdata->pinmask;
        chip->use_polling = pdata->use_polling;
 
-       INIT_DELAYED_WORK(&chip->dwork, tca6416_keys_work_func);
-
        input->phys = "tca6416-keys/input0";
        input->name = client->name;
-       input->dev.parent = &client->dev;
 
        input->open = tca6416_keys_open;
        input->close = tca6416_keys_close;
@@ -263,24 +249,28 @@ static int tca6416_keypad_probe(struct i2c_client *client)
         */
        error = tca6416_setup_registers(chip);
        if (error)
-               goto fail1;
+               return error;
 
-       if (!chip->use_polling) {
-               if (pdata->irq_is_gpio)
-                       chip->irqnum = gpio_to_irq(client->irq);
-               else
-                       chip->irqnum = client->irq;
-
-               error = request_threaded_irq(chip->irqnum, NULL,
-                                            tca6416_keys_isr,
-                                            IRQF_TRIGGER_FALLING |
-                                            IRQF_ONESHOT | IRQF_NO_AUTOEN,
-                                            "tca6416-keypad", chip);
+       if (chip->use_polling) {
+               error = input_setup_polling(input, tca6416_keys_scan);
+               if (error) {
+                       dev_err(&client->dev, "Failed to setup polling\n");
+                       return error;
+               }
+
+               input_set_poll_interval(input, TCA6416_POLL_INTERVAL);
+       } else {
+               error = devm_request_threaded_irq(&client->dev, client->irq,
+                                                 NULL, tca6416_keys_isr,
+                                                 IRQF_TRIGGER_FALLING |
+                                                       IRQF_ONESHOT |
+                                                       IRQF_NO_AUTOEN,
+                                                 "tca6416-keypad", input);
                if (error) {
                        dev_dbg(&client->dev,
                                "Unable to claim irq %d; error %d\n",
-                               chip->irqnum, error);
-                       goto fail1;
+                               client->irq, error);
+                       return error;
                }
        }
 
@@ -288,70 +278,19 @@ static int tca6416_keypad_probe(struct i2c_client *client)
        if (error) {
                dev_dbg(&client->dev,
                        "Unable to register input device, error: %d\n", error);
-               goto fail2;
+               return error;
        }
 
        i2c_set_clientdata(client, chip);
-       device_init_wakeup(&client->dev, 1);
 
        return 0;
-
-fail2:
-       if (!chip->use_polling) {
-               free_irq(chip->irqnum, chip);
-               enable_irq(chip->irqnum);
-       }
-fail1:
-       input_free_device(input);
-       kfree(chip);
-       return error;
 }
 
-static void tca6416_keypad_remove(struct i2c_client *client)
-{
-       struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
-
-       if (!chip->use_polling) {
-               free_irq(chip->irqnum, chip);
-               enable_irq(chip->irqnum);
-       }
-
-       input_unregister_device(chip->input);
-       kfree(chip);
-}
-
-static int tca6416_keypad_suspend(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
-
-       if (device_may_wakeup(dev))
-               enable_irq_wake(chip->irqnum);
-
-       return 0;
-}
-
-static int tca6416_keypad_resume(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
-
-       if (device_may_wakeup(dev))
-               disable_irq_wake(chip->irqnum);
-
-       return 0;
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops,
-                               tca6416_keypad_suspend, tca6416_keypad_resume);
-
 static struct i2c_driver tca6416_keypad_driver = {
        .driver = {
                .name   = "tca6416-keypad",
-               .pm     = pm_sleep_ptr(&tca6416_keypad_dev_pm_ops),
        },
        .probe          = tca6416_keypad_probe,
-       .remove         = tca6416_keypad_remove,
        .id_table       = tca6416_id,
 };
 
index d5a6c7d8eb25d0f57f40096dabc707fb01105c50..c9a823ea45d02965275f44318a7e8c5af3790887 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 75bd3ea5119490da8ca83c20809a33ab5e4f9c6a..0fd761ae052f10c47bbfa8300680fe787ba2a1e0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/pm.h>
 #include <linux/regulator/consumer.h>
 
index 8a320e6218e372a36b385bc04a8fa0bfb455cbd2..6ba984d7f0b18694f48160c4628575af1c8ea252 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 b14a389600c9eab7c356d6a85bea78aaf1e46289..74808bae326a710779cdfa455ff5781739bf6948 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
 #include <linux/workqueue.h>
 #include <linux/regmap.h>
 #include <linux/of.h>
@@ -251,6 +252,14 @@ static int da9063_onkey_probe(struct platform_device *pdev)
                return error;
        }
 
+       error = dev_pm_set_wake_irq(&pdev->dev, irq);
+       if (error)
+               dev_warn(&pdev->dev,
+                        "Failed to set IRQ %d as a wake IRQ: %d\n",
+                        irq, error);
+       else
+               device_init_wakeup(&pdev->dev, true);
+
        error = input_register_device(onkey->input);
        if (error) {
                dev_err(&pdev->dev,
index 134a1309ba927bcba83ae23f7244e0aec2c48938..ad44b4d18a2a16ace7420597a812287c5b6e4d39 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/input.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/regulator/consumer.h>
@@ -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 1272ef7b579494dab0b15cdc75dad90cfe5df931..c0a08563987053effad40b29e51d75a8839320d0 100644 (file)
@@ -17,9 +17,9 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
-#include <linux/of_device.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
index 50035c25c3f70aed98ce186bee08a6b9504fe94c..0dab54d3a0603b53e914df38f53104863ff3fbf3 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/input/touchscreen.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
index 096b0925f41bab10819c900e014708c1eca4c990..36aeeae7761101de277ffbfcbc93fba402c51590 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>
  */
 #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>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
 #include <linux/property.h>
 #include <linux/slab.h>
 #include <asm/unaligned.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);
@@ -2598,5 +3048,5 @@ static struct i2c_driver iqs7222_i2c_driver = {
 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 76a190b2220bd465016071118440b5fc90708116..662b436d765bb958c5e4d0030a1e27fed389fa8f 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
 
 #define MMA8450_DRV_NAME       "mma8450"
 
index 74d77d8aaeff204d3b9cfca4aa531dc4431d78bb..ba747c5b2b5fc7620fbd8b2acf2bac46cf92fd47 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/reboot.h>
 #include <linux/regmap.h>
index 04cb87efd7991cc075fb38172a347924001664ad..5c288fe7accf1fbc231923d6444721eff0fcccf5 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
index 89fb137e3715774b3fc081fda978b470a47cc363..c406a1cca5c443cb4b7cd6919231e1139e6ab504 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/regmap.h>
 #include <linux/log2.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 
 #define PON_CNTL_1 0x1C
 #define PON_CNTL_PULL_UP BIT(7)
index 3cf1812384e6ad97009aa594bbd5a96c40c0c3c0..1e731d8397c6f525c283b8858d45fac7c34eab6d 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 2ba035299db879b224010004b6b018e2fecd4b60..acac79c488aa1531fa421ea6d677469652d4c406 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/input.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/pwm.h>
@@ -140,32 +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\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->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
                                                        GPIOD_OUT_LOW);
-       err = PTR_ERR_OR_ZERO(vibrator->enable_gpio);
-       if (err) {
-               if (err != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "Failed to request enable gpio: %d\n",
-                               err);
-               return err;
-       }
+       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\n",
-                               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);
 
index 22ec620830653dd73505843a871874555ebd6f36..e94cab8133becb9b5970789a1658cb38c59ca5a2 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 cdcb7737c46aa50a91d5205d8728f13f9d8215a1..e5dd84725c6e74737ca4a080d6ac4b1129330623 100644 (file)
@@ -9,7 +9,8 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/input.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 
 #include <asm/io.h>
index 0cff742302a9fca607db01ee4496b88186748d37..148a601396f92cd5293405fe0355f57672154e4e 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) {
index 2a2459b1b4f2cb91b0465f77637f22a0b71bcf62..7b13de9799089fcea428738cb3f59fb9939b5abb 100644 (file)
@@ -5,6 +5,7 @@
 
 #define pr_fmt(fmt)            KBUILD_MODNAME ": " fmt
 
+#include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/libps2.h>
@@ -118,13 +119,18 @@ static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse)
        return PSMOUSE_FULL_PACKET;
 }
 
-static int psmouse_smbus_reconnect(struct psmouse *psmouse)
+static void psmouse_activate_smbus_mode(struct psmouse_smbus_dev *smbdev)
 {
-       struct psmouse_smbus_dev *smbdev = psmouse->private;
-
-       if (smbdev->need_deactivate)
-               psmouse_deactivate(psmouse);
+       if (smbdev->need_deactivate) {
+               psmouse_deactivate(smbdev->psmouse);
+               /* Give the device time to switch into SMBus mode */
+               msleep(30);
+       }
+}
 
+static int psmouse_smbus_reconnect(struct psmouse *psmouse)
+{
+       psmouse_activate_smbus_mode(psmouse->private);
        return 0;
 }
 
@@ -257,8 +263,7 @@ int psmouse_smbus_init(struct psmouse *psmouse,
                }
        }
 
-       if (need_deactivate)
-               psmouse_deactivate(psmouse);
+       psmouse_activate_smbus_mode(smbdev);
 
        psmouse->private = smbdev;
        psmouse->protocol_handler = psmouse_smbus_process_byte;
index 513d96e40e0efacbac3236f392cacd310ead80ff..3f6866d39b862454fa903981016c3df03b252c8f 100644 (file)
  * Contributors: Daniel Hellstrom <daniel@gaisler.com>
  */
 #include <linux/platform_device.h>
-#include <linux/of_device.h>
 #include <linux/module.h>
 #include <linux/serio.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/device.h>
 #include <linux/delay.h>
index c712c1fe060533045d5f10bf80f5f6bc00636632..b68793bf05c8cefb9f7bb59da7748147d611da7f 100644 (file)
@@ -2,7 +2,9 @@
 #ifndef _I8042_SPARCIO_H
 #define _I8042_SPARCIO_H
 
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 
 #include <asm/io.h>
index ce420eb1f51bec22d377e6043318a3c816e48263..e8a9709f32ebbb68ab1d09f8bc56860f1751b63c 100644 (file)
@@ -101,12 +101,12 @@ static int rpckbd_probe(struct platform_device *dev)
        int tx_irq, rx_irq;
 
        rx_irq = platform_get_irq(dev, 0);
-       if (rx_irq <= 0)
-               return rx_irq < 0 ? rx_irq : -ENXIO;
+       if (rx_irq < 0)
+               return rx_irq;
 
        tx_irq = platform_get_irq(dev, 1);
-       if (tx_irq <= 0)
-               return tx_irq < 0 ? tx_irq : -ENXIO;
+       if (tx_irq < 0)
+               return tx_irq;
 
        serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
        rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL);
index 960d7601fbc825dc22a7d64ac42cda1c95113070..f3d28da70b75c4478becad35f757e972fc7a054d 100644 (file)
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/mod_devicetable.h>
 #include <linux/of_address.h>
-#include <linux/of_device.h>
 #include <linux/of_irq.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
 
 #define DRIVER_NAME            "xilinx_ps2"
 
index c2cbd332af1dfabd17ad339a75efd5b76c9c943b..e3e2324547b909d0dc1f0e57a3b32db0c519ddbc 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
@@ -1365,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 159cd5136fdbca6938d31e2772296c6b73953ec2..62bd24f3ac8e0d382d041325c0de3c53e1cbc118 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 85332cfaa29dc92718a90c812ff30e8368e79da2..652439a79e216d8e67ffae5033fd5dd9929af992 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;
        }
 
index c8126d2efe95a9c4c6ed8e8d819d516a65e2aa81..e1dfbd92ab648e47dc517a6604c19e8123d8c120 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;
        }
 
index 9fbeaf17f00b70ea2ae604f18a578459b3220924..d6876d10b25283d2e2447c069edb5f00bb51331d 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)
index 967ecde23e83ff53cc6c17c40baddec88b7be138..ea3895167b82e529fc0d7f6d05e989f7022f6ef3 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)
index b461ded946fc892bbc5c08eac54983d2d5fd8b9e..db5a885ecd728573edc566eb2d57f10d26e7e33a 100644 (file)
@@ -18,8 +18,8 @@
 #include <linux/input/touchscreen.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
 #include <linux/regmap.h>
 #include <asm/unaligned.h>
 
index 795c7dad22bfb04f5fb58ff0c4cf33572ff1f4ad..457d53337fbb399191efd37f7f822a53e204b981 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)) {
index fd8724a3c19fd3e7eb751b122f0bee8b1643f8b2..cc3103b9cbfba4690db992bbf9de54f0f65e0e5d 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)
index 2da1db64126d19fc49860598d410dd9af11c52f7..a1af3de9f3109ed6c6887d6b6575a33facf44669 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)) {
index 4af4c1e5d0da25458f98439d09306b32bf114abe..e3f6d21b3c1b3d5510682d883279c40e47db37ce 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);
index f5aa240739f9709dab5640b87a6120d977f47c32..85d4249f10656ede20d8e45f8440e62c42cb6279 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;
 
index f7cd773f7292a1a3d582391a83d0f6a843c63034..ad6828e4f2e2df579b3f084c17405324eee662d4 100644 (file)
@@ -8,8 +8,8 @@
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
 #include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
index 0aa9d6492df8f8584f93a4cf743ee79253aeab17..b4768b66eb1012d6c669d7eaeb8848e1f91fc969 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/input/touchscreen.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
-#include <linux/of_device.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 
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 15b5cb763526a56d24d8c12949823e31f28bc7e6..9bad8b93c0395bd1435f216eae9ac68fa6b24e42 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 32896e5085bdcfb7090856e1d78f7523b40704d8..2ac4483fbc2588b552ef9c76f40caa7f51978036 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)
index ac12494c7930d679af17e3a0c77df03fe107c50e..af233b6a16d9abf780285a71b543a952fac1711a 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/i2c.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
@@ -43,6 +42,7 @@
 /* Touchscreen absolute values */
 #define MMS114_MAX_AREA                        0xff
 
+#define MMS114_MAX_TOUCHKEYS           15
 #define MMS114_MAX_TOUCH               10
 #define MMS114_EVENT_SIZE              8
 #define MMS136_EVENT_SIZE              6
@@ -70,6 +70,9 @@ struct mms114_data {
        unsigned int            contact_threshold;
        unsigned int            moving_threshold;
 
+       u32 keycodes[MMS114_MAX_TOUCHKEYS];
+       int num_keycodes;
+
        /* Use cache data for mode control register(write only) */
        u8                      cache_mode_control;
 };
@@ -167,11 +170,6 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou
                return;
        }
 
-       if (touch->type != MMS114_TYPE_TOUCHSCREEN) {
-               dev_err(&client->dev, "Wrong touch type (%d)\n", touch->type);
-               return;
-       }
-
        id = touch->id - 1;
        x = touch->x_lo | touch->x_hi << 8;
        y = touch->y_lo | touch->y_hi << 8;
@@ -191,9 +189,33 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou
        }
 }
 
+static void mms114_process_touchkey(struct mms114_data *data,
+                                   struct mms114_touch *touch)
+{
+       struct i2c_client *client = data->client;
+       struct input_dev *input_dev = data->input_dev;
+       unsigned int keycode_id;
+
+       if (touch->id == 0)
+               return;
+
+       if (touch->id > data->num_keycodes) {
+               dev_err(&client->dev, "Wrong touch id for touchkey (%d)\n",
+                       touch->id);
+               return;
+       }
+
+       keycode_id = touch->id - 1;
+       dev_dbg(&client->dev, "keycode id: %d, pressed: %d\n", keycode_id,
+               touch->pressed);
+
+       input_report_key(input_dev, data->keycodes[keycode_id], touch->pressed);
+}
+
 static irqreturn_t mms114_interrupt(int irq, void *dev_id)
 {
        struct mms114_data *data = dev_id;
+       struct i2c_client *client = data->client;
        struct input_dev *input_dev = data->input_dev;
        struct mms114_touch touch[MMS114_MAX_TOUCH];
        int packet_size;
@@ -223,8 +245,22 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
        if (error < 0)
                goto out;
 
-       for (index = 0; index < touch_size; index++)
-               mms114_process_mt(data, touch + index);
+       for (index = 0; index < touch_size; index++) {
+               switch (touch[index].type) {
+               case MMS114_TYPE_TOUCHSCREEN:
+                       mms114_process_mt(data, touch + index);
+                       break;
+
+               case MMS114_TYPE_TOUCHKEY:
+                       mms114_process_touchkey(data, touch + index);
+                       break;
+
+               default:
+                       dev_err(&client->dev, "Wrong touch type (%d)\n",
+                               touch[index].type);
+                       break;
+               }
+       }
 
        input_mt_report_pointer_emulation(data->input_dev, true);
        input_sync(data->input_dev);
@@ -446,6 +482,7 @@ static int mms114_probe(struct i2c_client *client)
        struct input_dev *input_dev;
        const void *match_data;
        int error;
+       int i;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                dev_err(&client->dev, "Not supported I2C adapter\n");
@@ -469,6 +506,42 @@ static int mms114_probe(struct i2c_client *client)
 
        data->type = (enum mms_type)match_data;
 
+       data->num_keycodes = device_property_count_u32(&client->dev,
+                                                      "linux,keycodes");
+       if (data->num_keycodes == -EINVAL) {
+               data->num_keycodes = 0;
+       } else if (data->num_keycodes < 0) {
+               dev_err(&client->dev,
+                       "Unable to parse linux,keycodes property: %d\n",
+                       data->num_keycodes);
+               return data->num_keycodes;
+       } else if (data->num_keycodes > MMS114_MAX_TOUCHKEYS) {
+               dev_warn(&client->dev,
+                       "Found %d linux,keycodes but max is %d, ignoring the rest\n",
+                        data->num_keycodes, MMS114_MAX_TOUCHKEYS);
+               data->num_keycodes = MMS114_MAX_TOUCHKEYS;
+       }
+
+       if (data->num_keycodes > 0) {
+               error = device_property_read_u32_array(&client->dev,
+                                                      "linux,keycodes",
+                                                      data->keycodes,
+                                                      data->num_keycodes);
+               if (error) {
+                       dev_err(&client->dev,
+                               "Unable to read linux,keycodes values: %d\n",
+                               error);
+                       return error;
+               }
+
+               input_dev->keycode = data->keycodes;
+               input_dev->keycodemax = data->num_keycodes;
+               input_dev->keycodesize = sizeof(data->keycodes[0]);
+               for (i = 0; i < data->num_keycodes; i++)
+                       input_set_capability(input_dev,
+                                            EV_KEY, data->keycodes[i]);
+       }
+
        input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
        input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
        input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
index 7f7d879aac6d55b6a265bce39faee4b8228c8398..1a797e410a3faeb324869a1620946627fc7335ef 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;
        }
 
@@ -296,6 +294,6 @@ static struct i2c_driver nvt_ts_driver = {
 
 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 554e179c2e487dbd0709b051e73cea7e32837868..4ede0687beb096565a88bd60fe3e36b55e258f43 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
 #include <linux/interrupt.h>
-#include <linux/of_device.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 
 #define PIXCIR_MAX_SLOTS       5 /* Max fingers supported by driver */
@@ -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);
index 76e7d62d587023c682edca7b73225f93de4e8b12..78dd3059d585ac21ecfd5d1fe502466b111ed984 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)
index 6f754a8d30b11776381b3fe78427c09226b98385..7e761ec73273b270ac49c0229d6fb7f6b81d1bf7 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 9e28f962e059d43231a47e7c505a116d0f584e53..62f562ad50263c64af43303e03d2bb75b6b04d66 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)
index 426564d0fc39aed0b4cc10e5d6649cbc942fa24b..ed56cb546f393b37d0ed9b75716401a15981ae71 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);
 
index 31d140248f2e96ee70d2c7900537c9b6678aaee8..7efbcd0fde4fc32021cefc9b3557e7c8ded25866 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 0293c493bc79f0184111307aa4b8fd44fdc750a4..f5c5881cef6bc7600d2f6d4913da05f015c35ea1 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);
index decf2d24a11554eb96f6170337f4f867163a5457..9aa4e35fb4f5aaf083341f93703457ead0d1deb2 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/sort.h>
 #include <linux/pm_wakeirq.h>
 
index 0a221e768ea4f6c92ff6bef47a5c4c3f85fe12ad..07e370113b2b6558faf293c11bebe5ac7ca85ea6 100644 (file)
@@ -63,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 */
index b0d36a9934ccd403bd586954694fdb67311e833f..5cf6f6f82aa700a794564dc420b1cf1348d56e5f 100644 (file)
@@ -25,7 +25,6 @@ struct tca6416_keys_platform_data {
        unsigned int rep:1;     /* enable input subsystem auto repeat */
        uint16_t pinmask;
        uint16_t invert;
-       int irq_is_gpio;
        int use_polling;        /* use polling if Interrupt is not connected*/
 };
 #endif