Commit 664a393a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'input-for-v5.19-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:

 - a new driver for the Azoteq IQS7222A/B/C capacitive touch controller

 - a new driver for Raspberry Pi Sense HAT joystick

 - sun4i-lradc-keys gained support of R329 and D1 variants, plus it can
   be now used as a wakeup source

 - pm8941-pwrkey can now properly handle PON GEN3 variants; the driver
   also implements software debouncing and has a workaround for missing
   key press events

 - assorted driver fixes and cleanups

* tag 'input-for-v5.19-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (29 commits)
  Input: stmfts - do not leave device disabled in stmfts_input_open
  Input: gpio-keys - cancel delayed work only in case of GPIO
  Input: cypress_ps2 - fix typo in comment
  Input: vmmouse - disable vmmouse before entering suspend mode
  dt-bindings: google,cros-ec-keyb: Fixup bad compatible match
  Input: cros-ec-keyb - allow skipping keyboard registration
  dt-bindings: google,cros-ec-keyb: Introduce switches only compatible
  Input: psmouse-smbus - avoid flush_scheduled_work() usage
  Input: bcm-keypad - remove unneeded NULL check before clk_disable_unprepare
  Input: sparcspkr - fix refcount leak in bbc_beep_probe
  Input: sun4i-lradc-keys - add support for R329 and D1
  Input: sun4i-lradc-keys - add optional clock/reset support
  dt-bindings: input: sun4i-lradc-keys: Add R329 and D1 compatibles
  Input: sun4i-lradc-keys - add wakeup support
  Input: pm8941-pwrkey - simulate missed key press events
  Input: pm8941-pwrkey - add software key press debouncing support
  Input: pm8941-pwrkey - add support for PON GEN3 base addresses
  Input: pm8941-pwrkey - fix error message
  Input: synaptics-rmi4 - remove unnecessary flush_workqueue()
  Input: ep93xx_keypad - use devm_platform_ioremap_resource() helper
  ...
parents 47f15561 1e90e262
......@@ -18,10 +18,20 @@ properties:
- items:
- const: allwinner,sun50i-a64-lradc
- const: allwinner,sun8i-a83t-r-lradc
- const: allwinner,sun50i-r329-lradc
- items:
- const: allwinner,sun20i-d1-lradc
- const: allwinner,sun50i-r329-lradc
reg:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
interrupts:
maxItems: 1
......@@ -68,6 +78,18 @@ required:
- interrupts
- vref-supply
if:
properties:
compatible:
contains:
enum:
- allwinner,sun50i-r329-lradc
then:
required:
- clocks
- resets
additionalProperties: false
examples:
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$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
maintainers:
- Jeff LaBundy <jeff@labundy.com>
description: |
The Azoteq IQS7222A, IQS7222B and IQS7222C are multichannel capacitive touch
controllers that feature additional sensing capabilities.
Link to datasheets: https://www.azoteq.com/
properties:
compatible:
enum:
- azoteq,iqs7222a
- azoteq,iqs7222b
- azoteq,iqs7222c
reg:
maxItems: 1
irq-gpios:
maxItems: 1
description:
Specifies the GPIO connected to the device's active-low RDY output.
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,rf-filt-enable:
type: boolean
description: Enables the device's internal RF filter.
azoteq,max-counts:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
description: |
Specifies the maximum number of conversion periods (counts) that can be
reported as follows:
0: 1023
1: 2047
2: 4095
3: 16384
azoteq,auto-mode:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
description: |
Specifies the number of conversions to occur before an interrupt is
generated as follows:
0: 4
1: 8
2: 16
3: 32
azoteq,ati-frac-div-fine:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
description: Specifies the preloaded ATI fine fractional divider.
azoteq,ati-frac-div-coarse:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
description: Specifies the preloaded ATI coarse fractional divider.
azoteq,ati-comp-select:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 1023
description: Specifies the preloaded ATI compensation selection.
azoteq,lta-beta-lp:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description:
Specifies the long-term average filter damping factor to be applied during
low-power mode.
azoteq,lta-beta-np:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description:
Specifies the long-term average filter damping factor to be applied during
normal-power mode.
azoteq,counts-beta-lp:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description:
Specifies the counts filter damping factor to be applied during low-power
mode.
azoteq,counts-beta-np:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description:
Specifies the counts filter damping factor to be applied during normal-
power mode.
azoteq,lta-fast-beta-lp:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description:
Specifies the long-term average filter fast damping factor to be applied
during low-power mode.
azoteq,lta-fast-beta-np:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description:
Specifies the long-term average filter fast damping factor to be applied
during normal-power mode.
azoteq,timeout-ati-ms:
multipleOf: 500
minimum: 0
maximum: 32767500
description:
Specifies the delay (in ms) before ATI is retried following an ATI error.
azoteq,rate-ati-ms:
minimum: 0
maximum: 65535
description: Specifies the rate (in ms) at which ATI status is evaluated.
azoteq,timeout-np-ms:
minimum: 0
maximum: 65535
description:
Specifies the length of time (in ms) to wait for an event before moving
from normal-power mode to low-power mode.
azoteq,rate-np-ms:
minimum: 0
maximum: 3000
description: Specifies the report rate (in ms) during normal-power mode.
azoteq,timeout-lp-ms:
minimum: 0
maximum: 65535
description:
Specifies the length of time (in ms) to wait for an event before moving
from low-power mode to ultra-low-power mode.
azoteq,rate-lp-ms:
minimum: 0
maximum: 3000
description: Specifies the report rate (in ms) during low-power mode.
azoteq,timeout-ulp-ms:
minimum: 0
maximum: 65535
description:
Specifies the rate (in ms) at which channels not regularly sampled during
ultra-low-power mode are updated.
azoteq,rate-ulp-ms:
minimum: 0
maximum: 3000
description: Specifies the report rate (in ms) during ultra-low-power mode.
patternProperties:
"^cycle-[0-9]$":
type: object
description: Represents a conversion cycle serving two sensing channels.
properties:
azoteq,conv-period:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
description: Specifies the cycle's conversion period.
azoteq,conv-frac:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
description: Specifies the cycle's conversion frequency fraction.
azoteq,tx-enable:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 9
items:
minimum: 0
maximum: 8
description: Specifies the CTx pin(s) associated with the cycle.
azoteq,rx-float-inactive:
type: boolean
description: Floats any inactive CRx pins instead of grounding them.
azoteq,dead-time-enable:
type: boolean
description:
Increases the denominator of the conversion frequency formula by one.
azoteq,tx-freq-fosc:
type: boolean
description:
Fixes the conversion frequency to that of the device's core clock.
azoteq,vbias-enable:
type: boolean
description: Enables the bias voltage for use during inductive sensing.
azoteq,sense-mode:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
description: |
Specifies the cycle's sensing mode as follows:
0: None
1: Self capacitive
2: Mutual capacitive
3: Inductive
Note that in the case of IQS7222A, cycles 5 and 6 are restricted to
Hall-effect sensing.
azoteq,iref-enable:
type: boolean
description:
Enables the current reference for use during various sensing modes.
azoteq,iref-level:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description: Specifies the cycle's current reference level.
azoteq,iref-trim:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description: Specifies the cycle's current reference trim.
dependencies:
azoteq,iref-level: ["azoteq,iref-enable"]
azoteq,iref-trim: ["azoteq,iref-enable"]
additionalProperties: false
"^channel-([0-9]|1[0-9])$":
type: object
description:
Represents a single sensing channel. A channel is active if defined and
inactive otherwise.
Note that in the case of IQS7222A, channels 10 and 11 are restricted to
Hall-effect sensing with events reported on channel 10 only.
properties:
azoteq,ulp-allow:
type: boolean
description:
Permits the device to enter ultra-low-power mode while the channel
lies in a state of touch or proximity.
azoteq,ref-select:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 9
description: Specifies a separate reference channel to be followed.
azoteq,ref-weight:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 65535
description: Specifies the relative weight of the reference channel.
azoteq,use-prox:
type: boolean
description:
Activates the reference channel in response to proximity events
instead of touch events.
azoteq,ati-band:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
description: |
Specifies the channel's ATI band as a fraction of its ATI target as
follows:
0: 1/16
1: 1/8
2: 1/4
3: 1/2
azoteq,global-halt:
type: boolean
description:
Specifies that the channel's long-term average is to freeze if any
other participating channel lies in a proximity or touch state.
azoteq,invert-enable:
type: boolean
description:
Inverts the polarity of the states reported for proximity and touch
events relative to their respective thresholds.
azoteq,dual-direction:
type: boolean
description:
Specifies that the channel's long-term average is to freeze in the
presence of either increasing or decreasing counts, thereby permit-
ting events to be reported in either direction.
azoteq,rx-enable:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 4
items:
minimum: 0
maximum: 7
description: Specifies the CRx pin(s) associated with the channel.
azoteq,samp-cap-double:
type: boolean
description: Doubles the sampling capacitance from 40 pF to 80 pF.
azoteq,vref-half:
type: boolean
description: Halves the discharge threshold from 1.0 V to 0.5 V.
azoteq,proj-bias:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
description: |
Specifies the bias current applied during mutual (projected)
capacitive sensing as follows:
0: 2 uA
1: 5 uA
2: 7 uA
3: 10 uA
azoteq,ati-target:
$ref: /schemas/types.yaml#/definitions/uint32
multipleOf: 8
minimum: 0
maximum: 2040
description: Specifies the channel's ATI target.
azoteq,ati-base:
$ref: /schemas/types.yaml#/definitions/uint32
multipleOf: 16
minimum: 0
maximum: 496
description: Specifies the channel's ATI base.
azoteq,ati-mode:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3, 4, 5]
description: |
Specifies the channel's ATI mode as follows:
0: Disabled
1: Compensation
2: Compensation divider
3: Fine fractional divider
4: Coarse fractional divider
5: Full
azoteq,ati-frac-div-fine:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
description: Specifies the channel's ATI fine fractional divider.
azoteq,ati-frac-mult-coarse:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description: Specifies the channel's ATI coarse fractional multiplier.
azoteq,ati-frac-div-coarse:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
description: Specifies the channel's ATI coarse fractional divider.
azoteq,ati-comp-div:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
description: Specifies the channel's ATI compensation divider.
azoteq,ati-comp-select:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 1023
description: Specifies the channel's ATI compensation selection.
azoteq,debounce-enter:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description: Specifies the channel's debounce entrance factor.
azoteq,debounce-exit:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 15
description: Specifies the channel's debounce exit factor.
patternProperties:
"^event-(prox|touch)$":
type: object
description:
Represents a proximity or touch event reported by the channel.
properties:
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 (IQS7222C only)
2: GPIO4 (IQS7222C only)
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).
azoteq,thresh:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Specifies the threshold for the event. Valid entries range from
0-127 and 0-255 for proximity and touch events, respectively.
azoteq,hyst:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
description:
Specifies the hysteresis for the event (touch events only).
azoteq,timeout-press-ms:
multipleOf: 500
minimum: 0
maximum: 127500
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.
The IQS7222B does not feature channel-specific timeouts; the time-
out specified for any one channel applies to all channels.
linux,code:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Numeric key or switch code associated with the event. Specify
KEY_RESERVED (0) to opt out of event reporting.
linux,input-type:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 5]
default: 1
description:
Specifies whether the event is to be interpreted as a key (1)
or a switch (5).
required:
- linux,code
additionalProperties: false
dependencies:
azoteq,ref-weight: ["azoteq,ref-select"]
azoteq,use-prox: ["azoteq,ref-select"]
additionalProperties: false
"^slider-[0-1]$":
type: object
description: Represents a slider comprising three or four channels.
properties:
azoteq,channel-select:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 3
maxItems: 4
items:
minimum: 0
maximum: 9
description:
Specifies the order of the channels that participate in the slider.
azoteq,slider-size:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 65535
description:
Specifies the slider's one-dimensional resolution, equal to the
maximum coordinate plus one.
azoteq,lower-cal:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
description: Specifies the slider's lower starting point.
azoteq,upper-cal:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
description: Specifies the slider's upper starting point.
azoteq,top-speed:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 65535
description:
Specifies the speed of movement after which coordinate filtering is
no longer applied.
azoteq,bottom-speed:
$ref: /schemas/types.yaml#/definitions/uint32
multipleOf: 4
minimum: 0
maximum: 1020
description:
Specifies the speed of movement after which coordinate filtering is
linearly reduced.
azoteq,bottom-beta:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
description:
Specifies the coordinate filter damping factor to be applied
while the speed of movement is below that which is specified
by azoteq,bottom-speed.
azoteq,static-beta:
type: boolean
description:
Applies the coordinate filter damping factor specified by
azoteq,bottom-beta regardless of the speed of movement.
azoteq,use-prox:
type: boolean
description:
Directs the slider to respond to the proximity states of the selected
channels instead of their corresponding touch states. Note the slider
cannot report granular coordinates during a state of proximity.
linux,axis:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Specifies the absolute axis to which coordinates are mapped. Specify
ABS_WHEEL to operate the slider as a wheel (IQS7222C only).
patternProperties:
"^event-(press|tap|(swipe|flick)-(pos|neg))$":
type: object
description:
Represents a press or gesture (IQS7222A only) event reported by
the slider.
properties:
linux,code:
$ref: /schemas/types.yaml#/definitions/uint32
description: Numeric key code associated with the event.
azoteq,gesture-max-ms:
multipleOf: 4
minimum: 0
maximum: 1020
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 remaining swipe or flick gestures.
azoteq,gesture-min-ms:
multipleOf: 4
minimum: 0
maximum: 124
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
multipleOf: 16
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.
azoteq,gpio-select:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 1
items:
minimum: 0
maximum: 0
description: |
Specifies an individual GPIO mapped to a tap, swipe or flick
gesture as follows:
0: GPIO0
1: GPIO3 (reserved)
2: GPIO4 (reserved)
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).
required:
- linux,code
additionalProperties: false
required:
- azoteq,channel-select
additionalProperties: false
"^gpio-[0-2]$":
type: object
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)
allOf:
- $ref: ../pinctrl/pincfg-node.yaml#
properties:
drive-open-drain: true
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
const: azoteq,iqs7222b
then:
patternProperties:
"^cycle-[0-9]$":
properties:
azoteq,iref-enable: false
"^channel-([0-9]|1[0-9])$":
properties:
azoteq,ref-select: false
patternProperties:
"^event-(prox|touch)$":
properties:
azoteq,gpio-select: false
"^slider-[0-1]$": false
"^gpio-[0-2]$": false
- if:
properties:
compatible:
contains:
const: azoteq,iqs7222a
then:
patternProperties:
"^channel-([0-9]|1[0-9])$":
patternProperties:
"^event-(prox|touch)$":
properties:
azoteq,gpio-select:
maxItems: 1
items:
maximum: 0
"^slider-[0-1]$":
properties:
azoteq,slider-size:
multipleOf: 16
maximum: 4080
azoteq,top-speed:
multipleOf: 4
maximum: 1020
else:
patternProperties:
"^channel-([0-9]|1[0-9])$":
properties:
azoteq,ulp-allow: false
"^slider-[0-1]$":
patternProperties:
"^event-(press|tap|(swipe|flick)-(pos|neg))$":
properties:
azoteq,gesture-max-ms: false
azoteq,gesture-min-ms: false
azoteq,gesture-dist: false
azoteq,gpio-select: false
required:
- compatible
- reg
- irq-gpios
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
iqs7222a@44 {
compatible = "azoteq,iqs7222a";
reg = <0x44>;
irq-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
azoteq,lta-beta-lp = <7>;
azoteq,lta-beta-np = <8>;
azoteq,counts-beta-lp = <2>;
azoteq,counts-beta-np = <3>;
azoteq,lta-fast-beta-lp = <3>;
azoteq,lta-fast-beta-np = <4>;
cycle-0 {
azoteq,conv-period = <5>;
azoteq,conv-frac = <127>;
azoteq,tx-enable = <1>, <2>, <4>, <5>;
azoteq,dead-time-enable;
azoteq,sense-mode = <2>;
};
cycle-1 {
azoteq,conv-period = <5>;
azoteq,conv-frac = <127>;
azoteq,tx-enable = <5>;
azoteq,dead-time-enable;
azoteq,sense-mode = <2>;
};
cycle-2 {
azoteq,conv-period = <5>;
azoteq,conv-frac = <127>;
azoteq,tx-enable = <4>;
azoteq,dead-time-enable;
azoteq,sense-mode = <2>;
};
cycle-3 {
azoteq,conv-period = <5>;
azoteq,conv-frac = <127>;
azoteq,tx-enable = <2>;
azoteq,dead-time-enable;
azoteq,sense-mode = <2>;
};
cycle-4 {
azoteq,conv-period = <5>;
azoteq,conv-frac = <127>;
azoteq,tx-enable = <1>;
azoteq,dead-time-enable;
azoteq,sense-mode = <2>;
};
cycle-5 {
azoteq,conv-period = <2>;
azoteq,conv-frac = <0>;
};
cycle-6 {
azoteq,conv-period = <2>;
azoteq,conv-frac = <0>;
};
channel-0 {
azoteq,ulp-allow;
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <3>;
azoteq,ati-target = <800>;
azoteq,ati-base = <208>;
azoteq,ati-mode = <5>;
};
channel-1 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <3>;
azoteq,ati-target = <496>;
azoteq,ati-base = <208>;
azoteq,ati-mode = <5>;
};
channel-2 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <3>;
azoteq,ati-target = <496>;
azoteq,ati-base = <208>;
azoteq,ati-mode = <5>;
};
channel-3 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <3>;
azoteq,ati-target = <496>;
azoteq,ati-base = <208>;
azoteq,ati-mode = <5>;
};
channel-4 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <3>;
azoteq,ati-target = <496>;
azoteq,ati-base = <208>;
azoteq,ati-mode = <5>;
};
channel-5 {
azoteq,ulp-allow;
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <6>;
azoteq,ati-target = <800>;
azoteq,ati-base = <144>;
azoteq,ati-mode = <5>;
};
channel-6 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <6>;
azoteq,ati-target = <496>;
azoteq,ati-base = <160>;
azoteq,ati-mode = <5>;
event-touch {
linux,code = <KEY_MUTE>;
};
};
channel-7 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <6>;
azoteq,ati-target = <496>;
azoteq,ati-base = <160>;
azoteq,ati-mode = <5>;
event-touch {
linux,code = <KEY_VOLUMEDOWN>;
};
};
channel-8 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <6>;
azoteq,ati-target = <496>;
azoteq,ati-base = <160>;
azoteq,ati-mode = <5>;
event-touch {
linux,code = <KEY_VOLUMEUP>;
};
};
channel-9 {
azoteq,global-halt;
azoteq,invert-enable;
azoteq,rx-enable = <6>;
azoteq,ati-target = <496>;
azoteq,ati-base = <160>;
azoteq,ati-mode = <5>;
event-touch {
linux,code = <KEY_POWER>;
};
};
channel-10 {
azoteq,ulp-allow;
azoteq,ati-target = <496>;
azoteq,ati-base = <112>;
event-touch {
linux,code = <SW_LID>;
linux,input-type = <EV_SW>;
};
};
channel-11 {
azoteq,ati-target = <496>;
azoteq,ati-base = <112>;
};
slider-0 {
azoteq,channel-select = <1>, <2>, <3>, <4>;
azoteq,slider-size = <4080>;
azoteq,upper-cal = <50>;
azoteq,lower-cal = <30>;
azoteq,top-speed = <200>;
azoteq,bottom-speed = <1>;
azoteq,bottom-beta = <3>;
event-tap {
linux,code = <KEY_PLAYPAUSE>;
azoteq,gesture-max-ms = <600>;
azoteq,gesture-min-ms = <24>;
};
event-flick-pos {
linux,code = <KEY_NEXTSONG>;
azoteq,gesture-max-ms = <600>;
azoteq,gesture-dist = <816>;
};
event-flick-neg {
linux,code = <KEY_PREVIOUSSONG>;
};
};
};
};
...
......@@ -15,13 +15,15 @@ description: |
Google's ChromeOS EC Keyboard is a simple matrix keyboard
implemented on a separate EC (Embedded Controller) device. It provides
a message for reading key scans from the EC. These are then converted
into keycodes for processing by the kernel.
allOf:
- $ref: "/schemas/input/matrix-keymap.yaml#"
into keycodes for processing by the kernel. This device also supports
switches/buttons like power and volume buttons.
properties:
compatible:
oneOf:
- description: ChromeOS EC with only buttons/switches
const: google,cros-ec-keyb-switches
- description: ChromeOS EC with keyboard and possibly buttons/switches
const: google,cros-ec-keyb
google,needs-ghost-filter:
......@@ -42,15 +44,31 @@ properties:
where the lower 16 bits are reserved. This property is specified only
when the keyboard has a custom design for the top row keys.
dependencies:
function-row-phsymap: [ 'linux,keymap' ]
google,needs-ghost-filter: [ 'linux,keymap' ]
required:
- compatible
if:
properties:
compatible:
contains:
const: google,cros-ec-keyb
then:
$ref: "/schemas/input/matrix-keymap.yaml#"
required:
- keypad,num-rows
- keypad,num-columns
- linux,keymap
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/input/input.h>
cros-ec-keyb {
keyboard-controller {
compatible = "google,cros-ec-keyb";
keypad,num-rows = <8>;
keypad,num-columns = <13>;
......@@ -114,3 +132,9 @@ examples:
/* UP LEFT */
0x070b0067 0x070c0069>;
};
- |
/* No matrix keyboard, just buttons/switches */
keyboard-controller {
compatible = "google,cros-ec-keyb-switches";
};
...
......@@ -1793,8 +1793,6 @@ EXPORT_SYMBOL(input_reset_device);
static int input_inhibit_device(struct input_dev *dev)
{
int ret = 0;
mutex_lock(&dev->mutex);
if (dev->inhibited)
......@@ -1816,7 +1814,7 @@ static int input_inhibit_device(struct input_dev *dev)
out:
mutex_unlock(&dev->mutex);
return ret;
return 0;
}
static int input_uninhibit_device(struct input_dev *dev)
......
......@@ -399,4 +399,15 @@ config JOYSTICK_N64
Say Y here if you want enable support for the four
built-in controller ports on the Nintendo 64 console.
config JOYSTICK_SENSEHAT
tristate "Raspberry Pi Sense HAT joystick"
depends on INPUT && I2C
select MFD_SIMPLE_MFD_I2C
help
Say Y here if you want to enable the driver for the
the Raspberry Pi Sense HAT.
To compile this driver as a module, choose M here: the
module will be called sensehat_joystick.
endif
......@@ -28,6 +28,7 @@ obj-$(CONFIG_JOYSTICK_N64) += n64joy.o
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
obj-$(CONFIG_JOYSTICK_QWIIC) += qwiic-joystick.o
obj-$(CONFIG_JOYSTICK_SENSEHAT) += sensehat-joystick.o
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Raspberry Pi Sense HAT joystick driver
* http://raspberrypi.org
*
* Copyright (C) 2015 Raspberry Pi
* Copyright (C) 2021 Charles Mirabile, Mwesigwa Guma, Joel Savitz
*
* Original Author: Serge Schneider
* Revised for upstream Linux by: Charles Mirabile, Mwesigwa Guma, Joel Savitz
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/property.h>
#define JOYSTICK_SMB_REG 0xf2
struct sensehat_joystick {
struct platform_device *pdev;
struct input_dev *keys_dev;
unsigned long prev_states;
struct regmap *regmap;
};
static const unsigned int keymap[] = {
BTN_DPAD_DOWN, BTN_DPAD_RIGHT, BTN_DPAD_UP, BTN_SELECT, BTN_DPAD_LEFT,
};
static irqreturn_t sensehat_joystick_report(int irq, void *cookie)
{
struct sensehat_joystick *sensehat_joystick = cookie;
unsigned long curr_states, changes;
unsigned int keys;
int error;
int i;
error = regmap_read(sensehat_joystick->regmap, JOYSTICK_SMB_REG, &keys);
if (error < 0) {
dev_err(&sensehat_joystick->pdev->dev,
"Failed to read joystick state: %d", error);
return IRQ_NONE;
}
curr_states = keys;
bitmap_xor(&changes, &curr_states, &sensehat_joystick->prev_states,
ARRAY_SIZE(keymap));
for_each_set_bit(i, &changes, ARRAY_SIZE(keymap))
input_report_key(sensehat_joystick->keys_dev, keymap[i],
curr_states & BIT(i));
input_sync(sensehat_joystick->keys_dev);
sensehat_joystick->prev_states = keys;
return IRQ_HANDLED;
}
static int sensehat_joystick_probe(struct platform_device *pdev)
{
struct sensehat_joystick *sensehat_joystick;
int error, i, irq;
sensehat_joystick = devm_kzalloc(&pdev->dev, sizeof(*sensehat_joystick),
GFP_KERNEL);
if (!sensehat_joystick)
return -ENOMEM;
sensehat_joystick->pdev = pdev;
sensehat_joystick->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!sensehat_joystick->regmap) {
dev_err(&pdev->dev, "unable to get sensehat regmap");
return -ENODEV;
}
sensehat_joystick->keys_dev = devm_input_allocate_device(&pdev->dev);
if (!sensehat_joystick->keys_dev) {
dev_err(&pdev->dev, "Could not allocate input device");
return -ENOMEM;
}
sensehat_joystick->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
sensehat_joystick->keys_dev->phys = "sensehat-joystick/input0";
sensehat_joystick->keys_dev->id.bustype = BUS_I2C;
__set_bit(EV_KEY, sensehat_joystick->keys_dev->evbit);
__set_bit(EV_REP, sensehat_joystick->keys_dev->evbit);
for (i = 0; i < ARRAY_SIZE(keymap); i++)
__set_bit(keymap[i], sensehat_joystick->keys_dev->keybit);
error = input_register_device(sensehat_joystick->keys_dev);
if (error) {
dev_err(&pdev->dev, "Could not register input device");
return error;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "Could not retrieve interrupt request");
return irq;
}
error = devm_request_threaded_irq(&pdev->dev, irq,
NULL, sensehat_joystick_report,
IRQF_ONESHOT, "keys",
sensehat_joystick);
if (error) {
dev_err(&pdev->dev, "IRQ request failed");
return error;
}
return 0;
}
static const struct of_device_id sensehat_joystick_device_id[] = {
{ .compatible = "raspberrypi,sensehat-joystick" },
{},
};
MODULE_DEVICE_TABLE(of, sensehat_joystick_device_id);
static struct platform_driver sensehat_joystick_driver = {
.probe = sensehat_joystick_probe,
.driver = {
.name = "sensehat-joystick",
.of_match_table = sensehat_joystick_device_id,
},
};
module_platform_driver(sensehat_joystick_driver);
MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
MODULE_AUTHOR("Charles Mirabile <cmirabil@redhat.com>");
MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
MODULE_LICENSE("GPL");
......@@ -183,7 +183,6 @@ static void bcm_kp_stop(const struct bcm_kp *kp)
writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
if (kp->clk)
clk_disable_unprepare(kp->clk);
}
......
......@@ -95,8 +95,7 @@ static int clps711x_keypad_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->syscon =
syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
priv->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(priv->syscon))
return PTR_ERR(priv->syscon);
......
......@@ -435,10 +435,13 @@ static __maybe_unused int cros_ec_keyb_resume(struct device *dev)
* but the ckdev->bs_idev will remain NULL when this function exits.
*
* @ckdev: The keyboard device
* @expect_buttons_switches: Indicates that EC must report button and/or
* switch events
*
* Returns 0 if no error or -error upon error.
*/
static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev)
static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev,
bool expect_buttons_switches)
{
struct cros_ec_device *ec_dev = ckdev->ec;
struct device *dev = ckdev->dev;
......@@ -465,7 +468,7 @@ static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev)
switches = get_unaligned_le32(&event_data.switches);
if (!buttons && !switches)
return 0;
return expect_buttons_switches ? -EINVAL : 0;
/*
* We call the non-matrix buttons/switches 'input1', if present.
......@@ -516,7 +519,7 @@ static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev)
}
/**
* cros_ec_keyb_register_bs - Register matrix keys
* cros_ec_keyb_register_matrix - Register matrix keys
*
* Handles all the bits of the keyboard driver related to matrix keys.
*
......@@ -648,12 +651,12 @@ static const struct attribute_group cros_ec_keyb_attr_group = {
.attrs = cros_ec_keyb_attrs,
};
static int cros_ec_keyb_probe(struct platform_device *pdev)
{
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct cros_ec_keyb *ckdev;
bool buttons_switches_only = device_get_match_data(dev);
int err;
if (!dev->of_node)
......@@ -667,13 +670,16 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
ckdev->dev = dev;
dev_set_drvdata(dev, ckdev);
if (!buttons_switches_only) {
err = cros_ec_keyb_register_matrix(ckdev);
if (err) {
dev_err(dev, "cannot register matrix inputs: %d\n", err);
dev_err(dev, "cannot register matrix inputs: %d\n",
err);
return err;
}
}
err = cros_ec_keyb_register_bs(ckdev);
err = cros_ec_keyb_register_bs(ckdev, buttons_switches_only);
if (err) {
dev_err(dev, "cannot register non-matrix inputs: %d\n", err);
return err;
......@@ -681,7 +687,7 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
err = devm_device_add_group(dev, &cros_ec_keyb_attr_group);
if (err) {
dev_err(dev, "failed to create attributes. err=%d\n", err);
dev_err(dev, "failed to create attributes: %d\n", err);
return err;
}
......@@ -710,7 +716,8 @@ static int cros_ec_keyb_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id cros_ec_keyb_of_match[] = {
{ .compatible = "google,cros-ec-keyb" },
{},
{ .compatible = "google,cros-ec-keyb-switches", .data = (void *)true },
{}
};
MODULE_DEVICE_TABLE(of, cros_ec_keyb_of_match);
#endif
......
......@@ -231,7 +231,6 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
struct ep93xx_keypad *keypad;
const struct matrix_keymap_data *keymap_data;
struct input_dev *input_dev;
struct resource *res;
int err;
keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
......@@ -250,11 +249,7 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
if (keypad->irq < 0)
return keypad->irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENXIO;
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);
......
......@@ -131,7 +131,7 @@ static void gpio_keys_quiesce_key(void *data)
if (!bdata->gpiod)
hrtimer_cancel(&bdata->release_timer);
if (bdata->debounce_use_hrtimer)
else if (bdata->debounce_use_hrtimer)
hrtimer_cancel(&bdata->debounce_timer);
else
cancel_delayed_work_sync(&bdata->work);
......
......@@ -24,7 +24,6 @@ struct mt6779_keypad {
struct regmap *regmap;
struct input_dev *input_dev;
struct clk *clk;
void __iomem *base;
u32 n_rows;
u32 n_cols;
DECLARE_BITMAP(keymap_state, MTK_KPD_NUM_BITS);
......@@ -91,6 +90,7 @@ static void mt6779_keypad_clk_disable(void *data)
static int mt6779_keypad_pdrv_probe(struct platform_device *pdev)
{
struct mt6779_keypad *keypad;
void __iomem *base;
int irq;
u32 debounce;
bool wakeup;
......@@ -100,11 +100,11 @@ static int mt6779_keypad_pdrv_probe(struct platform_device *pdev)
if (!keypad)
return -ENOMEM;
keypad->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(keypad->base))
return PTR_ERR(keypad->base);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
keypad->regmap = devm_regmap_init_mmio(&pdev->dev, keypad->base,
keypad->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&mt6779_keypad_regmap_cfg);
if (IS_ERR(keypad->regmap)) {
dev_err(&pdev->dev,
......
......@@ -14,6 +14,7 @@
* there are no boards known to use channel 1.
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/input.h>
......@@ -22,7 +23,10 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/pm_wakeup.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#define LRADC_CTRL 0x00
......@@ -58,10 +62,12 @@
/* struct lradc_variant - Describe sun4i-a10-lradc-keys hardware variant
* @divisor_numerator: The numerator of lradc Vref internally divisor
* @divisor_denominator: The denominator of lradc Vref internally divisor
* @has_clock_reset: If the binding requires a clock and reset
*/
struct lradc_variant {
u8 divisor_numerator;
u8 divisor_denominator;
bool has_clock_reset;
};
static const struct lradc_variant lradc_variant_a10 = {
......@@ -74,6 +80,12 @@ static const struct lradc_variant r_lradc_variant_a83t = {
.divisor_denominator = 4
};
static const struct lradc_variant lradc_variant_r329 = {
.divisor_numerator = 3,
.divisor_denominator = 4,
.has_clock_reset = true,
};
struct sun4i_lradc_keymap {
u32 voltage;
u32 keycode;
......@@ -83,6 +95,8 @@ struct sun4i_lradc_data {
struct device *dev;
struct input_dev *input;
void __iomem *base;
struct clk *clk;
struct reset_control *reset;
struct regulator *vref_supply;
struct sun4i_lradc_keymap *chan0_map;
const struct lradc_variant *variant;
......@@ -140,6 +154,14 @@ static int sun4i_lradc_open(struct input_dev *dev)
if (error)
return error;
error = reset_control_deassert(lradc->reset);
if (error)
goto err_disable_reg;
error = clk_prepare_enable(lradc->clk);
if (error)
goto err_assert_reset;
lradc->vref = regulator_get_voltage(lradc->vref_supply) *
lradc->variant->divisor_numerator /
lradc->variant->divisor_denominator;
......@@ -153,6 +175,13 @@ static int sun4i_lradc_open(struct input_dev *dev)
writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC);
return 0;
err_assert_reset:
reset_control_assert(lradc->reset);
err_disable_reg:
regulator_disable(lradc->vref_supply);
return error;
}
static void sun4i_lradc_close(struct input_dev *dev)
......@@ -164,6 +193,8 @@ static void sun4i_lradc_close(struct input_dev *dev)
SAMPLE_RATE(2), lradc->base + LRADC_CTRL);
writel(0, lradc->base + LRADC_INTC);
clk_disable_unprepare(lradc->clk);
reset_control_assert(lradc->reset);
regulator_disable(lradc->vref_supply);
}
......@@ -226,8 +257,7 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
{
struct sun4i_lradc_data *lradc;
struct device *dev = &pdev->dev;
int i;
int error;
int error, i, irq;
lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
if (!lradc)
......@@ -243,6 +273,16 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
return -EINVAL;
}
if (lradc->variant->has_clock_reset) {
lradc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(lradc->clk))
return PTR_ERR(lradc->clk);
lradc->reset = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(lradc->reset))
return PTR_ERR(lradc->reset);
}
lradc->vref_supply = devm_regulator_get(dev, "vref");
if (IS_ERR(lradc->vref_supply))
return PTR_ERR(lradc->vref_supply);
......@@ -272,8 +312,11 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
if (IS_ERR(lradc->base))
return PTR_ERR(lradc->base);
error = devm_request_irq(dev, platform_get_irq(pdev, 0),
sun4i_lradc_irq, 0,
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
error = devm_request_irq(dev, irq, sun4i_lradc_irq, 0,
"sun4i-a10-lradc-keys", lradc);
if (error)
return error;
......@@ -282,6 +325,16 @@ static int sun4i_lradc_probe(struct platform_device *pdev)
if (error)
return error;
if (device_property_read_bool(dev, "wakeup-source")) {
error = dev_pm_set_wake_irq(dev, irq);
if (error)
dev_warn(dev,
"Failed to set IRQ %d as a wake IRQ: %d\n",
irq, error);
else
device_set_wakeup_capable(dev, true);
}
return 0;
}
......@@ -290,6 +343,8 @@ static const struct of_device_id sun4i_lradc_of_match[] = {
.data = &lradc_variant_a10 },
{ .compatible = "allwinner,sun8i-a83t-r-lradc",
.data = &r_lradc_variant_a83t },
{ .compatible = "allwinner,sun50i-r329-lradc",
.data = &lradc_variant_r329 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
......
......@@ -762,6 +762,16 @@ config INPUT_IQS626A
To compile this driver as a module, choose M here: the
module will be called iqs626a.
config INPUT_IQS7222
tristate "Azoteq IQS7222A/B/C capacitive touch controller"
depends on I2C
help
Say Y to enable support for the Azoteq IQS7222A/B/C family
of capacitive touch controllers.
To compile this driver as a module, choose M here: the
module will be called iqs7222.
config INPUT_CMA3000
tristate "VTI CMA3000 Tri-axis accelerometer"
help
......
......@@ -44,6 +44,7 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
obj-$(CONFIG_INPUT_IQS269A) += iqs269a.o
obj-$(CONFIG_INPUT_IQS626A) += iqs626a.o
obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Azoteq IQS7222A/B/C Capacitive Touch Controller
*
* Copyright (C) 2022 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/interrupt.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#define IQS7222_PROD_NUM 0x00
#define IQS7222_PROD_NUM_A 840
#define IQS7222_PROD_NUM_B 698
#define IQS7222_PROD_NUM_C 863
#define IQS7222_SYS_STATUS 0x10
#define IQS7222_SYS_STATUS_RESET BIT(3)
#define IQS7222_SYS_STATUS_ATI_ERROR BIT(1)
#define IQS7222_SYS_STATUS_ATI_ACTIVE BIT(0)
#define IQS7222_CHAN_SETUP_0_REF_MODE_MASK GENMASK(15, 14)
#define IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW BIT(15)
#define IQS7222_CHAN_SETUP_0_REF_MODE_REF BIT(14)
#define IQS7222_CHAN_SETUP_0_CHAN_EN BIT(8)
#define IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK GENMASK(2, 0)
#define IQS7222_SLDR_SETUP_2_RES_MASK GENMASK(15, 8)
#define IQS7222_SLDR_SETUP_2_RES_SHIFT 8
#define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK GENMASK(7, 0)
#define IQS7222_SLDR_SETUP_3_CHAN_SEL_MASK GENMASK(9, 0)
#define IQS7222_GPIO_SETUP_0_GPIO_EN BIT(0)
#define IQS7222_SYS_SETUP 0xD0
#define IQS7222_SYS_SETUP_INTF_MODE_MASK GENMASK(7, 6)
#define IQS7222_SYS_SETUP_INTF_MODE_TOUCH BIT(7)
#define IQS7222_SYS_SETUP_INTF_MODE_EVENT BIT(6)
#define IQS7222_SYS_SETUP_PWR_MODE_MASK GENMASK(5, 4)
#define IQS7222_SYS_SETUP_PWR_MODE_AUTO IQS7222_SYS_SETUP_PWR_MODE_MASK
#define IQS7222_SYS_SETUP_REDO_ATI BIT(2)
#define IQS7222_SYS_SETUP_ACK_RESET BIT(0)
#define IQS7222_EVENT_MASK_ATI BIT(12)
#define IQS7222_COMMS_HOLD BIT(0)
#define IQS7222_COMMS_ERROR 0xEEEE
#define IQS7222_COMMS_RETRY_MS 50
#define IQS7222_COMMS_TIMEOUT_MS 100
#define IQS7222_RESET_TIMEOUT_MS 250
#define IQS7222_ATI_TIMEOUT_MS 2000
#define IQS7222_MAX_COLS_STAT 8
#define IQS7222_MAX_COLS_CYCLE 3
#define IQS7222_MAX_COLS_GLBL 3
#define IQS7222_MAX_COLS_BTN 3
#define IQS7222_MAX_COLS_CHAN 6
#define IQS7222_MAX_COLS_FILT 2
#define IQS7222_MAX_COLS_SLDR 11
#define IQS7222_MAX_COLS_GPIO 3
#define IQS7222_MAX_COLS_SYS 13
#define IQS7222_MAX_CHAN 20
#define IQS7222_MAX_SLDR 2
#define IQS7222_NUM_RETRIES 5
#define IQS7222_REG_OFFSET 0x100
enum iqs7222_reg_key_id {
IQS7222_REG_KEY_NONE,
IQS7222_REG_KEY_PROX,
IQS7222_REG_KEY_TOUCH,
IQS7222_REG_KEY_DEBOUNCE,
IQS7222_REG_KEY_TAP,
IQS7222_REG_KEY_AXIAL,
IQS7222_REG_KEY_WHEEL,
IQS7222_REG_KEY_NO_WHEEL,
IQS7222_REG_KEY_RESERVED
};
enum iqs7222_reg_grp_id {
IQS7222_REG_GRP_STAT,
IQS7222_REG_GRP_CYCLE,
IQS7222_REG_GRP_GLBL,
IQS7222_REG_GRP_BTN,
IQS7222_REG_GRP_CHAN,
IQS7222_REG_GRP_FILT,
IQS7222_REG_GRP_SLDR,
IQS7222_REG_GRP_GPIO,
IQS7222_REG_GRP_SYS,
IQS7222_NUM_REG_GRPS
};
static const char * const iqs7222_reg_grp_names[] = {
[IQS7222_REG_GRP_CYCLE] = "cycle",
[IQS7222_REG_GRP_CHAN] = "channel",
[IQS7222_REG_GRP_SLDR] = "slider",
[IQS7222_REG_GRP_GPIO] = "gpio",
};
static const unsigned int iqs7222_max_cols[] = {
[IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT,
[IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE,
[IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL,
[IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN,
[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_GPIO] = IQS7222_MAX_COLS_GPIO,
[IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS,
};
static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, };
struct iqs7222_event_desc {
const char *name;
u16 mask;
u16 val;
u16 enable;
enum iqs7222_reg_key_id reg_key;
};
static const struct iqs7222_event_desc iqs7222_kp_events[] = {
{
.name = "event-prox",
.enable = BIT(0),
.reg_key = IQS7222_REG_KEY_PROX,
},
{
.name = "event-touch",
.enable = BIT(1),
.reg_key = IQS7222_REG_KEY_TOUCH,
},
};
static const struct iqs7222_event_desc iqs7222_sl_events[] = {
{ .name = "event-press", },
{
.name = "event-tap",
.mask = BIT(0),
.val = BIT(0),
.enable = BIT(0),
.reg_key = IQS7222_REG_KEY_TAP,
},
{
.name = "event-swipe-pos",
.mask = BIT(5) | BIT(1),
.val = BIT(1),
.enable = BIT(1),
.reg_key = IQS7222_REG_KEY_AXIAL,
},
{
.name = "event-swipe-neg",
.mask = BIT(5) | BIT(1),
.val = BIT(5) | BIT(1),
.enable = BIT(1),
.reg_key = IQS7222_REG_KEY_AXIAL,
},
{
.name = "event-flick-pos",
.mask = BIT(5) | BIT(2),
.val = BIT(2),
.enable = BIT(2),
.reg_key = IQS7222_REG_KEY_AXIAL,
},
{
.name = "event-flick-neg",
.mask = BIT(5) | BIT(2),
.val = BIT(5) | BIT(2),
.enable = BIT(2),
.reg_key = IQS7222_REG_KEY_AXIAL,
},
};
struct iqs7222_reg_grp_desc {
u16 base;
int num_row;
int num_col;
};
struct iqs7222_dev_desc {
u16 prod_num;
u16 fw_major;
u16 fw_minor;
u16 sldr_res;
u16 touch_link;
u16 wheel_enable;
int allow_offset;
int event_offset;
int comms_offset;
struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS];
};
static const struct iqs7222_dev_desc iqs7222_devs[] = {
{
.prod_num = IQS7222_PROD_NUM_A,
.fw_major = 1,
.fw_minor = 12,
.sldr_res = U8_MAX * 16,
.touch_link = 1768,
.allow_offset = 9,
.event_offset = 10,
.comms_offset = 12,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
.num_row = 1,
.num_col = 8,
},
[IQS7222_REG_GRP_CYCLE] = {
.base = 0x8000,
.num_row = 7,
.num_col = 3,
},
[IQS7222_REG_GRP_GLBL] = {
.base = 0x8700,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_BTN] = {
.base = 0x9000,
.num_row = 12,
.num_col = 3,
},
[IQS7222_REG_GRP_CHAN] = {
.base = 0xA000,
.num_row = 12,
.num_col = 6,
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAC00,
.num_row = 1,
.num_col = 2,
},
[IQS7222_REG_GRP_SLDR] = {
.base = 0xB000,
.num_row = 2,
.num_col = 11,
},
[IQS7222_REG_GRP_GPIO] = {
.base = 0xC000,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_SYS] = {
.base = IQS7222_SYS_SETUP,
.num_row = 1,
.num_col = 13,
},
},
},
{
.prod_num = IQS7222_PROD_NUM_B,
.fw_major = 1,
.fw_minor = 43,
.event_offset = 10,
.comms_offset = 11,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
.num_row = 1,
.num_col = 6,
},
[IQS7222_REG_GRP_CYCLE] = {
.base = 0x8000,
.num_row = 10,
.num_col = 2,
},
[IQS7222_REG_GRP_GLBL] = {
.base = 0x8A00,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_BTN] = {
.base = 0x9000,
.num_row = 20,
.num_col = 2,
},
[IQS7222_REG_GRP_CHAN] = {
.base = 0xB000,
.num_row = 20,
.num_col = 4,
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xC400,
.num_row = 1,
.num_col = 2,
},
[IQS7222_REG_GRP_SYS] = {
.base = IQS7222_SYS_SETUP,
.num_row = 1,
.num_col = 13,
},
},
},
{
.prod_num = IQS7222_PROD_NUM_B,
.fw_major = 1,
.fw_minor = 27,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
.num_row = 1,
.num_col = 6,
},
[IQS7222_REG_GRP_CYCLE] = {
.base = 0x8000,
.num_row = 10,
.num_col = 2,
},
[IQS7222_REG_GRP_GLBL] = {
.base = 0x8A00,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_BTN] = {
.base = 0x9000,
.num_row = 20,
.num_col = 2,
},
[IQS7222_REG_GRP_CHAN] = {
.base = 0xB000,
.num_row = 20,
.num_col = 4,
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xC400,
.num_row = 1,
.num_col = 2,
},
[IQS7222_REG_GRP_SYS] = {
.base = IQS7222_SYS_SETUP,
.num_row = 1,
.num_col = 10,
},
},
},
{
.prod_num = IQS7222_PROD_NUM_C,
.fw_major = 2,
.fw_minor = 6,
.sldr_res = U16_MAX,
.touch_link = 1686,
.wheel_enable = BIT(3),
.event_offset = 9,
.comms_offset = 10,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
.num_row = 1,
.num_col = 6,
},
[IQS7222_REG_GRP_CYCLE] = {
.base = 0x8000,
.num_row = 5,
.num_col = 3,
},
[IQS7222_REG_GRP_GLBL] = {
.base = 0x8500,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_BTN] = {
.base = 0x9000,
.num_row = 10,
.num_col = 3,
},
[IQS7222_REG_GRP_CHAN] = {
.base = 0xA000,
.num_row = 10,
.num_col = 6,
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAA00,
.num_row = 1,
.num_col = 2,
},
[IQS7222_REG_GRP_SLDR] = {
.base = 0xB000,
.num_row = 2,
.num_col = 10,
},
[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,
},
},
},
{
.prod_num = IQS7222_PROD_NUM_C,
.fw_major = 1,
.fw_minor = 13,
.sldr_res = U16_MAX,
.touch_link = 1674,
.wheel_enable = BIT(3),
.event_offset = 9,
.comms_offset = 10,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
.num_row = 1,
.num_col = 6,
},
[IQS7222_REG_GRP_CYCLE] = {
.base = 0x8000,
.num_row = 5,
.num_col = 3,
},
[IQS7222_REG_GRP_GLBL] = {
.base = 0x8500,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_BTN] = {
.base = 0x9000,
.num_row = 10,
.num_col = 3,
},
[IQS7222_REG_GRP_CHAN] = {
.base = 0xA000,
.num_row = 10,
.num_col = 6,
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAA00,
.num_row = 1,
.num_col = 2,
},
[IQS7222_REG_GRP_SLDR] = {
.base = 0xB000,
.num_row = 2,
.num_col = 10,
},
[IQS7222_REG_GRP_GPIO] = {
.base = 0xC000,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_SYS] = {
.base = IQS7222_SYS_SETUP,
.num_row = 1,
.num_col = 11,
},
},
},
};
struct iqs7222_prop_desc {
const char *name;
enum iqs7222_reg_grp_id reg_grp;
enum iqs7222_reg_key_id reg_key;
int reg_offset;
int reg_shift;
int reg_width;
int val_pitch;
int val_min;
int val_max;
bool invert;
const char *label;
};
static const struct iqs7222_prop_desc iqs7222_props[] = {
{
.name = "azoteq,conv-period",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 0,
.reg_shift = 8,
.reg_width = 8,
.label = "conversion period",
},
{
.name = "azoteq,conv-frac",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 0,
.reg_shift = 0,
.reg_width = 8,
.label = "conversion frequency fractional divider",
},
{
.name = "azoteq,rx-float-inactive",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 1,
.reg_shift = 6,
.reg_width = 1,
.invert = true,
},
{
.name = "azoteq,dead-time-enable",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 1,
.reg_shift = 5,
.reg_width = 1,
},
{
.name = "azoteq,tx-freq-fosc",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 1,
.reg_shift = 4,
.reg_width = 1,
},
{
.name = "azoteq,vbias-enable",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 1,
.reg_shift = 3,
.reg_width = 1,
},
{
.name = "azoteq,sense-mode",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 1,
.reg_shift = 0,
.reg_width = 3,
.val_max = 3,
.label = "sensing mode",
},
{
.name = "azoteq,iref-enable",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 2,
.reg_shift = 10,
.reg_width = 1,
},
{
.name = "azoteq,iref-level",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 2,
.reg_shift = 4,
.reg_width = 4,
.label = "current reference level",
},
{
.name = "azoteq,iref-trim",
.reg_grp = IQS7222_REG_GRP_CYCLE,
.reg_offset = 2,
.reg_shift = 0,
.reg_width = 4,
.label = "current reference trim",
},
{
.name = "azoteq,rf-filt-enable",
.reg_grp = IQS7222_REG_GRP_GLBL,
.reg_offset = 0,
.reg_shift = 15,
.reg_width = 1,
},
{
.name = "azoteq,max-counts",
.reg_grp = IQS7222_REG_GRP_GLBL,
.reg_offset = 0,
.reg_shift = 13,
.reg_width = 2,
.label = "maximum counts",
},
{
.name = "azoteq,auto-mode",
.reg_grp = IQS7222_REG_GRP_GLBL,
.reg_offset = 0,
.reg_shift = 2,
.reg_width = 2,
.label = "number of conversions",
},
{
.name = "azoteq,ati-frac-div-fine",
.reg_grp = IQS7222_REG_GRP_GLBL,
.reg_offset = 1,
.reg_shift = 9,
.reg_width = 5,
.label = "ATI fine fractional divider",
},
{
.name = "azoteq,ati-frac-div-coarse",
.reg_grp = IQS7222_REG_GRP_GLBL,
.reg_offset = 1,
.reg_shift = 0,
.reg_width = 5,
.label = "ATI coarse fractional divider",
},
{
.name = "azoteq,ati-comp-select",
.reg_grp = IQS7222_REG_GRP_GLBL,
.reg_offset = 2,
.reg_shift = 0,
.reg_width = 10,
.label = "ATI compensation selection",
},
{
.name = "azoteq,ati-band",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 0,
.reg_shift = 12,
.reg_width = 2,
.label = "ATI band",
},
{
.name = "azoteq,global-halt",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 0,
.reg_shift = 11,
.reg_width = 1,
},
{
.name = "azoteq,invert-enable",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 0,
.reg_shift = 10,
.reg_width = 1,
},
{
.name = "azoteq,dual-direction",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 0,
.reg_shift = 9,
.reg_width = 1,
},
{
.name = "azoteq,samp-cap-double",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 0,
.reg_shift = 3,
.reg_width = 1,
},
{
.name = "azoteq,vref-half",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 0,
.reg_shift = 2,
.reg_width = 1,
},
{
.name = "azoteq,proj-bias",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 0,
.reg_shift = 0,
.reg_width = 2,
.label = "projected bias current",
},
{
.name = "azoteq,ati-target",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 1,
.reg_shift = 8,
.reg_width = 8,
.val_pitch = 8,
.label = "ATI target",
},
{
.name = "azoteq,ati-base",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 1,
.reg_shift = 3,
.reg_width = 5,
.val_pitch = 16,
.label = "ATI base",
},
{
.name = "azoteq,ati-mode",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 1,
.reg_shift = 0,
.reg_width = 3,
.val_max = 5,
.label = "ATI mode",
},
{
.name = "azoteq,ati-frac-div-fine",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 2,
.reg_shift = 9,
.reg_width = 5,
.label = "ATI fine fractional divider",
},
{
.name = "azoteq,ati-frac-mult-coarse",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 2,
.reg_shift = 5,
.reg_width = 4,
.label = "ATI coarse fractional multiplier",
},
{
.name = "azoteq,ati-frac-div-coarse",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 2,
.reg_shift = 0,
.reg_width = 5,
.label = "ATI coarse fractional divider",
},
{
.name = "azoteq,ati-comp-div",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 3,
.reg_shift = 11,
.reg_width = 5,
.label = "ATI compensation divider",
},
{
.name = "azoteq,ati-comp-select",
.reg_grp = IQS7222_REG_GRP_CHAN,
.reg_offset = 3,
.reg_shift = 0,
.reg_width = 10,
.label = "ATI compensation selection",
},
{
.name = "azoteq,debounce-exit",
.reg_grp = IQS7222_REG_GRP_BTN,
.reg_key = IQS7222_REG_KEY_DEBOUNCE,
.reg_offset = 0,
.reg_shift = 12,
.reg_width = 4,
.label = "debounce exit factor",
},
{
.name = "azoteq,debounce-enter",
.reg_grp = IQS7222_REG_GRP_BTN,
.reg_key = IQS7222_REG_KEY_DEBOUNCE,
.reg_offset = 0,
.reg_shift = 8,
.reg_width = 4,
.label = "debounce entrance factor",
},
{
.name = "azoteq,thresh",
.reg_grp = IQS7222_REG_GRP_BTN,
.reg_key = IQS7222_REG_KEY_PROX,
.reg_offset = 0,
.reg_shift = 0,
.reg_width = 8,
.val_max = 127,
.label = "threshold",
},
{
.name = "azoteq,thresh",
.reg_grp = IQS7222_REG_GRP_BTN,
.reg_key = IQS7222_REG_KEY_TOUCH,
.reg_offset = 1,
.reg_shift = 0,
.reg_width = 8,
.label = "threshold",
},
{
.name = "azoteq,hyst",
.reg_grp = IQS7222_REG_GRP_BTN,
.reg_key = IQS7222_REG_KEY_TOUCH,
.reg_offset = 1,
.reg_shift = 8,
.reg_width = 8,
.label = "hysteresis",
},
{
.name = "azoteq,lta-beta-lp",
.reg_grp = IQS7222_REG_GRP_FILT,
.reg_offset = 0,
.reg_shift = 12,
.reg_width = 4,
.label = "low-power mode long-term average beta",
},
{
.name = "azoteq,lta-beta-np",
.reg_grp = IQS7222_REG_GRP_FILT,
.reg_offset = 0,
.reg_shift = 8,
.reg_width = 4,
.label = "normal-power mode long-term average beta",
},
{
.name = "azoteq,counts-beta-lp",
.reg_grp = IQS7222_REG_GRP_FILT,
.reg_offset = 0,
.reg_shift = 4,
.reg_width = 4,
.label = "low-power mode counts beta",
},
{
.name = "azoteq,counts-beta-np",
.reg_grp = IQS7222_REG_GRP_FILT,
.reg_offset = 0,
.reg_shift = 0,
.reg_width = 4,
.label = "normal-power mode counts beta",
},
{
.name = "azoteq,lta-fast-beta-lp",
.reg_grp = IQS7222_REG_GRP_FILT,
.reg_offset = 1,
.reg_shift = 4,
.reg_width = 4,
.label = "low-power mode long-term average fast beta",
},
{
.name = "azoteq,lta-fast-beta-np",
.reg_grp = IQS7222_REG_GRP_FILT,
.reg_offset = 1,
.reg_shift = 0,
.reg_width = 4,
.label = "normal-power mode long-term average fast beta",
},
{
.name = "azoteq,lower-cal",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_offset = 0,
.reg_shift = 8,
.reg_width = 8,
.label = "lower calibration",
},
{
.name = "azoteq,static-beta",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_NO_WHEEL,
.reg_offset = 0,
.reg_shift = 6,
.reg_width = 1,
},
{
.name = "azoteq,bottom-beta",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_NO_WHEEL,
.reg_offset = 0,
.reg_shift = 3,
.reg_width = 3,
.label = "bottom beta",
},
{
.name = "azoteq,static-beta",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_WHEEL,
.reg_offset = 0,
.reg_shift = 7,
.reg_width = 1,
},
{
.name = "azoteq,bottom-beta",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_WHEEL,
.reg_offset = 0,
.reg_shift = 4,
.reg_width = 3,
.label = "bottom beta",
},
{
.name = "azoteq,bottom-speed",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_offset = 1,
.reg_shift = 8,
.reg_width = 8,
.label = "bottom speed",
},
{
.name = "azoteq,upper-cal",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_offset = 1,
.reg_shift = 0,
.reg_width = 8,
.label = "upper calibration",
},
{
.name = "azoteq,gesture-max-ms",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_TAP,
.reg_offset = 9,
.reg_shift = 8,
.reg_width = 8,
.val_pitch = 4,
.label = "maximum gesture time",
},
{
.name = "azoteq,gesture-min-ms",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_TAP,
.reg_offset = 9,
.reg_shift = 3,
.reg_width = 5,
.val_pitch = 4,
.label = "minimum gesture time",
},
{
.name = "azoteq,gesture-dist",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_AXIAL,
.reg_offset = 10,
.reg_shift = 8,
.reg_width = 8,
.val_pitch = 16,
.label = "gesture distance",
},
{
.name = "azoteq,gesture-max-ms",
.reg_grp = IQS7222_REG_GRP_SLDR,
.reg_key = IQS7222_REG_KEY_AXIAL,
.reg_offset = 10,
.reg_shift = 0,
.reg_width = 8,
.val_pitch = 4,
.label = "maximum gesture time",
},
{
.name = "drive-open-drain",
.reg_grp = IQS7222_REG_GRP_GPIO,
.reg_offset = 0,
.reg_shift = 1,
.reg_width = 1,
},
{
.name = "azoteq,timeout-ati-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 1,
.reg_shift = 0,
.reg_width = 16,
.val_pitch = 500,
.label = "ATI error timeout",
},
{
.name = "azoteq,rate-ati-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 2,
.reg_shift = 0,
.reg_width = 16,
.label = "ATI report rate",
},
{
.name = "azoteq,timeout-np-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 3,
.reg_shift = 0,
.reg_width = 16,
.label = "normal-power mode timeout",
},
{
.name = "azoteq,rate-np-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 4,
.reg_shift = 0,
.reg_width = 16,
.val_max = 3000,
.label = "normal-power mode report rate",
},
{
.name = "azoteq,timeout-lp-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 5,
.reg_shift = 0,
.reg_width = 16,
.label = "low-power mode timeout",
},
{
.name = "azoteq,rate-lp-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 6,
.reg_shift = 0,
.reg_width = 16,
.val_max = 3000,
.label = "low-power mode report rate",
},
{
.name = "azoteq,timeout-ulp-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 7,
.reg_shift = 0,
.reg_width = 16,
.label = "ultra-low-power mode timeout",
},
{
.name = "azoteq,rate-ulp-ms",
.reg_grp = IQS7222_REG_GRP_SYS,
.reg_offset = 8,
.reg_shift = 0,
.reg_width = 16,
.val_max = 3000,
.label = "ultra-low-power mode report rate",
},
};
struct iqs7222_private {
const struct iqs7222_dev_desc *dev_desc;
struct gpio_desc *reset_gpio;
struct gpio_desc *irq_gpio;
struct i2c_client *client;
struct input_dev *keypad;
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];
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 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO];
u16 sys_setup[IQS7222_MAX_COLS_SYS];
};
static u16 *iqs7222_setup(struct iqs7222_private *iqs7222,
enum iqs7222_reg_grp_id reg_grp, int row)
{
switch (reg_grp) {
case IQS7222_REG_GRP_CYCLE:
return iqs7222->cycle_setup[row];
case IQS7222_REG_GRP_GLBL:
return iqs7222->glbl_setup;
case IQS7222_REG_GRP_BTN:
return iqs7222->btn_setup[row];
case IQS7222_REG_GRP_CHAN:
return iqs7222->chan_setup[row];
case IQS7222_REG_GRP_FILT:
return iqs7222->filt_setup;
case IQS7222_REG_GRP_SLDR:
return iqs7222->sldr_setup[row];
case IQS7222_REG_GRP_GPIO:
return iqs7222->gpio_setup[row];
case IQS7222_REG_GRP_SYS:
return iqs7222->sys_setup;
default:
return NULL;
}
}
static int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms)
{
ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms);
int ret;
do {
usleep_range(1000, 1100);
ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
if (ret < 0)
return ret;
else if (ret > 0)
return 0;
} while (ktime_compare(ktime_get(), irq_timeout) < 0);
return -EBUSY;
}
static int iqs7222_hard_reset(struct iqs7222_private *iqs7222)
{
struct i2c_client *client = iqs7222->client;
int error;
if (!iqs7222->reset_gpio)
return 0;
gpiod_set_value_cansleep(iqs7222->reset_gpio, 1);
usleep_range(1000, 1100);
gpiod_set_value_cansleep(iqs7222->reset_gpio, 0);
error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS);
if (error)
dev_err(&client->dev, "Failed to reset device: %d\n", error);
return error;
}
static int iqs7222_force_comms(struct iqs7222_private *iqs7222)
{
u8 msg_buf[] = { 0xFF, 0x00, };
int ret;
/*
* 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(iqs7222->irq_gpio);
if (ret < 0)
return ret;
else if (ret > 0)
return 0;
ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf));
if (ret < (int)sizeof(msg_buf)) {
if (ret >= 0)
ret = -EIO;
/*
* The datasheet states that the host must wait to retry any
* failed attempt to communicate over I2C.
*/
msleep(IQS7222_COMMS_RETRY_MS);
return ret;
}
return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS);
}
static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
u16 reg, void *val, u16 num_val)
{
u8 reg_buf[sizeof(__be16)];
int ret, i;
struct i2c_client *client = iqs7222->client;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.len = reg > U8_MAX ? sizeof(reg) : sizeof(u8),
.buf = reg_buf,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = num_val * sizeof(__le16),
.buf = (u8 *)val,
},
};
if (reg > U8_MAX)
put_unaligned_be16(reg, reg_buf);
else
*reg_buf = (u8)reg;
/*
* 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 < IQS7222_NUM_RETRIES; i++) {
ret = iqs7222_force_comms(iqs7222);
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(IQS7222_COMMS_RETRY_MS);
continue;
}
if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) {
ret = -ENODATA;
continue;
}
ret = 0;
break;
}
/*
* The following delay ensures the device has deasserted the RDY pin
* following the I2C stop condition.
*/
usleep_range(50, 100);
if (ret < 0)
dev_err(&client->dev,
"Failed to read from address 0x%04X: %d\n", reg, ret);
return ret;
}
static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
{
__le16 val_buf;
int error;
error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1);
if (error)
return error;
*val = le16_to_cpu(val_buf);
return 0;
}
static int iqs7222_write_burst(struct iqs7222_private *iqs7222,
u16 reg, const void *val, u16 num_val)
{
int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
int val_len = num_val * sizeof(__le16);
int msg_len = reg_len + val_len;
int ret, i;
struct i2c_client *client = iqs7222->client;
u8 *msg_buf;
msg_buf = kzalloc(msg_len, GFP_KERNEL);
if (!msg_buf)
return -ENOMEM;
if (reg > U8_MAX)
put_unaligned_be16(reg, msg_buf);
else
*msg_buf = (u8)reg;
memcpy(msg_buf + reg_len, 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 < IQS7222_NUM_RETRIES; i++) {
ret = iqs7222_force_comms(iqs7222);
if (ret < 0)
continue;
ret = i2c_master_send(client, msg_buf, msg_len);
if (ret < msg_len) {
if (ret >= 0)
ret = -EIO;
msleep(IQS7222_COMMS_RETRY_MS);
continue;
}
ret = 0;
break;
}
kfree(msg_buf);
usleep_range(50, 100);
if (ret < 0)
dev_err(&client->dev,
"Failed to write to address 0x%04X: %d\n", reg, ret);
return ret;
}
static int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val)
{
__le16 val_buf = cpu_to_le16(val);
return iqs7222_write_burst(iqs7222, reg, &val_buf, 1);
}
static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
{
struct i2c_client *client = iqs7222->client;
ktime_t ati_timeout;
u16 sys_status = 0;
u16 sys_setup = iqs7222->sys_setup[0] & ~IQS7222_SYS_SETUP_ACK_RESET;
int error, i;
for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
/*
* Trigger ATI from streaming and normal-power modes so that
* the RDY pin continues to be asserted during ATI.
*/
error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
sys_setup |
IQS7222_SYS_SETUP_REDO_ATI);
if (error)
return error;
ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS);
do {
error = iqs7222_irq_poll(iqs7222,
IQS7222_COMMS_TIMEOUT_MS);
if (error)
continue;
error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS,
&sys_status);
if (error)
return error;
if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE)
continue;
if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR)
break;
/*
* Use stream-in-touch mode if either slider reports
* absolute position.
*/
sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit)
? IQS7222_SYS_SETUP_INTF_MODE_TOUCH
: IQS7222_SYS_SETUP_INTF_MODE_EVENT;
sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO;
return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
sys_setup);
} while (ktime_compare(ktime_get(), ati_timeout) < 0);
dev_err(&client->dev,
"ATI attempt %d of %d failed with status 0x%02X, %s\n",
i + 1, IQS7222_NUM_RETRIES, (u8)sys_status,
i < IQS7222_NUM_RETRIES ? "retrying..." : "stopping");
}
return -ETIMEDOUT;
}
static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
{
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
int comms_offset = dev_desc->comms_offset;
int error, i, j, k;
/*
* Take advantage of the stop-bit disable function, if available, to
* save the trouble of having to reopen a communication window after
* each burst read or write.
*/
if (comms_offset) {
u16 comms_setup;
error = iqs7222_read_word(iqs7222,
IQS7222_SYS_SETUP + comms_offset,
&comms_setup);
if (error)
return error;
error = iqs7222_write_word(iqs7222,
IQS7222_SYS_SETUP + comms_offset,
comms_setup | IQS7222_COMMS_HOLD);
if (error)
return error;
}
for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
int num_row = dev_desc->reg_grps[i].num_row;
int num_col = dev_desc->reg_grps[i].num_col;
u16 reg = dev_desc->reg_grps[i].base;
__le16 *val_buf;
u16 *val;
if (!num_col)
continue;
val = iqs7222_setup(iqs7222, i, 0);
if (!val)
continue;
val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL);
if (!val_buf)
return -ENOMEM;
for (j = 0; j < num_row; j++) {
switch (dir) {
case READ:
error = iqs7222_read_burst(iqs7222, reg,
val_buf, num_col);
for (k = 0; k < num_col; k++)
val[k] = le16_to_cpu(val_buf[k]);
break;
case WRITE:
for (k = 0; k < num_col; k++)
val_buf[k] = cpu_to_le16(val[k]);
error = iqs7222_write_burst(iqs7222, reg,
val_buf, num_col);
break;
default:
error = -EINVAL;
}
if (error)
break;
reg += IQS7222_REG_OFFSET;
val += iqs7222_max_cols[i];
}
kfree(val_buf);
if (error)
return error;
}
if (comms_offset) {
u16 comms_setup;
error = iqs7222_read_word(iqs7222,
IQS7222_SYS_SETUP + comms_offset,
&comms_setup);
if (error)
return error;
error = iqs7222_write_word(iqs7222,
IQS7222_SYS_SETUP + comms_offset,
comms_setup & ~IQS7222_COMMS_HOLD);
if (error)
return error;
}
if (dir == READ)
return 0;
return iqs7222_ati_trigger(iqs7222);
}
static int iqs7222_dev_info(struct iqs7222_private *iqs7222)
{
struct i2c_client *client = iqs7222->client;
bool prod_num_valid = false;
__le16 dev_id[3];
int error, i;
error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
ARRAY_SIZE(dev_id));
if (error)
return error;
for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) {
if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num)
continue;
prod_num_valid = true;
if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major)
continue;
if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor)
continue;
iqs7222->dev_desc = &iqs7222_devs[i];
return 0;
}
if (prod_num_valid)
dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n",
le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2]));
else
dev_err(&client->dev, "Unrecognized product number: %u\n",
le16_to_cpu(dev_id[0]));
return -EINVAL;
}
static int iqs7222_gpio_select(struct iqs7222_private *iqs7222,
struct fwnode_handle *child_node,
int child_enable, u16 child_link)
{
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
struct i2c_client *client = iqs7222->client;
int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row;
int error, count, i;
unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)];
if (!num_gpio)
return 0;
if (!fwnode_property_present(child_node, "azoteq,gpio-select"))
return 0;
count = fwnode_property_count_u32(child_node, "azoteq,gpio-select");
if (count > num_gpio) {
dev_err(&client->dev, "Invalid number of %s GPIOs\n",
fwnode_get_name(child_node));
return -EINVAL;
} else if (count < 0) {
dev_err(&client->dev, "Failed to count %s GPIOs: %d\n",
fwnode_get_name(child_node), count);
return count;
}
error = fwnode_property_read_u32_array(child_node,
"azoteq,gpio-select",
gpio_sel, count);
if (error) {
dev_err(&client->dev, "Failed to read %s GPIOs: %d\n",
fwnode_get_name(child_node), error);
return error;
}
for (i = 0; i < count; i++) {
u16 *gpio_setup;
if (gpio_sel[i] >= num_gpio) {
dev_err(&client->dev, "Invalid %s GPIO: %u\n",
fwnode_get_name(child_node), gpio_sel[i]);
return -EINVAL;
}
gpio_setup = iqs7222->gpio_setup[gpio_sel[i]];
if (gpio_setup[2] && child_link != gpio_setup[2]) {
dev_err(&client->dev,
"Conflicting GPIO %u event types\n",
gpio_sel[i]);
return -EINVAL;
}
gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN;
gpio_setup[1] |= child_enable;
gpio_setup[2] = child_link;
}
return 0;
}
static int iqs7222_parse_props(struct iqs7222_private *iqs7222,
struct fwnode_handle **child_node,
int child_index,
enum iqs7222_reg_grp_id reg_grp,
enum iqs7222_reg_key_id reg_key)
{
u16 *setup = iqs7222_setup(iqs7222, reg_grp, child_index);
struct i2c_client *client = iqs7222->client;
struct fwnode_handle *reg_grp_node;
char reg_grp_name[16];
int i;
switch (reg_grp) {
case IQS7222_REG_GRP_CYCLE:
case IQS7222_REG_GRP_CHAN:
case IQS7222_REG_GRP_SLDR:
case IQS7222_REG_GRP_GPIO:
case IQS7222_REG_GRP_BTN:
/*
* These groups derive a child node and return it to the caller
* for additional group-specific processing. In some cases, the
* child node may have already been derived.
*/
reg_grp_node = *child_node;
if (reg_grp_node)
break;
snprintf(reg_grp_name, sizeof(reg_grp_name), "%s-%d",
iqs7222_reg_grp_names[reg_grp], child_index);
reg_grp_node = device_get_named_child_node(&client->dev,
reg_grp_name);
if (!reg_grp_node)
return 0;
*child_node = reg_grp_node;
break;
case IQS7222_REG_GRP_GLBL:
case IQS7222_REG_GRP_FILT:
case IQS7222_REG_GRP_SYS:
/*
* These groups are not organized beneath a child node, nor are
* they subject to any additional processing by the caller.
*/
reg_grp_node = dev_fwnode(&client->dev);
break;
default:
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) {
const char *name = iqs7222_props[i].name;
int reg_offset = iqs7222_props[i].reg_offset;
int reg_shift = iqs7222_props[i].reg_shift;
int reg_width = iqs7222_props[i].reg_width;
int val_pitch = iqs7222_props[i].val_pitch ? : 1;
int val_min = iqs7222_props[i].val_min;
int val_max = iqs7222_props[i].val_max;
bool invert = iqs7222_props[i].invert;
const char *label = iqs7222_props[i].label ? : name;
unsigned int val;
int error;
if (iqs7222_props[i].reg_grp != reg_grp ||
iqs7222_props[i].reg_key != reg_key)
continue;
/*
* Boolean register fields are one bit wide; they are forcibly
* reset to provide a means to undo changes by a bootloader if
* necessary.
*
* Scalar fields, on the other hand, are left untouched unless
* their corresponding properties are present.
*/
if (reg_width == 1) {
if (invert)
setup[reg_offset] |= BIT(reg_shift);
else
setup[reg_offset] &= ~BIT(reg_shift);
}
if (!fwnode_property_present(reg_grp_node, name))
continue;
if (reg_width == 1) {
if (invert)
setup[reg_offset] &= ~BIT(reg_shift);
else
setup[reg_offset] |= BIT(reg_shift);
continue;
}
error = fwnode_property_read_u32(reg_grp_node, name, &val);
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 %s: %u\n",
fwnode_get_name(reg_grp_node), label, val);
return -EINVAL;
}
setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1,
reg_shift);
setup[reg_offset] |= (val / val_pitch << reg_shift);
}
return 0;
}
static int iqs7222_parse_cycle(struct iqs7222_private *iqs7222, int cycle_index)
{
u16 *cycle_setup = iqs7222->cycle_setup[cycle_index];
struct i2c_client *client = iqs7222->client;
struct fwnode_handle *cycle_node = NULL;
unsigned int pins[9];
int error, count, i;
/*
* Each channel shares a cycle with one other channel; the mapping of
* channels to cycles is fixed. Properties defined for a cycle impact
* both channels tied to the cycle.
*/
error = iqs7222_parse_props(iqs7222, &cycle_node, cycle_index,
IQS7222_REG_GRP_CYCLE,
IQS7222_REG_KEY_NONE);
if (error)
return error;
if (!cycle_node)
return 0;
/*
* Unlike channels which are restricted to a select range of CRx pins
* based on channel number, any cycle can claim any of the device's 9
* CTx pins (CTx0-8).
*/
if (!fwnode_property_present(cycle_node, "azoteq,tx-enable"))
return 0;
count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable");
if (count < 0) {
dev_err(&client->dev, "Failed to count %s CTx pins: %d\n",
fwnode_get_name(cycle_node), count);
return count;
} else if (count > ARRAY_SIZE(pins)) {
dev_err(&client->dev, "Invalid number of %s CTx pins\n",
fwnode_get_name(cycle_node));
return -EINVAL;
}
error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable",
pins, count);
if (error) {
dev_err(&client->dev, "Failed to read %s CTx pins: %d\n",
fwnode_get_name(cycle_node), error);
return error;
}
cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7);
for (i = 0; i < count; i++) {
if (pins[i] > 8) {
dev_err(&client->dev, "Invalid %s CTx pin: %u\n",
fwnode_get_name(cycle_node), pins[i]);
return -EINVAL;
}
cycle_setup[1] |= BIT(pins[i] + 7);
}
return 0;
}
static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, int chan_index)
{
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
struct i2c_client *client = iqs7222->client;
struct fwnode_handle *chan_node = NULL;
int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
int ext_chan = rounddown(num_chan, 10);
int error, i;
u16 *chan_setup = iqs7222->chan_setup[chan_index];
u16 *sys_setup = iqs7222->sys_setup;
unsigned int val;
error = iqs7222_parse_props(iqs7222, &chan_node, chan_index,
IQS7222_REG_GRP_CHAN,
IQS7222_REG_KEY_NONE);
if (error)
return error;
if (!chan_node)
return 0;
if (dev_desc->allow_offset) {
sys_setup[dev_desc->allow_offset] |= BIT(chan_index);
if (fwnode_property_present(chan_node, "azoteq,ulp-allow"))
sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index);
}
chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN;
/*
* The reference channel function allows for differential measurements
* and is only available in the case of IQS7222A or IQS7222C.
*/
if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 &&
fwnode_property_present(chan_node, "azoteq,ref-select")) {
u16 *ref_setup;
error = fwnode_property_read_u32(chan_node, "azoteq,ref-select",
&val);
if (error) {
dev_err(&client->dev,
"Failed to read %s reference channel: %d\n",
fwnode_get_name(chan_node), error);
return error;
}
if (val >= ext_chan) {
dev_err(&client->dev,
"Invalid %s reference channel: %u\n",
fwnode_get_name(chan_node), val);
return -EINVAL;
}
ref_setup = iqs7222->chan_setup[val];
/*
* Configure the current channel as a follower of the selected
* reference channel.
*/
chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW;
chan_setup[4] = val * 42 + 1048;
if (!fwnode_property_read_u32(chan_node, "azoteq,ref-weight",
&val)) {
if (val > U16_MAX) {
dev_err(&client->dev,
"Invalid %s reference weight: %u\n",
fwnode_get_name(chan_node), val);
return -EINVAL;
}
chan_setup[5] = val;
}
/*
* Configure the selected channel as a reference channel which
* serves the current channel.
*/
ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
ref_setup[5] |= BIT(chan_index);
ref_setup[4] = dev_desc->touch_link;
if (fwnode_property_present(chan_node, "azoteq,use-prox"))
ref_setup[4] -= 2;
}
if (fwnode_property_present(chan_node, "azoteq,rx-enable")) {
/*
* Each channel can claim up to 4 CRx pins. The first half of
* the channels can use CRx0-3, while the second half can use
* CRx4-7.
*/
unsigned int pins[4];
int count;
count = fwnode_property_count_u32(chan_node,
"azoteq,rx-enable");
if (count < 0) {
dev_err(&client->dev,
"Failed to count %s CRx pins: %d\n",
fwnode_get_name(chan_node), count);
return count;
} else if (count > ARRAY_SIZE(pins)) {
dev_err(&client->dev,
"Invalid number of %s CRx pins\n",
fwnode_get_name(chan_node));
return -EINVAL;
}
error = fwnode_property_read_u32_array(chan_node,
"azoteq,rx-enable",
pins, count);
if (error) {
dev_err(&client->dev,
"Failed to read %s CRx pins: %d\n",
fwnode_get_name(chan_node), error);
return error;
}
chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4);
for (i = 0; i < count; i++) {
int min_crx = chan_index < ext_chan / 2 ? 0 : 4;
if (pins[i] < min_crx || pins[i] > min_crx + 3) {
dev_err(&client->dev,
"Invalid %s CRx pin: %u\n",
fwnode_get_name(chan_node), pins[i]);
return -EINVAL;
}
chan_setup[0] |= BIT(pins[i] + 4 - min_crx);
}
}
for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) {
const char *event_name = iqs7222_kp_events[i].name;
u16 event_enable = iqs7222_kp_events[i].enable;
struct fwnode_handle *event_node;
event_node = fwnode_get_named_child_node(chan_node, event_name);
if (!event_node)
continue;
error = iqs7222_parse_props(iqs7222, &event_node, chan_index,
IQS7222_REG_GRP_BTN,
iqs7222_kp_events[i].reg_key);
if (error)
return error;
error = iqs7222_gpio_select(iqs7222, event_node,
BIT(chan_index),
dev_desc->touch_link - (i ? 0 : 2));
if (error)
return error;
if (!fwnode_property_read_u32(event_node,
"azoteq,timeout-press-ms",
&val)) {
/*
* The IQS7222B employs a global pair of press timeout
* registers as opposed to channel-specific registers.
*/
u16 *setup = dev_desc->reg_grps
[IQS7222_REG_GRP_BTN].num_col > 2 ?
&iqs7222->btn_setup[chan_index][2] :
&sys_setup[9];
if (val > U8_MAX * 500) {
dev_err(&client->dev,
"Invalid %s press timeout: %u\n",
fwnode_get_name(chan_node), val);
return -EINVAL;
}
*setup &= ~(U8_MAX << i * 8);
*setup |= (val / 500 << i * 8);
}
error = fwnode_property_read_u32(event_node, "linux,code",
&val);
if (error) {
dev_err(&client->dev, "Failed to read %s code: %d\n",
fwnode_get_name(chan_node), error);
return error;
}
iqs7222->kp_code[chan_index][i] = val;
iqs7222->kp_type[chan_index][i] = EV_KEY;
if (fwnode_property_present(event_node, "linux,input-type")) {
error = fwnode_property_read_u32(event_node,
"linux,input-type",
&val);
if (error) {
dev_err(&client->dev,
"Failed to read %s input type: %d\n",
fwnode_get_name(chan_node), error);
return error;
}
if (val != EV_KEY && val != EV_SW) {
dev_err(&client->dev,
"Invalid %s input type: %u\n",
fwnode_get_name(chan_node), val);
return -EINVAL;
}
iqs7222->kp_type[chan_index][i] = val;
}
/*
* Reference channels can opt out of event reporting by using
* KEY_RESERVED in place of a true key or switch code.
*/
if (iqs7222->kp_type[chan_index][i] == EV_KEY &&
iqs7222->kp_code[chan_index][i] == KEY_RESERVED)
continue;
input_set_capability(iqs7222->keypad,
iqs7222->kp_type[chan_index][i],
iqs7222->kp_code[chan_index][i]);
if (!dev_desc->event_offset)
continue;
sys_setup[dev_desc->event_offset] |= event_enable;
}
/*
* The following call handles a special pair of properties that apply
* to a channel node, but reside within the button (event) group.
*/
return iqs7222_parse_props(iqs7222, &chan_node, chan_index,
IQS7222_REG_GRP_BTN,
IQS7222_REG_KEY_DEBOUNCE);
}
static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index)
{
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
struct i2c_client *client = iqs7222->client;
struct fwnode_handle *sldr_node = NULL;
int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
int ext_chan = rounddown(num_chan, 10);
int count, error, reg_offset, i;
u16 *sldr_setup = iqs7222->sldr_setup[sldr_index];
u16 *sys_setup = iqs7222->sys_setup;
unsigned int chan_sel[4], val;
error = iqs7222_parse_props(iqs7222, &sldr_node, sldr_index,
IQS7222_REG_GRP_SLDR,
IQS7222_REG_KEY_NONE);
if (error)
return error;
if (!sldr_node)
return 0;
/*
* Each slider can be spread across 3 to 4 channels. It is possible to
* select only 2 channels, but doing so prevents the slider from using
* the specified resolution.
*/
count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select");
if (count < 0) {
dev_err(&client->dev, "Failed to count %s channels: %d\n",
fwnode_get_name(sldr_node), count);
return count;
} else if (count < 3 || count > ARRAY_SIZE(chan_sel)) {
dev_err(&client->dev, "Invalid number of %s channels\n",
fwnode_get_name(sldr_node));
return -EINVAL;
}
error = fwnode_property_read_u32_array(sldr_node,
"azoteq,channel-select",
chan_sel, count);
if (error) {
dev_err(&client->dev, "Failed to read %s channels: %d\n",
fwnode_get_name(sldr_node), error);
return error;
}
/*
* Resolution and top speed, if small enough, are packed into a single
* register. Otherwise, each occupies its own register and the rest of
* the slider-related register addresses are offset by one.
*/
reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1;
sldr_setup[0] |= count;
sldr_setup[3 + reg_offset] &= ~IQS7222_SLDR_SETUP_3_CHAN_SEL_MASK;
for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
sldr_setup[5 + reg_offset + i] = 0;
if (i >= count)
continue;
if (chan_sel[i] >= ext_chan) {
dev_err(&client->dev, "Invalid %s channel: %u\n",
fwnode_get_name(sldr_node), chan_sel[i]);
return -EINVAL;
}
/*
* The following fields indicate which channels participate in
* the slider, as well as each channel's relative placement.
*/
sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]);
sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080;
}
sldr_setup[4 + reg_offset] = dev_desc->touch_link;
if (fwnode_property_present(sldr_node, "azoteq,use-prox"))
sldr_setup[4 + reg_offset] -= 2;
if (!fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val)) {
if (!val || val > dev_desc->sldr_res) {
dev_err(&client->dev, "Invalid %s size: %u\n",
fwnode_get_name(sldr_node), val);
return -EINVAL;
}
if (reg_offset) {
sldr_setup[3] = val;
} else {
sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK;
sldr_setup[2] |= (val / 16 <<
IQS7222_SLDR_SETUP_2_RES_SHIFT);
}
}
if (!fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val)) {
if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) {
dev_err(&client->dev, "Invalid %s top speed: %u\n",
fwnode_get_name(sldr_node), val);
return -EINVAL;
}
if (reg_offset) {
sldr_setup[2] = val;
} else {
sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK;
sldr_setup[2] |= (val / 4);
}
}
if (!fwnode_property_read_u32(sldr_node, "linux,axis", &val)) {
u16 sldr_max = sldr_setup[3] - 1;
if (!reg_offset) {
sldr_max = sldr_setup[2];
sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK;
sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT;
sldr_max = sldr_max * 16 - 1;
}
input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0);
iqs7222->sl_axis[sldr_index] = val;
}
if (dev_desc->wheel_enable) {
sldr_setup[0] &= ~dev_desc->wheel_enable;
if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL)
sldr_setup[0] |= dev_desc->wheel_enable;
}
for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) {
const char *event_name = iqs7222_sl_events[i].name;
struct fwnode_handle *event_node;
/*
* The absence of a register offset means the remaining fields
* in the group represent gesture settings.
*/
if (iqs7222_sl_events[i].enable && !reg_offset)
sldr_setup[9] &= ~iqs7222_sl_events[i].enable;
event_node = fwnode_get_named_child_node(sldr_node, event_name);
if (!event_node)
continue;
error = iqs7222_parse_props(iqs7222, &event_node, sldr_index,
IQS7222_REG_GRP_SLDR,
reg_offset ?
IQS7222_REG_KEY_RESERVED :
iqs7222_sl_events[i].reg_key);
if (error)
return error;
error = fwnode_property_read_u32(event_node, "linux,code",
&val);
if (error) {
dev_err(&client->dev, "Failed to read %s code: %d\n",
fwnode_get_name(sldr_node), error);
return error;
}
iqs7222->sl_code[sldr_index][i] = val;
input_set_capability(iqs7222->keypad, EV_KEY, val);
/*
* The press/release event is determined based on whether the
* coordinate field reports 0xFFFF and has no explicit enable
* control.
*/
if (!iqs7222_sl_events[i].enable || reg_offset)
continue;
sldr_setup[9] |= iqs7222_sl_events[i].enable;
error = iqs7222_gpio_select(iqs7222, event_node,
iqs7222_sl_events[i].enable,
1568 + sldr_index * 30);
if (error)
return error;
if (!dev_desc->event_offset)
continue;
sys_setup[dev_desc->event_offset] |= BIT(10 + sldr_index);
}
/*
* The following call handles a special pair of properties that shift
* to make room for a wheel enable control in the case of IQS7222C.
*/
return iqs7222_parse_props(iqs7222, &sldr_node, sldr_index,
IQS7222_REG_GRP_SLDR,
dev_desc->wheel_enable ?
IQS7222_REG_KEY_WHEEL :
IQS7222_REG_KEY_NO_WHEEL);
}
static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
{
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps;
u16 *sys_setup = iqs7222->sys_setup;
int error, i;
if (dev_desc->event_offset)
sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI;
for (i = 0; i < reg_grps[IQS7222_REG_GRP_CYCLE].num_row; i++) {
error = iqs7222_parse_cycle(iqs7222, i);
if (error)
return error;
}
error = iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_GLBL,
IQS7222_REG_KEY_NONE);
if (error)
return error;
for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) {
struct fwnode_handle *gpio_node = NULL;
u16 *gpio_setup = iqs7222->gpio_setup[i];
int j;
gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN;
gpio_setup[1] = 0;
gpio_setup[2] = 0;
error = iqs7222_parse_props(iqs7222, &gpio_node, i,
IQS7222_REG_GRP_GPIO,
IQS7222_REG_KEY_NONE);
if (error)
return error;
if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1)
continue;
/*
* The IQS7222C exposes 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]);
gpio_setup[0] |= BIT(iqs7222_gpio_links[i]);
}
for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
u16 *chan_setup = iqs7222->chan_setup[i];
chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK;
chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN;
chan_setup[5] = 0;
}
for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
error = iqs7222_parse_chan(iqs7222, i);
if (error)
return error;
}
error = iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_FILT,
IQS7222_REG_KEY_NONE);
if (error)
return error;
for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
u16 *sldr_setup = iqs7222->sldr_setup[i];
sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK;
error = iqs7222_parse_sldr(iqs7222, i);
if (error)
return error;
}
sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
sys_setup[0] |= IQS7222_SYS_SETUP_ACK_RESET;
return iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_SYS,
IQS7222_REG_KEY_NONE);
}
static int iqs7222_report(struct iqs7222_private *iqs7222)
{
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
struct i2c_client *client = iqs7222->client;
int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
int num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col;
int error, i, j;
__le16 status[IQS7222_MAX_COLS_STAT];
error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
num_stat);
if (error)
return error;
if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) {
dev_err(&client->dev, "Unexpected device reset\n");
return iqs7222_dev_init(iqs7222, WRITE);
}
if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) {
dev_err(&client->dev, "Unexpected ATI error\n");
return iqs7222_ati_trigger(iqs7222);
}
if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE)
return 0;
for (i = 0; i < num_chan; i++) {
u16 *chan_setup = iqs7222->chan_setup[i];
if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN))
continue;
for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) {
/*
* Proximity state begins at offset 2 and spills into
* offset 3 for devices with more than 16 channels.
*
* Touch state begins at the first offset immediately
* following proximity state.
*/
int k = 2 + j * (num_chan > 16 ? 2 : 1);
u16 state = le16_to_cpu(status[k + i / 16]);
input_event(iqs7222->keypad,
iqs7222->kp_type[i][j],
iqs7222->kp_code[i][j],
!!(state & BIT(i % 16)));
}
}
for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
u16 *sldr_setup = iqs7222->sldr_setup[i];
u16 sldr_pos = le16_to_cpu(status[4 + i]);
u16 state = le16_to_cpu(status[6 + i]);
if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK))
continue;
if (sldr_pos < dev_desc->sldr_res)
input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i],
sldr_pos);
for (j = 0; j < ARRAY_SIZE(iqs7222_sl_events); j++) {
u16 mask = iqs7222_sl_events[j].mask;
u16 val = iqs7222_sl_events[j].val;
if (!iqs7222_sl_events[j].enable) {
input_report_key(iqs7222->keypad,
iqs7222->sl_code[i][j],
sldr_pos < dev_desc->sldr_res);
continue;
}
/*
* The remaining offsets represent gesture state, and
* are discarded in the case of IQS7222C because only
* absolute position is reported.
*/
if (num_stat < IQS7222_MAX_COLS_STAT)
continue;
input_report_key(iqs7222->keypad,
iqs7222->sl_code[i][j],
(state & mask) == val);
}
}
input_sync(iqs7222->keypad);
return 0;
}
static irqreturn_t iqs7222_irq(int irq, void *context)
{
struct iqs7222_private *iqs7222 = context;
return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED;
}
static int iqs7222_probe(struct i2c_client *client)
{
struct iqs7222_private *iqs7222;
unsigned long irq_flags;
int error, irq;
iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL);
if (!iqs7222)
return -ENOMEM;
i2c_set_clientdata(client, iqs7222);
iqs7222->client = client;
iqs7222->keypad = devm_input_allocate_device(&client->dev);
if (!iqs7222->keypad)
return -ENOMEM;
iqs7222->keypad->name = client->name;
iqs7222->keypad->id.bustype = BUS_I2C;
/*
* 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.
*/
iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN);
if (IS_ERR(iqs7222->irq_gpio)) {
error = PTR_ERR(iqs7222->irq_gpio);
dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
error);
return error;
}
iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(iqs7222->reset_gpio)) {
error = PTR_ERR(iqs7222->reset_gpio);
dev_err(&client->dev, "Failed to request reset GPIO: %d\n",
error);
return error;
}
error = iqs7222_hard_reset(iqs7222);
if (error)
return error;
error = iqs7222_dev_info(iqs7222);
if (error)
return error;
error = iqs7222_dev_init(iqs7222, READ);
if (error)
return error;
error = iqs7222_parse_all(iqs7222);
if (error)
return error;
error = iqs7222_dev_init(iqs7222, WRITE);
if (error)
return error;
error = iqs7222_report(iqs7222);
if (error)
return error;
error = input_register_device(iqs7222->keypad);
if (error) {
dev_err(&client->dev, "Failed to register device: %d\n", error);
return error;
}
irq = gpiod_to_irq(iqs7222->irq_gpio);
if (irq < 0)
return irq;
irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW
: IRQF_TRIGGER_HIGH;
irq_flags |= IRQF_ONESHOT;
error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq,
irq_flags, client->name, iqs7222);
if (error)
dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
return error;
}
static const struct of_device_id iqs7222_of_match[] = {
{ .compatible = "azoteq,iqs7222a" },
{ .compatible = "azoteq,iqs7222b" },
{ .compatible = "azoteq,iqs7222c" },
{ }
};
MODULE_DEVICE_TABLE(of, iqs7222_of_match);
static struct i2c_driver iqs7222_i2c_driver = {
.driver = {
.name = "iqs7222",
.of_match_table = iqs7222_of_match,
},
.probe_new = iqs7222_probe,
};
module_i2c_driver(iqs7222_i2c_driver);
MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
MODULE_DESCRIPTION("Azoteq IQS7222A/B/C Capacitive Touch Controller");
MODULE_LICENSE("GPL");
......@@ -9,9 +9,11 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/log2.h>
#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>
......@@ -19,6 +21,16 @@
#define PON_REV2 0x01
#define PON_SUBTYPE 0x05
#define PON_SUBTYPE_PRIMARY 0x01
#define PON_SUBTYPE_SECONDARY 0x02
#define PON_SUBTYPE_1REG 0x03
#define PON_SUBTYPE_GEN2_PRIMARY 0x04
#define PON_SUBTYPE_GEN2_SECONDARY 0x05
#define PON_SUBTYPE_GEN3_PBS 0x08
#define PON_SUBTYPE_GEN3_HLOS 0x09
#define PON_RT_STS 0x10
#define PON_KPDPWR_N_SET BIT(0)
#define PON_RESIN_N_SET BIT(1)
......@@ -45,6 +57,7 @@ struct pm8941_data {
unsigned int status_bit;
bool supports_ps_hold_poff_config;
bool supports_debounce_config;
bool has_pon_pbs;
const char *name;
const char *phys;
};
......@@ -53,13 +66,18 @@ struct pm8941_pwrkey {
struct device *dev;
int irq;
u32 baseaddr;
u32 pon_pbs_baseaddr;
struct regmap *regmap;
struct input_dev *input;
unsigned int revision;
unsigned int subtype;
struct notifier_block reboot_notifier;
u32 code;
u32 sw_debounce_time_us;
ktime_t sw_debounce_end_time;
bool last_status;
const struct pm8941_data *data;
};
......@@ -129,20 +147,76 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
{
struct pm8941_pwrkey *pwrkey = _data;
unsigned int sts;
int error;
int err;
error = regmap_read(pwrkey->regmap,
pwrkey->baseaddr + PON_RT_STS, &sts);
if (error)
if (pwrkey->sw_debounce_time_us) {
if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) {
dev_dbg(pwrkey->dev,
"ignoring key event received before debounce end %llu us\n",
pwrkey->sw_debounce_end_time);
return IRQ_HANDLED;
}
}
err = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_RT_STS, &sts);
if (err)
return IRQ_HANDLED;
input_report_key(pwrkey->input, pwrkey->code,
sts & pwrkey->data->status_bit);
sts &= pwrkey->data->status_bit;
if (pwrkey->sw_debounce_time_us && !sts)
pwrkey->sw_debounce_end_time = ktime_add_us(ktime_get(),
pwrkey->sw_debounce_time_us);
/*
* Simulate a press event in case a release event occurred without a
* corresponding press event.
*/
if (!pwrkey->last_status && !sts) {
input_report_key(pwrkey->input, pwrkey->code, 1);
input_sync(pwrkey->input);
}
pwrkey->last_status = sts;
input_report_key(pwrkey->input, pwrkey->code, sts);
input_sync(pwrkey->input);
return IRQ_HANDLED;
}
static int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey)
{
unsigned int val, addr, mask;
int error;
if (pwrkey->data->has_pon_pbs && !pwrkey->pon_pbs_baseaddr) {
dev_err(pwrkey->dev,
"PON_PBS address missing, can't read HW debounce time\n");
return 0;
}
if (pwrkey->pon_pbs_baseaddr)
addr = pwrkey->pon_pbs_baseaddr + PON_DBC_CTL;
else
addr = pwrkey->baseaddr + PON_DBC_CTL;
error = regmap_read(pwrkey->regmap, addr, &val);
if (error)
return error;
if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY)
mask = 0xf;
else
mask = 0x7;
pwrkey->sw_debounce_time_us =
2 * USEC_PER_SEC / (1 << (mask - (val & mask)));
dev_dbg(pwrkey->dev, "SW debounce time = %u us\n",
pwrkey->sw_debounce_time_us);
return 0;
}
static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
......@@ -171,6 +245,8 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
struct pm8941_pwrkey *pwrkey;
bool pull_up;
struct device *parent;
struct device_node *regmap_node;
const __be32 *addr;
u32 req_delay;
int error;
......@@ -192,8 +268,10 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
pwrkey->data = of_device_get_match_data(&pdev->dev);
parent = pdev->dev.parent;
regmap_node = pdev->dev.of_node;
pwrkey->regmap = dev_get_regmap(parent, NULL);
if (!pwrkey->regmap) {
regmap_node = parent->of_node;
/*
* We failed to get regmap for parent. Let's see if we are
* a child of pon node and read regmap and reg from its
......@@ -204,15 +282,21 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to locate regmap\n");
return -ENODEV;
}
}
error = of_property_read_u32(parent->of_node,
"reg", &pwrkey->baseaddr);
} else {
error = of_property_read_u32(pdev->dev.of_node, "reg",
&pwrkey->baseaddr);
addr = of_get_address(regmap_node, 0, NULL, NULL);
if (!addr) {
dev_err(&pdev->dev, "reg property missing\n");
return -EINVAL;
}
pwrkey->baseaddr = be32_to_cpup(addr);
if (pwrkey->data->has_pon_pbs) {
/* PON_PBS base address is optional */
addr = of_get_address(regmap_node, 1, NULL, NULL);
if (addr)
pwrkey->pon_pbs_baseaddr = be32_to_cpup(addr);
}
if (error)
return error;
pwrkey->irq = platform_get_irq(pdev, 0);
if (pwrkey->irq < 0)
......@@ -221,7 +305,14 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2,
&pwrkey->revision);
if (error) {
dev_err(&pdev->dev, "failed to set debounce: %d\n", error);
dev_err(&pdev->dev, "failed to read revision: %d\n", error);
return error;
}
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_SUBTYPE,
&pwrkey->subtype);
if (error) {
dev_err(&pdev->dev, "failed to read subtype: %d\n", error);
return error;
}
......@@ -259,6 +350,10 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
}
}
error = pm8941_pwrkey_sw_debounce_init(pwrkey);
if (error)
return error;
if (pwrkey->data->pull_up_bit) {
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + PON_PULL_CTL,
......@@ -320,6 +415,7 @@ static const struct pm8941_data pwrkey_data = {
.phys = "pm8941_pwrkey/input0",
.supports_ps_hold_poff_config = true,
.supports_debounce_config = true,
.has_pon_pbs = false,
};
static const struct pm8941_data resin_data = {
......@@ -329,6 +425,7 @@ static const struct pm8941_data resin_data = {
.phys = "pm8941_resin/input0",
.supports_ps_hold_poff_config = true,
.supports_debounce_config = true,
.has_pon_pbs = false,
};
static const struct pm8941_data pon_gen3_pwrkey_data = {
......@@ -337,6 +434,7 @@ static const struct pm8941_data pon_gen3_pwrkey_data = {
.phys = "pmic_pwrkey/input0",
.supports_ps_hold_poff_config = false,
.supports_debounce_config = false,
.has_pon_pbs = true,
};
static const struct pm8941_data pon_gen3_resin_data = {
......@@ -345,6 +443,7 @@ static const struct pm8941_data pon_gen3_resin_data = {
.phys = "pmic_resin/input0",
.supports_ps_hold_poff_config = false,
.supports_debounce_config = false,
.has_pon_pbs = true,
};
static const struct of_device_id pm8941_pwr_key_id_table[] = {
......
......@@ -205,6 +205,7 @@ static int bbc_beep_probe(struct platform_device *op)
info = &state->u.bbc;
info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
of_node_put(dp);
if (!info->clock_freq)
goto out_free;
......
......@@ -696,7 +696,7 @@ int cypress_init(struct psmouse *psmouse)
err_exit:
/*
* Reset Cypress Trackpad as a standard mouse. Then
* let psmouse driver commmunicating with it as default PS2 mouse.
* let psmouse driver communicating with it as default PS2 mouse.
*/
cypress_reset(psmouse);
......
......@@ -26,6 +26,8 @@ struct psmouse_smbus_dev {
static LIST_HEAD(psmouse_smbus_list);
static DEFINE_MUTEX(psmouse_smbus_mutex);
static struct workqueue_struct *psmouse_smbus_wq;
static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter)
{
struct psmouse_smbus_dev *smbdev;
......@@ -161,7 +163,7 @@ static void psmouse_smbus_schedule_remove(struct i2c_client *client)
INIT_WORK(&rwork->work, psmouse_smbus_remove_i2c_device);
rwork->client = client;
schedule_work(&rwork->work);
queue_work(psmouse_smbus_wq, &rwork->work);
}
}
......@@ -305,9 +307,14 @@ int __init psmouse_smbus_module_init(void)
{
int error;
psmouse_smbus_wq = alloc_workqueue("psmouse-smbus", 0, 0);
if (!psmouse_smbus_wq)
return -ENOMEM;
error = bus_register_notifier(&i2c_bus_type, &psmouse_smbus_notifier);
if (error) {
pr_err("failed to register i2c bus notifier: %d\n", error);
destroy_workqueue(psmouse_smbus_wq);
return error;
}
......@@ -317,5 +324,5 @@ int __init psmouse_smbus_module_init(void)
void psmouse_smbus_module_exit(void)
{
bus_unregister_notifier(&i2c_bus_type, &psmouse_smbus_notifier);
flush_scheduled_work();
destroy_workqueue(psmouse_smbus_wq);
}
......@@ -365,6 +365,19 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
return 0;
}
/**
* vmmouse_reset - Disable vmmouse and reset
*
* @psmouse: Pointer to the psmouse struct
*
* Tries to disable vmmouse mode before enter suspend.
*/
static void vmmouse_reset(struct psmouse *psmouse)
{
vmmouse_disable(psmouse);
psmouse_reset(psmouse);
}
/**
* vmmouse_disconnect - Take down vmmouse driver
*
......@@ -472,6 +485,7 @@ int vmmouse_init(struct psmouse *psmouse)
psmouse->protocol_handler = vmmouse_process_byte;
psmouse->disconnect = vmmouse_disconnect;
psmouse->reconnect = vmmouse_reconnect;
psmouse->cleanup = vmmouse_reset;
return 0;
......
......@@ -733,7 +733,6 @@ static int rmi_f54_probe(struct rmi_function *fn)
v4l2_device_unregister(&f54->v4l2);
remove_wq:
cancel_delayed_work_sync(&f54->work);
flush_workqueue(f54->workqueue);
destroy_workqueue(f54->workqueue);
return ret;
}
......
......@@ -931,8 +931,7 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
}
msleep(aiptek->curSetting.programmableDelay);
if ((ret =
aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
if (aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf) != sizeof_buf) {
dev_dbg(&aiptek->intf->dev,
"aiptek_query failed: returned 0x%02x 0x%02x 0x%02x\n",
buf[0], buf[1], buf[2]);
......
......@@ -337,13 +337,15 @@ static int stmfts_input_open(struct input_dev *dev)
struct stmfts_data *sdata = input_get_drvdata(dev);
int err;
err = pm_runtime_get_sync(&sdata->client->dev);
if (err < 0)
goto out;
err = pm_runtime_resume_and_get(&sdata->client->dev);
if (err)
return err;
err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_ON);
if (err)
goto out;
if (err) {
pm_runtime_put_sync(&sdata->client->dev);
return err;
}
mutex_lock(&sdata->mutex);
sdata->running = true;
......@@ -366,9 +368,7 @@ static int stmfts_input_open(struct input_dev *dev)
"failed to enable touchkey\n");
}
out:
pm_runtime_put_noidle(&sdata->client->dev);
return err;
return 0;
}
static void stmfts_input_close(struct input_dev *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment