diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2022-05-27 15:48:45 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2022-05-27 15:48:45 -0700 |
commit | 1e90e2628cec11c080db3260833f515cc32fc27c (patch) | |
tree | a50cb16a2046266e39a60bc554782e667edd31c4 | |
parent | b26ff9137183309c18cdfe931e1cafcf3c1a980d (diff) | |
parent | 5f76955ab1e43e5795a9631b22ca4f918a0ae986 (diff) | |
download | linux-1e90e2628cec11c080db3260833f515cc32fc27c.tar.bz2 |
Merge branch 'next' into for-linus
Prepare input updates for 5.19 merge window.
94 files changed, 4170 insertions, 364 deletions
diff --git a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml index d74f2002409e..3399fc288afb 100644 --- a/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml +++ b/Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml @@ -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: diff --git a/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml b/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml new file mode 100644 index 000000000000..a3a1e5a65306 --- /dev/null +++ b/Documentation/devicetree/bindings/input/azoteq,iqs7222.yaml @@ -0,0 +1,960 @@ +# 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>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml index e8f137abb03c..c31a02149f37 100644 --- a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml +++ b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml @@ -15,14 +15,16 @@ 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: - const: google,cros-ec-keyb + 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: description: @@ -41,15 +43,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>; @@ -113,3 +131,9 @@ examples: /* UP LEFT */ 0x070b0067 0x070c0069>; }; + - | + /* No matrix keyboard, just buttons/switches */ + keyboard-controller { + compatible = "google,cros-ec-keyb-switches"; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 5936f2d9d8ed..91439d6e2a7c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13382,6 +13382,7 @@ F: net/core/drop_monitor.c NETWORKING DRIVERS M: "David S. Miller" <davem@davemloft.net> M: Jakub Kicinski <kuba@kernel.org> +M: Paolo Abeni <pabeni@redhat.com> L: netdev@vger.kernel.org S: Maintained Q: https://patchwork.kernel.org/project/netdevbpf/list/ @@ -13428,6 +13429,7 @@ F: tools/testing/selftests/drivers/net/dsa/ NETWORKING [GENERAL] M: "David S. Miller" <davem@davemloft.net> M: Jakub Kicinski <kuba@kernel.org> +M: Paolo Abeni <pabeni@redhat.com> L: netdev@vger.kernel.org S: Maintained Q: https://patchwork.kernel.org/project/netdevbpf/list/ @@ -2,7 +2,7 @@ VERSION = 5 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = -rc8 +EXTRAVERSION = NAME = Superb Owl # *DOCUMENTATION* diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index 3ed1f2c51cad..18e529118476 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -253,18 +253,18 @@ interrupt-controller; reg = <0x14 4>; interrupt-map = - <0 0 &gic 0 0 GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, - <1 0 &gic 0 0 GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, - <2 0 &gic 0 0 GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, - <3 0 &gic 0 0 GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, - <4 0 &gic 0 0 GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, - <5 0 &gic 0 0 GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, - <6 0 &gic 0 0 GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, - <7 0 &gic 0 0 GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, - <8 0 &gic 0 0 GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, - <9 0 &gic 0 0 GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, - <10 0 &gic 0 0 GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, - <11 0 &gic 0 0 GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + <0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <1 0 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, + <2 0 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, + <3 0 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, + <4 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, + <5 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, + <6 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <7 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, + <8 0 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, + <9 0 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, + <10 0 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, + <11 0 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; interrupt-map-mask = <0xffffffff 0x0>; }; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi index 3cb9c21d2775..1282b61da8a5 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi @@ -293,18 +293,18 @@ interrupt-controller; reg = <0x14 4>; interrupt-map = - <0 0 &gic 0 0 GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, - <1 0 &gic 0 0 GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, - <2 0 &gic 0 0 GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, - <3 0 &gic 0 0 GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, - <4 0 &gic 0 0 GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, - <5 0 &gic 0 0 GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, - <6 0 &gic 0 0 GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, - <7 0 &gic 0 0 GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, - <8 0 &gic 0 0 GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, - <9 0 &gic 0 0 GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, - <10 0 &gic 0 0 GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, - <11 0 &gic 0 0 GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + <0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <1 0 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, + <2 0 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, + <3 0 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, + <4 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, + <5 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, + <6 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <7 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, + <8 0 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, + <9 0 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, + <10 0 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, + <11 0 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; interrupt-map-mask = <0xffffffff 0x0>; }; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi index 7032505f5ef3..3c611cb4f5fe 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi @@ -680,18 +680,18 @@ interrupt-controller; reg = <0x14 4>; interrupt-map = - <0 0 &gic 0 0 GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, - <1 0 &gic 0 0 GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, - <2 0 &gic 0 0 GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, - <3 0 &gic 0 0 GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, - <4 0 &gic 0 0 GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, - <5 0 &gic 0 0 GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, - <6 0 &gic 0 0 GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, - <7 0 &gic 0 0 GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, - <8 0 &gic 0 0 GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, - <9 0 &gic 0 0 GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, - <10 0 &gic 0 0 GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, - <11 0 &gic 0 0 GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; + <0 0 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, + <1 0 &gic GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>, + <2 0 &gic GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>, + <3 0 &gic GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, + <4 0 &gic GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, + <5 0 &gic GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>, + <6 0 &gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>, + <7 0 &gic GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, + <8 0 &gic GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>, + <9 0 &gic GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>, + <10 0 &gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, + <11 0 &gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>; interrupt-map-mask = <0xffffffff 0x0>; }; }; diff --git a/arch/arm64/include/asm/vectors.h b/arch/arm64/include/asm/vectors.h index f64613a96d53..bc9a2145f419 100644 --- a/arch/arm64/include/asm/vectors.h +++ b/arch/arm64/include/asm/vectors.h @@ -56,14 +56,14 @@ enum arm64_bp_harden_el1_vectors { DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector); #ifndef CONFIG_UNMAP_KERNEL_AT_EL0 -#define TRAMP_VALIAS 0 +#define TRAMP_VALIAS 0ul #endif static inline const char * arm64_get_bp_hardening_vector(enum arm64_bp_harden_el1_vectors slot) { if (arm64_kernel_unmapped_at_el0()) - return (char *)TRAMP_VALIAS + SZ_2K * slot; + return (char *)(TRAMP_VALIAS + SZ_2K * slot); WARN_ON_ONCE(slot == EL1_VECTOR_KPTI); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index a401180e8d66..146fa2e76834 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -611,7 +611,6 @@ const struct arm64_cpu_capabilities arm64_errata[] = { { .desc = "ARM erratum 2077057", .capability = ARM64_WORKAROUND_2077057, - .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2), }, #endif diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5719d8cfdbd9..e86d610dc6b7 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -429,8 +429,23 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop); FOP_END /* Special case for SETcc - 1 instruction per cc */ + +/* + * Depending on .config the SETcc functions look like: + * + * SETcc %al [3 bytes] + * RET [1 byte] + * INT3 [1 byte; CONFIG_SLS] + * + * Which gives possible sizes 4 or 5. When rounded up to the + * next power-of-two alignment they become 4 or 8. + */ +#define SETCC_LENGTH (4 + IS_ENABLED(CONFIG_SLS)) +#define SETCC_ALIGN (4 << IS_ENABLED(CONFIG_SLS)) +static_assert(SETCC_LENGTH <= SETCC_ALIGN); + #define FOP_SETCC(op) \ - ".align 4 \n\t" \ + ".align " __stringify(SETCC_ALIGN) " \n\t" \ ".type " #op ", @function \n\t" \ #op ": \n\t" \ #op " %al \n\t" \ @@ -1047,7 +1062,7 @@ static int em_bsr_c(struct x86_emulate_ctxt *ctxt) static __always_inline u8 test_cc(unsigned int condition, unsigned long flags) { u8 rc; - void (*fop)(void) = (void *)em_setcc + 4 * (condition & 0xf); + void (*fop)(void) = (void *)em_setcc + SETCC_ALIGN * (condition & 0xf); flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF; asm("push %[flags]; popf; " CALL_NOSPEC diff --git a/block/blk-core.c b/block/blk-core.c index 1039515c99d6..779b4a1f66ac 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -50,6 +50,7 @@ #include "blk-mq-sched.h" #include "blk-pm.h" #include "blk-throttle.h" +#include "blk-rq-qos.h" struct dentry *blk_debugfs_root; @@ -314,6 +315,9 @@ void blk_cleanup_queue(struct request_queue *q) */ blk_freeze_queue(q); + /* cleanup rq qos structures for queue without disk */ + rq_qos_exit(q); + blk_queue_flag_set(QUEUE_FLAG_DEAD, q); blk_sync_queue(q); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1331756d4cfc..8b2e5ef15559 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1377,11 +1377,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, if (info->valid & ACPI_VALID_HID) { acpi_add_id(pnp, info->hardware_id.string); pnp->type.platform_id = 1; - if (info->valid & ACPI_VALID_CID) { - cid_list = &info->compatible_id_list; - for (i = 0; i < cid_list->count; i++) - acpi_add_id(pnp, cid_list->ids[i].string); - } + } + if (info->valid & ACPI_VALID_CID) { + cid_list = &info->compatible_id_list; + for (i = 0; i < cid_list->count; i++) + acpi_add_id(pnp, cid_list->ids[i].string); } if (info->valid & ACPI_VALID_ADR) { pnp->bus_address = info->address; diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 422753d52244..a31ffe16e626 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1112,6 +1112,8 @@ DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags); skb_data3 = skb->data[3]; paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr)) + return enq_next; ENI_PRV_PADDR(skb) = paddr; /* prepare DMA queue entries */ j = 0; diff --git a/drivers/counter/counter-sysfs.c b/drivers/counter/counter-sysfs.c index 7cc4d1d523ea..04eac41dad33 100644 --- a/drivers/counter/counter-sysfs.c +++ b/drivers/counter/counter-sysfs.c @@ -19,6 +19,11 @@ #include "counter-sysfs.h" +static inline struct counter_device *counter_from_dev(struct device *dev) +{ + return container_of(dev, struct counter_device, dev); +} + /** * struct counter_attribute - Counter sysfs attribute * @dev_attr: device attribute for sysfs @@ -90,7 +95,7 @@ static ssize_t counter_comp_u8_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct counter_attribute *const a = to_counter_attribute(attr); - struct counter_device *const counter = dev_get_drvdata(dev); + struct counter_device *const counter = counter_from_dev(dev); int err; u8 data = 0; @@ -122,7 +127,7 @@ static ssize_t counter_comp_u8_store(struct device *dev, const char *buf, size_t len) { const struct counter_attribute *const a = to_counter_attribute(attr); - struct counter_device *const counter = dev_get_drvdata(dev); + struct counter_device *const counter = counter_from_dev(dev); int err; bool bool_data = 0; u8 data = 0; @@ -158,7 +163,7 @@ static ssize_t counter_comp_u32_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct counter_attribute *const a = to_counter_attribute(attr); - struct counter_device *const counter = dev_get_drvdata(dev); + struct counter_device *const counter = counter_from_dev(dev); const struct counter_available *const avail = a->comp.priv; int err; u32 data = 0; @@ -221,7 +226,7 @@ static ssize_t counter_comp_u32_store(struct device *dev, const char *buf, size_t len) { const struct counter_attribute *const a = to_counter_attribute(attr); - struct counter_device *const counter = dev_get_drvdata(dev); + struct counter_device *const counter = counter_from_dev(dev); struct counter_count *const count = a->parent; struct counter_synapse *const synapse = a->comp.priv; const struct counter_available *const avail = a->comp.priv; @@ -281,7 +286,7 @@ static ssize_t counter_comp_u64_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct counter_attribute *const a = to_counter_attribute(attr); - struct counter_device *const counter = dev_get_drvdata(dev); + struct counter_device *const counter = counter_from_dev(dev); int err; u64 data = 0; @@ -309,7 +314,7 @@ static ssize_t counter_comp_u64_store(struct device *dev, const char *buf, size_t len) { const struct counter_attribute *const a = to_counter_attribute(attr); - struct counter_device *const counter = dev_get_drvdata(dev); + struct counter_device *const counter = counter_from_dev(dev); int err; u64 data = 0; diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c index 99ba8d51d102..11f30fd48c14 100644 --- a/drivers/crypto/qcom-rng.c +++ b/drivers/crypto/qcom-rng.c @@ -8,6 +8,7 @@ #include <linux/clk.h> #include <linux/crypto.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -43,16 +44,19 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max) { unsigned int currsize = 0; u32 val; + int ret; /* read random data from hardware */ do { - val = readl_relaxed(rng->base + PRNG_STATUS); - if (!(val & PRNG_STATUS_DATA_AVAIL)) - break; + ret = readl_poll_timeout(rng->base + PRNG_STATUS, val, + val & PRNG_STATUS_DATA_AVAIL, + 200, 10000); + if (ret) + return ret; val = readl_relaxed(rng->base + PRNG_DATA_OUT); if (!val) - break; + return -EINVAL; if ((max - currsize) >= WORD_SZ) { memcpy(data, &val, WORD_SZ); @@ -61,11 +65,10 @@ static int qcom_rng_read(struct qcom_rng *rng, u8 *data, unsigned int max) } else { /* copy only remaining bytes */ memcpy(data, &val, max - currsize); - break; } } while (currsize < max); - return currsize; + return 0; } static int qcom_rng_generate(struct crypto_rng *tfm, @@ -87,7 +90,7 @@ static int qcom_rng_generate(struct crypto_rng *tfm, mutex_unlock(&rng->lock); clk_disable_unprepare(rng->clk); - return 0; + return ret; } static int qcom_rng_seed(struct crypto_rng *tfm, const u8 *seed, diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c index 4c3201e290e2..ea84108035eb 100644 --- a/drivers/firmware/efi/apple-properties.c +++ b/drivers/firmware/efi/apple-properties.c @@ -24,7 +24,7 @@ static bool dump_properties __initdata; static int __init dump_properties_enable(char *arg) { dump_properties = true; - return 0; + return 1; } __setup("dump_apple_properties", dump_properties_enable); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 7de3f5b6e8d0..5502e176d51b 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -212,7 +212,7 @@ static int __init efivar_ssdt_setup(char *str) memcpy(efivar_ssdt, str, strlen(str)); else pr_warn("efivar_ssdt: name too long: %s\n", str); - return 0; + return 1; } __setup("efivar_ssdt=", efivar_ssdt_setup); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index defb7c464b87..6630d92e30ad 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1701,6 +1701,11 @@ static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc) */ int gpiochip_generic_request(struct gpio_chip *gc, unsigned int offset) { +#ifdef CONFIG_PINCTRL + if (list_empty(&gc->gpiodev->pin_ranges)) + return 0; +#endif + return pinctrl_gpio_request(gc->gpiodev->base + offset); } EXPORT_SYMBOL_GPL(gpiochip_generic_request); @@ -1712,6 +1717,11 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_request); */ void gpiochip_generic_free(struct gpio_chip *gc, unsigned int offset) { +#ifdef CONFIG_PINCTRL + if (list_empty(&gc->gpiodev->pin_ranges)) + return; +#endif + pinctrl_gpio_free(gc->gpiodev->base + offset); } EXPORT_SYMBOL_GPL(gpiochip_generic_free); diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 61db5a66b493..44ad70939663 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -8,7 +8,6 @@ config DRM_BRIDGE config DRM_PANEL_BRIDGE def_bool y depends on DRM_BRIDGE - depends on DRM_KMS_HELPER select DRM_PANEL help DRM bridge wrapper of DRM panels @@ -30,6 +29,7 @@ config DRM_CDNS_DSI config DRM_CHIPONE_ICN6211 tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge" depends on OF + select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE help diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index a8aba0141ce7..06cb1a59b9bc 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -217,14 +217,6 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge, if (!imx_pd_format_supported(bus_fmt)) return -EINVAL; - if (bus_flags & - ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH | - DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | - DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)) { - dev_warn(imxpd->dev, "invalid bus_flags (%x)\n", bus_flags); - return -EINVAL; - } - bridge_state->output_bus_cfg.flags = bus_flags; bridge_state->input_bus_cfg.flags = bus_flags; imx_crtc_state->bus_flags = bus_flags; diff --git a/drivers/gpu/drm/mgag200/mgag200_pll.c b/drivers/gpu/drm/mgag200/mgag200_pll.c index e9ae22b4f813..52be08b744ad 100644 --- a/drivers/gpu/drm/mgag200/mgag200_pll.c +++ b/drivers/gpu/drm/mgag200/mgag200_pll.c @@ -404,9 +404,9 @@ mgag200_pixpll_update_g200wb(struct mgag200_pll *pixpll, const struct mgag200_pl udelay(50); /* program pixel pll register */ - WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); + WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp); udelay(50); diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 0aec5a10b064..9989a316fe88 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -107,6 +107,7 @@ config DRM_PANEL_EDP select VIDEOMODE_HELPERS select DRM_DP_AUX_BUS select DRM_DP_HELPER + select DRM_KMS_HELPER help DRM panel driver for dumb eDP panels that need at most a regulator and a GPIO to be powered up. Optionally a backlight can be attached so diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 3c08f9827acf..b42c1d816e79 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2017,7 +2017,7 @@ static const struct display_timing innolux_g070y2_l01_timing = { static const struct panel_desc innolux_g070y2_l01 = { .timings = &innolux_g070y2_l01_timing, .num_timings = 1, - .bpc = 6, + .bpc = 8, .size = { .width = 152, .height = 91, diff --git a/drivers/input/input.c b/drivers/input/input.c index e5a668ce884d..1365c9dfb5f2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -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) diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 3b23078bc7b5..505a032e2786 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -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 diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile index 5174b8aba2dd..3937535f0098 100644 --- a/drivers/input/joystick/Makefile +++ b/drivers/input/joystick/Makefile @@ -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 diff --git a/drivers/input/joystick/sensehat-joystick.c b/drivers/input/joystick/sensehat-joystick.c new file mode 100644 index 000000000000..5ad1fe4ff496 --- /dev/null +++ b/drivers/input/joystick/sensehat-joystick.c @@ -0,0 +1,137 @@ +// 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"); diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c index 2b771c3a5578..166d6023a538 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -183,8 +183,7 @@ 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); + clk_disable_unprepare(kp->clk); } static int bcm_kp_open(struct input_dev *dev) diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c index 019dd6ed2c29..939c88655fc0 100644 --- a/drivers/input/keyboard/clps711x-keypad.c +++ b/drivers/input/keyboard/clps711x-keypad.c @@ -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); diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 6534dfca60b4..cc73a149da28 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -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); - err = cros_ec_keyb_register_matrix(ckdev); - if (err) { - dev_err(dev, "cannot register matrix inputs: %d\n", err); - return err; + if (!buttons_switches_only) { + err = cros_ec_keyb_register_matrix(ckdev); + if (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 diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 272a4f1c6e81..7a3b0664ab4f 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -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); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index d75a8b179a8a..a5dc4ab87fa1 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -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); diff --git a/drivers/input/keyboard/mt6779-keypad.c b/drivers/input/keyboard/mt6779-keypad.c index 0dbbddc7f298..2e7c9187c10f 100644 --- a/drivers/input/keyboard/mt6779-keypad.c +++ b/drivers/input/keyboard/mt6779-keypad.c @@ -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, diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c index 4a796bed48ac..15c15c0958b0 100644 --- a/drivers/input/keyboard/sun4i-lradc-keys.c +++ b/drivers/input/keyboard/sun4i-lradc-keys.c @@ -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); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index dd5227cf8696..a18ab7358d8f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -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 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index b92c53a6b5ae..28dfc444f0a9 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -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 diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c new file mode 100644 index 000000000000..6b4138771a3f --- /dev/null +++ b/drivers/input/misc/iqs7222.c @@ -0,0 +1,2446 @@ +// 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"); diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index 89af52498c96..549df01b6ee3 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -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; + + 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; + } + } - error = regmap_read(pwrkey->regmap, - pwrkey->baseaddr + PON_RT_STS, &sts); - if (error) + 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[] = { diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index fe43e5557ed7..cdcb7737c46a 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -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; diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index 5f868009d35b..d272f1ec27ba 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c @@ -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); diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index 164f6c757f6b..2a2459b1b4f2 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -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); } diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c index 42443ffba7c4..ea9eff7c8099 100644 --- a/drivers/input/mouse/vmmouse.c +++ b/drivers/input/mouse/vmmouse.c @@ -366,6 +366,19 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties) } /** + * 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 * * @psmouse: Pointer to the psmouse struct @@ -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; diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index 93b328c796c6..c5ce907535ef 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -733,7 +733,6 @@ remove_v4l2: v4l2_device_unregister(&f54->v4l2); remove_wq: cancel_delayed_work_sync(&f54->work); - flush_workqueue(f54->workqueue); destroy_workqueue(f54->workqueue); return ret; } diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 1581f6ef0927..24ec4844a5c3 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -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]); diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 72e0b767e1ba..c175d44c52f3 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -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) diff --git a/drivers/net/dsa/microchip/ksz8795_spi.c b/drivers/net/dsa/microchip/ksz8795_spi.c index 866767b70d65..b0a7dee27ffc 100644 --- a/drivers/net/dsa/microchip/ksz8795_spi.c +++ b/drivers/net/dsa/microchip/ksz8795_spi.c @@ -124,12 +124,23 @@ static const struct of_device_id ksz8795_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, ksz8795_dt_ids); +static const struct spi_device_id ksz8795_spi_ids[] = { + { "ksz8765" }, + { "ksz8794" }, + { "ksz8795" }, + { "ksz8863" }, + { "ksz8873" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids); + static struct spi_driver ksz8795_spi_driver = { .driver = { .name = "ksz8795-switch", .owner = THIS_MODULE, .of_match_table = of_match_ptr(ksz8795_dt_ids), }, + .id_table = ksz8795_spi_ids, .probe = ksz8795_spi_probe, .remove = ksz8795_spi_remove, .shutdown = ksz8795_spi_shutdown, diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c index e3cb0e6c9f6f..43addeabfc25 100644 --- a/drivers/net/dsa/microchip/ksz9477_spi.c +++ b/drivers/net/dsa/microchip/ksz9477_spi.c @@ -98,12 +98,24 @@ static const struct of_device_id ksz9477_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, ksz9477_dt_ids); +static const struct spi_device_id ksz9477_spi_ids[] = { + { "ksz9477" }, + { "ksz9897" }, + { "ksz9893" }, + { "ksz9563" }, + { "ksz8563" }, + { "ksz9567" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, ksz9477_spi_ids); + static struct spi_driver ksz9477_spi_driver = { .driver = { .name = "ksz9477-switch", .owner = THIS_MODULE, .of_match_table = of_match_ptr(ksz9477_dt_ids), }, + .id_table = ksz9477_spi_ids, .probe = ksz9477_spi_probe, .remove = ksz9477_spi_remove, .shutdown = ksz9477_spi_shutdown, diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 4ad3fc72e74e..a89b93cb4e26 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1181,8 +1181,11 @@ static int alx_change_mtu(struct net_device *netdev, int mtu) alx->hw.mtu = mtu; alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE); netdev_update_features(netdev); - if (netif_running(netdev)) + if (netif_running(netdev)) { + mutex_lock(&alx->mtx); alx_reinit(alx); + mutex_unlock(&alx->mtx); + } return 0; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index a19dd6797070..2209d99b3404 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -2533,6 +2533,4 @@ void bnx2x_register_phc(struct bnx2x *bp); * Meant for implicit re-load flows. */ int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp); -int bnx2x_init_firmware(struct bnx2x *bp); -void bnx2x_release_firmware(struct bnx2x *bp); #endif /* bnx2x.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 8d36ebbf08e1..5729a5ab059d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2364,24 +2364,30 @@ int bnx2x_compare_fw_ver(struct bnx2x *bp, u32 load_code, bool print_err) /* is another pf loaded on this engine? */ if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP && load_code != FW_MSG_CODE_DRV_LOAD_COMMON) { - /* build my FW version dword */ - u32 my_fw = (bp->fw_major) + (bp->fw_minor << 8) + - (bp->fw_rev << 16) + (bp->fw_eng << 24); + u8 loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng; + u32 loaded_fw; /* read loaded FW from chip */ - u32 loaded_fw = REG_RD(bp, XSEM_REG_PRAM); + loaded_fw = REG_RD(bp, XSEM_REG_PRAM); - DP(BNX2X_MSG_SP, "loaded fw %x, my fw %x\n", - loaded_fw, my_fw); + loaded_fw_major = loaded_fw & 0xff; + loaded_fw_minor = (loaded_fw >> 8) & 0xff; + loaded_fw_rev = (loaded_fw >> 16) & 0xff; + loaded_fw_eng = (loaded_fw >> 24) & 0xff; + + DP(BNX2X_MSG_SP, "loaded fw 0x%x major 0x%x minor 0x%x rev 0x%x eng 0x%x\n", + loaded_fw, loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng); /* abort nic load if version mismatch */ - if (my_fw != loaded_fw) { + if (loaded_fw_major != BCM_5710_FW_MAJOR_VERSION || + loaded_fw_minor != BCM_5710_FW_MINOR_VERSION || + loaded_fw_eng != BCM_5710_FW_ENGINEERING_VERSION || + loaded_fw_rev < BCM_5710_FW_REVISION_VERSION_V15) { if (print_err) - BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. Aborting\n", - loaded_fw, my_fw); + BNX2X_ERR("loaded FW incompatible. Aborting\n"); else - BNX2X_DEV_INFO("bnx2x with FW %x was already loaded which mismatches my %x FW, possibly due to MF UNDI\n", - loaded_fw, my_fw); + BNX2X_DEV_INFO("loaded FW incompatible, possibly due to MF UNDI\n"); + return -EBUSY; } } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index eedb48d945ed..c19b072f3a23 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12319,15 +12319,6 @@ static int bnx2x_init_bp(struct bnx2x *bp) bnx2x_read_fwinfo(bp); - if (IS_PF(bp)) { - rc = bnx2x_init_firmware(bp); - - if (rc) { - bnx2x_free_mem_bp(bp); - return rc; - } - } - func = BP_FUNC(bp); /* need to reset chip if undi was active */ @@ -12340,7 +12331,6 @@ static int bnx2x_init_bp(struct bnx2x *bp) rc = bnx2x_prev_unload(bp); if (rc) { - bnx2x_release_firmware(bp); bnx2x_free_mem_bp(bp); return rc; } @@ -13409,7 +13399,7 @@ do { \ (u8 *)bp->arr, len); \ } while (0) -int bnx2x_init_firmware(struct bnx2x *bp) +static int bnx2x_init_firmware(struct bnx2x *bp) { const char *fw_file_name, *fw_file_name_v15; struct bnx2x_fw_file_hdr *fw_hdr; @@ -13509,7 +13499,7 @@ request_firmware_exit: return rc; } -void bnx2x_release_firmware(struct bnx2x *bp) +static void bnx2x_release_firmware(struct bnx2x *bp) { kfree(bp->init_ops_offsets); kfree(bp->init_ops); @@ -14026,7 +14016,6 @@ static int bnx2x_init_one(struct pci_dev *pdev, return 0; init_one_freemem: - bnx2x_release_firmware(bp); bnx2x_free_mem_bp(bp); init_one_exit: diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 87f1056e29ff..2da804f84b48 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2287,8 +2287,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, dma_length_status = status->length_status; if (dev->features & NETIF_F_RXCSUM) { rx_csum = (__force __be16)(status->rx_csum & 0xffff); - skb->csum = (__force __wsum)ntohs(rx_csum); - skb->ip_summed = CHECKSUM_COMPLETE; + if (rx_csum) { + skb->csum = (__force __wsum)ntohs(rx_csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } } /* DMA flags and length are still valid no matter how diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 8e644e9ed8da..0e178a0a59c5 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -2541,6 +2541,13 @@ restart_watchdog: queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ * 2); } +/** + * iavf_disable_vf - disable VF + * @adapter: board private structure + * + * Set communication failed flag and free all resources. + * NOTE: This function is expected to be called with crit_lock being held. + **/ static void iavf_disable_vf(struct iavf_adapter *adapter) { struct iavf_mac_filter *f, *ftmp; @@ -2595,7 +2602,6 @@ static void iavf_disable_vf(struct iavf_adapter *adapter) memset(adapter->vf_res, 0, IAVF_VIRTCHNL_VF_RESOURCE_SIZE); iavf_shutdown_adminq(&adapter->hw); adapter->netdev->flags &= ~IFF_UP; - mutex_unlock(&adapter->crit_lock); adapter->flags &= ~IAVF_FLAG_RESET_PENDING; iavf_change_state(adapter, __IAVF_DOWN); wake_up(&adapter->down_waitqueue); @@ -4614,6 +4620,13 @@ static void iavf_remove(struct pci_dev *pdev) struct iavf_hw *hw = &adapter->hw; int err; + /* When reboot/shutdown is in progress no need to do anything + * as the adapter is already REMOVE state that was set during + * iavf_shutdown() callback. + */ + if (adapter->state == __IAVF_REMOVE) + return; + set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section); /* Wait until port initialization is complete. * There are flows where register/unregister netdev may race. diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 493942e910be..b7e8744b0c0a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4880,7 +4880,6 @@ static void ice_remove(struct pci_dev *pdev) ice_devlink_unregister_params(pf); set_bit(ICE_DOWN, pf->state); - mutex_destroy(&(&pf->hw)->fdir_fltr_lock); ice_deinit_lag(pf); if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) ice_ptp_release(pf); @@ -4888,6 +4887,7 @@ static void ice_remove(struct pci_dev *pdev) ice_remove_arfs(pf); ice_setup_mc_magic_wake(pf); ice_vsi_release_all(pf); + mutex_destroy(&(&pf->hw)->fdir_fltr_lock); ice_set_wake(pf); ice_free_irq_msix_misc(pf); ice_for_each_vsi(pf, i) { @@ -5962,8 +5962,9 @@ ice_update_vsi_tx_ring_stats(struct ice_vsi *vsi, u64 pkts = 0, bytes = 0; ring = READ_ONCE(rings[i]); - if (ring) - ice_fetch_u64_stats_per_ring(&ring->syncp, ring->stats, &pkts, &bytes); + if (!ring) + continue; + ice_fetch_u64_stats_per_ring(&ring->syncp, ring->stats, &pkts, &bytes); vsi_stats->tx_packets += pkts; vsi_stats->tx_bytes += bytes; vsi->tx_restart += ring->tx_stats.restart_q; diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index 949858891973..fdb4d7e7296c 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -60,6 +60,12 @@ static int ocelot_chain_to_block(int chain, bool ingress) */ static int ocelot_chain_to_lookup(int chain) { + /* Backwards compatibility with older, single-chain tc-flower + * offload support in Ocelot + */ + if (chain == 0) + return 0; + return (chain / VCAP_LOOKUP) % 10; } @@ -68,7 +74,15 @@ static int ocelot_chain_to_lookup(int chain) */ static int ocelot_chain_to_pag(int chain) { - int lookup = ocelot_chain_to_lookup(chain); + int lookup; + + /* Backwards compatibility with older, single-chain tc-flower + * offload support in Ocelot + */ + if (chain == 0) + return 0; + + lookup = ocelot_chain_to_lookup(chain); /* calculate PAG value as chain index relative to the first PAG */ return chain - VCAP_IS2_CHAIN(lookup, 0); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 3646469433b1..fde1c492ca02 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1587,6 +1587,9 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, pcpu_sum = kvmalloc_array(num_possible_cpus(), sizeof(struct netvsc_ethtool_pcpu_stats), GFP_KERNEL); + if (!pcpu_sum) + return; + netvsc_get_pcpu_stats(dev, pcpu_sum); for_each_present_cpu(cpu) { struct netvsc_ethtool_pcpu_stats *this_sum = &pcpu_sum[cpu]; diff --git a/drivers/net/mdio/mdio-mscc-miim.c b/drivers/net/mdio/mdio-mscc-miim.c index 7d2abaf2b2c9..64fb76c1e395 100644 --- a/drivers/net/mdio/mdio-mscc-miim.c +++ b/drivers/net/mdio/mdio-mscc-miim.c @@ -187,6 +187,13 @@ static const struct regmap_config mscc_miim_regmap_config = { .reg_stride = 4, }; +static const struct regmap_config mscc_miim_phy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .name = "phy", +}; + int mscc_miim_setup(struct device *dev, struct mii_bus **pbus, const char *name, struct regmap *mii_regmap, int status_offset) { @@ -250,7 +257,7 @@ static int mscc_miim_probe(struct platform_device *pdev) } phy_regmap = devm_regmap_init_mmio(&pdev->dev, phy_regs, - &mscc_miim_regmap_config); + &mscc_miim_phy_regmap_config); if (IS_ERR(phy_regmap)) { dev_err(&pdev->dev, "Unable to create phy register regmap\n"); return PTR_ERR(phy_regmap); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 2429db614b59..2702faf7b0f6 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1687,8 +1687,8 @@ static int marvell_suspend(struct phy_device *phydev) int err; /* Suspend the fiber mode first */ - if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, - phydev->supported)) { + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->supported)) { err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; @@ -1722,8 +1722,8 @@ static int marvell_resume(struct phy_device *phydev) int err; /* Resume the fiber mode first */ - if (!linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, - phydev->supported)) { + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, + phydev->supported)) { err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); if (err < 0) goto error; diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index ebfeeb3c67c1..7e3017e7a1c0 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2685,3 +2685,6 @@ MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl); MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver"); MODULE_AUTHOR("Nagaraju Lakkaraju"); MODULE_LICENSE("Dual MIT/GPL"); + +MODULE_FIRMWARE(MSCC_VSC8584_REVB_INT8051_FW); +MODULE_FIRMWARE(MSCC_VSC8574_REVB_INT8051_FW); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 62c453a21e49..7c1c2658cb5f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2611,36 +2611,9 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_mac_handle_beacon(ar, skb); if (ieee80211_is_beacon(hdr->frame_control) || - ieee80211_is_probe_resp(hdr->frame_control)) { - struct ieee80211_mgmt *mgmt = (void *)skb->data; - enum cfg80211_bss_frame_type ftype; - u8 *ies; - int ies_ch; - + ieee80211_is_probe_resp(hdr->frame_control)) status->boottime_ns = ktime_get_boottime_ns(); - if (!ar->scan_channel) - goto drop; - - ies = mgmt->u.beacon.variable; - - if (ieee80211_is_beacon(mgmt->frame_control)) - ftype = CFG80211_BSS_FTYPE_BEACON; - else - ftype = CFG80211_BSS_FTYPE_PRESP; - - ies_ch = cfg80211_get_ies_channel_number(mgmt->u.beacon.variable, - skb_tail_pointer(skb) - ies, - sband->band, ftype); - - if (ies_ch > 0 && ies_ch != channel) { - ath10k_dbg(ar, ATH10K_DBG_MGMT, - "channel mismatched ds channel %d scan channel %d\n", - ies_ch, channel); - goto drop; - } - } - ath10k_dbg(ar, ATH10K_DBG_MGMT, "event mgmt rx skb %pK len %d ftype %02x stype %02x\n", skb, skb->len, @@ -2654,10 +2627,6 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) ieee80211_rx_ni(ar->hw, skb); return 0; - -drop: - dev_kfree_skb(skb); - return 0; } static int freq_to_idx(struct ath10k *ar, int freq) diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 091a0ca16361..496d775c6770 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -1233,44 +1233,6 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item, } CONFIGFS_ATTR(nvmet_subsys_, attr_model); -static ssize_t nvmet_subsys_attr_discovery_nqn_show(struct config_item *item, - char *page) -{ - return snprintf(page, PAGE_SIZE, "%s\n", - nvmet_disc_subsys->subsysnqn); -} - -static ssize_t nvmet_subsys_attr_discovery_nqn_store(struct config_item *item, - const char *page, size_t count) -{ - struct nvmet_subsys *subsys = to_subsys(item); - char *subsysnqn; - int len; - - len = strcspn(page, "\n"); - if (!len) - return -EINVAL; - - subsysnqn = kmemdup_nul(page, len, GFP_KERNEL); - if (!subsysnqn) - return -ENOMEM; - - /* - * The discovery NQN must be different from subsystem NQN. - */ - if (!strcmp(subsysnqn, subsys->subsysnqn)) { - kfree(subsysnqn); - return -EBUSY; - } - down_write(&nvmet_config_sem); - kfree(nvmet_disc_subsys->subsysnqn); - nvmet_disc_subsys->subsysnqn = subsysnqn; - up_write(&nvmet_config_sem); - - return count; -} -CONFIGFS_ATTR(nvmet_subsys_, attr_discovery_nqn); - #ifdef CONFIG_BLK_DEV_INTEGRITY static ssize_t nvmet_subsys_attr_pi_enable_show(struct config_item *item, char *page) @@ -1300,7 +1262,6 @@ static struct configfs_attribute *nvmet_subsys_attrs[] = { &nvmet_subsys_attr_attr_cntlid_min, &nvmet_subsys_attr_attr_cntlid_max, &nvmet_subsys_attr_attr_model, - &nvmet_subsys_attr_attr_discovery_nqn, #ifdef CONFIG_BLK_DEV_INTEGRITY &nvmet_subsys_attr_attr_pi_enable, #endif diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 5119c687de68..626caf6f1e4b 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -1493,8 +1493,7 @@ static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port, if (!port) return NULL; - if (!strcmp(NVME_DISC_SUBSYS_NAME, subsysnqn) || - !strcmp(nvmet_disc_subsys->subsysnqn, subsysnqn)) { + if (!strcmp(NVME_DISC_SUBSYS_NAME, subsysnqn)) { if (!kref_get_unless_zero(&nvmet_disc_subsys->ref)) return NULL; return nvmet_disc_subsys; diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 88c549f257db..40a52feb315d 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -986,8 +986,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, CMD_SP(sc) = NULL; CMD_FLAGS(sc) |= FNIC_IO_DONE; - spin_unlock_irqrestore(io_lock, flags); - if (hdr_status != FCPIO_SUCCESS) { atomic64_inc(&fnic_stats->io_stats.io_failures); shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n", @@ -996,8 +994,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - cmd_trace = ((u64)hdr_status << 56) | (u64)icmnd_cmpl->scsi_status << 48 | (u64)icmnd_cmpl->flags << 40 | (u64)sc->cmnd[0] << 32 | @@ -1021,6 +1017,12 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, } else fnic->lport->host_stats.fcp_control_requests++; + /* Call SCSI completion function to complete the IO */ + scsi_done(sc); + spin_unlock_irqrestore(io_lock, flags); + + mempool_free(io_req, fnic->io_req_pool); + atomic64_dec(&fnic_stats->io_stats.active_ios); if (atomic64_read(&fnic->io_cmpl_skip)) atomic64_dec(&fnic->io_cmpl_skip); @@ -1049,9 +1051,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, if(io_duration_time > atomic64_read(&fnic_stats->io_stats.current_max_io_time)) atomic64_set(&fnic_stats->io_stats.current_max_io_time, io_duration_time); } - - /* Call SCSI completion function to complete the IO */ - scsi_done(sc); } /* fnic_fcpio_itmf_cmpl_handler diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 511726f92d9a..76229b839560 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2011,9 +2011,10 @@ mpt3sas_base_sync_reply_irqs(struct MPT3SAS_ADAPTER *ioc, u8 poll) enable_irq(reply_q->os_irq); } } + + if (poll) + _base_process_reply_queue(reply_q); } - if (poll) - _base_process_reply_queue(reply_q); } /** diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 73f419adce61..4bb6d304eb4b 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1919,6 +1919,7 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, struct usbtmc_ctrlrequest request; u8 *buffer = NULL; int rv; + unsigned int is_in, pipe; unsigned long res; res = copy_from_user(&request, arg, sizeof(struct usbtmc_ctrlrequest)); @@ -1928,12 +1929,14 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, if (request.req.wLength > USBTMC_BUFSIZE) return -EMSGSIZE; + is_in = request.req.bRequestType & USB_DIR_IN; + if (request.req.wLength) { buffer = kmalloc(request.req.wLength, GFP_KERNEL); if (!buffer) return -ENOMEM; - if ((request.req.bRequestType & USB_DIR_IN) == 0) { + if (!is_in) { /* Send control data to device */ res = copy_from_user(buffer, request.data, request.req.wLength); @@ -1944,8 +1947,12 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, } } + if (is_in) + pipe = usb_rcvctrlpipe(data->usb_dev, 0); + else + pipe = usb_sndctrlpipe(data->usb_dev, 0); rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), + pipe, request.req.bRequest, request.req.bRequestType, request.req.wValue, @@ -1957,7 +1964,7 @@ static int usbtmc_ioctl_request(struct usbtmc_device_data *data, goto exit; } - if (rv && (request.req.bRequestType & USB_DIR_IN)) { + if (rv && is_in) { /* Read control data from device */ res = copy_to_user(request.data, buffer, rv); if (res) diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 00b3f6b3bb31..713efd9aefde 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -640,6 +640,7 @@ static int rndis_set_response(struct rndis_params *params, BufLength = le32_to_cpu(buf->InformationBufferLength); BufOffset = le32_to_cpu(buf->InformationBufferOffset); if ((BufLength > RNDIS_MAX_TOTAL_SIZE) || + (BufOffset > RNDIS_MAX_TOTAL_SIZE) || (BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE)) return -EINVAL; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 568534a0d17c..c109b069f511 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1436,7 +1436,6 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) usb_gadget_udc_stop(udc); udc->driver = NULL; - udc->dev.driver = NULL; udc->gadget->dev.driver = NULL; } @@ -1498,7 +1497,6 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri driver->function); udc->driver = driver; - udc->dev.driver = &driver->driver; udc->gadget->dev.driver = &driver->driver; usb_gadget_udc_set_speed(udc, driver->max_speed); @@ -1521,7 +1519,6 @@ err1: dev_err(&udc->dev, "failed to start %s: %d\n", udc->driver->function, ret); udc->driver = NULL; - udc->dev.driver = NULL; udc->gadget->dev.driver = NULL; return ret; } diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 7d4d0713f4f0..d2b7e613eb34 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -327,7 +327,6 @@ static int omap2430_probe(struct platform_device *pdev) musb->dev.parent = &pdev->dev; musb->dev.dma_mask = &omap2430_dmamask; musb->dev.coherent_dma_mask = omap2430_dmamask; - device_set_of_node_from_dev(&musb->dev, &pdev->dev); glue->dev = &pdev->dev; glue->musb = musb; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 082380c03a3e..1768362115c6 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1170,7 +1170,9 @@ ssize_t vhost_chr_write_iter(struct vhost_dev *dev, goto done; } - if (msg.size == 0) { + if ((msg.type == VHOST_IOTLB_UPDATE || + msg.type == VHOST_IOTLB_INVALIDATE) && + msg.size == 0) { ret = -EINVAL; goto done; } diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 37f0b4274113..e6c9d41db1de 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -753,7 +753,8 @@ static int vhost_vsock_dev_release(struct inode *inode, struct file *file) /* Iterating over all connections for all CIDs to find orphans is * inefficient. Room for improvement here. */ - vsock_for_each_connected_socket(vhost_vsock_reset_orphans); + vsock_for_each_connected_socket(&vhost_transport.transport, + vhost_vsock_reset_orphans); /* Don't check the owner, because we are in the release path, so we * need to stop the vsock device in any case. diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 053cb449eb16..d3020abfe404 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3924,7 +3924,8 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, /* only send once per connect */ spin_lock(&cifs_tcp_ses_lock); - if (server->tcpStatus != CifsNeedSessSetup) { + if ((server->tcpStatus != CifsNeedSessSetup) && + (ses->status == CifsGood)) { spin_unlock(&cifs_tcp_ses_lock); return 0; } diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 2772dec9dcea..8bde30fa5387 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1105,17 +1105,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } - root = d_make_root(inode); - if (!root) { - status = -ENOMEM; - mlog_errno(status); - goto read_super_error; - } - - sb->s_root = root; - - ocfs2_complete_mount_recovery(osb); - osb->osb_dev_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj); if (!osb->osb_dev_kset) { @@ -1133,6 +1122,17 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) goto read_super_error; } + root = d_make_root(inode); + if (!root) { + status = -ENOMEM; + mlog_errno(status); + goto read_super_error; + } + + sb->s_root = root; + + ocfs2_complete_mount_recovery(osb); + if (ocfs2_mount_local(osb)) snprintf(nodestr, sizeof(nodestr), "local"); else diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index b712217f7030..1ed52441972f 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -52,6 +52,7 @@ static inline bool dev_is_mac_header_xmit(const struct net_device *dev) case ARPHRD_VOID: case ARPHRD_NONE: case ARPHRD_RAWIP: + case ARPHRD_PIMREG: return false; default: return true; diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index ab207677e0a8..f742e50207fb 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -205,7 +205,8 @@ struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr); struct sock *vsock_find_connected_socket(struct sockaddr_vm *src, struct sockaddr_vm *dst); void vsock_remove_sock(struct vsock_sock *vsk); -void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)); +void vsock_for_each_connected_socket(struct vsock_transport *transport, + void (*fn)(struct sock *sk)); int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk); bool vsock_find_cid(unsigned int cid); diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 8731d5bcb47d..b08b70989d2c 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -97,7 +97,6 @@ struct nf_conn { unsigned long status; u16 cpu; - u16 local_origin:1; possible_net_t ct_net; #if IS_ENABLED(CONFIG_NF_NAT) diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config index 07df6d93c4df..e8db8d938661 100644 --- a/kernel/configs/debug.config +++ b/kernel/configs/debug.config @@ -16,6 +16,7 @@ CONFIG_SYMBOLIC_ERRNAME=y # # Compile-time checks and compiler options # +CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_DEBUG_SECTION_MISMATCH=y CONFIG_FRAME_WARN=2048 diff --git a/mm/swap_state.c b/mm/swap_state.c index 8d4104242100..ee67164531c0 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -478,7 +478,7 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, * __read_swap_cache_async(), which has set SWAP_HAS_CACHE * in swap_map, but not yet added its page to swap cache. */ - cond_resched(); + schedule_timeout_uninterruptible(1); } /* diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 074e4a69a728..88e2808019b4 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -1436,6 +1436,7 @@ static int dsa_port_parse_of(struct dsa_port *dp, struct device_node *dn) const char *user_protocol; master = of_find_net_device_by_node(ethernet); + of_node_put(ethernet); if (!master) return -EPROBE_DEFER; diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index b0ffbcd5432d..55d604c9b3b3 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -812,8 +812,7 @@ int esp6_input_done2(struct sk_buff *skb, int err) struct tcphdr *th; offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); - - if (offset < 0) { + if (offset == -1) { err = -EINVAL; goto out; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4788f6b37053..194832663d85 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1476,8 +1476,8 @@ static int __ip6_append_data(struct sock *sk, sizeof(struct frag_hdr) : 0) + rt->rt6i_nfheader_len; - if (mtu < fragheaderlen || - ((mtu - fragheaderlen) & ~7) + fragheaderlen < sizeof(struct frag_hdr)) + if (mtu <= fragheaderlen || + ((mtu - fragheaderlen) & ~7) + fragheaderlen <= sizeof(struct frag_hdr)) goto emsgsize; maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - diff --git a/net/key/af_key.c b/net/key/af_key.c index 9bf52a09b5ff..fd51db3be91c 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1699,7 +1699,7 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad xfrm_probe_algs(); - supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); + supp_skb = compose_sadb_supported(hdr, GFP_KERNEL | __GFP_ZERO); if (!supp_skb) { if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) pfk->registered &= ~(1<<hdr->sadb_msg_satype); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index d6aa5b47031e..bf1e17c678f1 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1748,9 +1748,6 @@ resolve_normal_ct(struct nf_conn *tmpl, return 0; if (IS_ERR(h)) return PTR_ERR(h); - - ct = nf_ct_tuplehash_to_ctrack(h); - ct->local_origin = state->hook == NF_INET_LOCAL_OUT; } ct = nf_ct_tuplehash_to_ctrack(h); diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 2d06a66899b2..ffcf6529afc3 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -494,38 +494,6 @@ another_round: goto another_round; } -static bool tuple_force_port_remap(const struct nf_conntrack_tuple *tuple) -{ - u16 sp, dp; - - switch (tuple->dst.protonum) { - case IPPROTO_TCP: - sp = ntohs(tuple->src.u.tcp.port); - dp = ntohs(tuple->dst.u.tcp.port); - break; - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - sp = ntohs(tuple->src.u.udp.port); - dp = ntohs(tuple->dst.u.udp.port); - break; - default: - return false; - } - - /* IANA: System port range: 1-1023, - * user port range: 1024-49151, - * private port range: 49152-65535. - * - * Linux default ephemeral port range is 32768-60999. - * - * Enforce port remapping if sport is significantly lower - * than dport to prevent NAT port shadowing, i.e. - * accidental match of 'new' inbound connection vs. - * existing outbound one. - */ - return sp < 16384 && dp >= 32768; -} - /* Manipulate the tuple into the range given. For NF_INET_POST_ROUTING, * we change the source to map into the range. For NF_INET_PRE_ROUTING * and NF_INET_LOCAL_OUT, we change the destination to map into the @@ -539,17 +507,11 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, struct nf_conn *ct, enum nf_nat_manip_type maniptype) { - bool random_port = range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL; const struct nf_conntrack_zone *zone; struct net *net = nf_ct_net(ct); zone = nf_ct_zone(ct); - if (maniptype == NF_NAT_MANIP_SRC && - !random_port && - !ct->local_origin) - random_port = tuple_force_port_remap(orig_tuple); - /* 1) If this srcip/proto/src-proto-part is currently mapped, * and that same mapping gives a unique tuple within the given * range, use that. @@ -558,7 +520,8 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, * So far, we don't do local source mappings, so multiple * manips not an issue. */ - if (maniptype == NF_NAT_MANIP_SRC && !random_port) { + if (maniptype == NF_NAT_MANIP_SRC && + !(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) { /* try the original tuple first */ if (in_range(orig_tuple, range)) { if (!nf_nat_used_tuple(orig_tuple, ct)) { @@ -582,7 +545,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, */ /* Only bother mapping if it's not already in range and unique */ - if (!random_port) { + if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) { if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { if (!(range->flags & NF_NAT_RANGE_PROTO_OFFSET) && l4proto_in_range(tuple, maniptype, diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index c86748b3873b..d71a33ae39b3 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -8260,6 +8260,12 @@ void nf_tables_trans_destroy_flush_work(void) } EXPORT_SYMBOL_GPL(nf_tables_trans_destroy_flush_work); +static bool nft_expr_reduce(struct nft_regs_track *track, + const struct nft_expr *expr) +{ + return false; +} + static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *chain) { const struct nft_expr *expr, *last; @@ -8307,8 +8313,7 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha nft_rule_for_each_expr(expr, last, rule) { track.cur = expr; - if (expr->ops->reduce && - expr->ops->reduce(&track, expr)) { + if (nft_expr_reduce(&track, expr)) { expr = track.cur; continue; } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ab87f22cc7ec..a7273af2d900 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2317,8 +2317,11 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, copy_skb = skb_get(skb); skb_head = skb->data; } - if (copy_skb) + if (copy_skb) { + memset(&PACKET_SKB_CB(copy_skb)->sa.ll, 0, + sizeof(PACKET_SKB_CB(copy_skb)->sa.ll)); skb_set_owner_r(copy_skb, sk); + } } snaplen = po->rx_ring.frame_size - macoff; if ((int)snaplen < 0) { @@ -3462,6 +3465,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, sock_recv_ts_and_drops(msg, sk, skb); if (msg->msg_name) { + const size_t max_len = min(sizeof(skb->cb), + sizeof(struct sockaddr_storage)); int copy_len; /* If the address length field is there to be filled @@ -3484,6 +3489,10 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, msg->msg_namelen = sizeof(struct sockaddr_ll); } } + if (WARN_ON_ONCE(copy_len > max_len)) { + copy_len = max_len; + msg->msg_namelen = copy_len; + } memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, copy_len); } diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 38baeb189d4e..f04abf662ec6 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -334,7 +334,8 @@ void vsock_remove_sock(struct vsock_sock *vsk) } EXPORT_SYMBOL_GPL(vsock_remove_sock); -void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)) +void vsock_for_each_connected_socket(struct vsock_transport *transport, + void (*fn)(struct sock *sk)) { int i; @@ -343,8 +344,12 @@ void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)) for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) { struct vsock_sock *vsk; list_for_each_entry(vsk, &vsock_connected_table[i], - connected_table) + connected_table) { + if (vsk->transport != transport) + continue; + fn(sk_vsock(vsk)); + } } spin_unlock_bh(&vsock_table_lock); diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index fb3302fff627..5afc194a58bb 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -24,6 +24,7 @@ static struct workqueue_struct *virtio_vsock_workqueue; static struct virtio_vsock __rcu *the_virtio_vsock; static DEFINE_MUTEX(the_virtio_vsock_mutex); /* protects the_virtio_vsock */ +static struct virtio_transport virtio_transport; /* forward declaration */ struct virtio_vsock { struct virtio_device *vdev; @@ -384,7 +385,8 @@ static void virtio_vsock_event_handle(struct virtio_vsock *vsock, switch (le32_to_cpu(event->id)) { case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET: virtio_vsock_update_guest_cid(vsock); - vsock_for_each_connected_socket(virtio_vsock_reset_sock); + vsock_for_each_connected_socket(&virtio_transport.transport, + virtio_vsock_reset_sock); break; } } @@ -662,7 +664,8 @@ static void virtio_vsock_remove(struct virtio_device *vdev) synchronize_rcu(); /* Reset all connected sockets when the device disappear */ - vsock_for_each_connected_socket(virtio_vsock_reset_sock); + vsock_for_each_connected_socket(&virtio_transport.transport, + virtio_vsock_reset_sock); /* Stop all work handlers to make sure no one is accessing the device, * so we can safely call virtio_reset_device(). diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 7aef34e32bdf..b17dc9745188 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -75,6 +75,8 @@ static u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; static int PROTOCOL_OVERRIDE = -1; +static struct vsock_transport vmci_transport; /* forward declaration */ + /* Helper function to convert from a VMCI error code to a VSock error code. */ static s32 vmci_transport_error_to_vsock_error(s32 vmci_error) @@ -882,7 +884,8 @@ static void vmci_transport_qp_resumed_cb(u32 sub_id, const struct vmci_event_data *e_data, void *client_data) { - vsock_for_each_connected_socket(vmci_transport_handle_detach); + vsock_for_each_connected_socket(&vmci_transport, + vmci_transport_handle_detach); } static void vmci_transport_recv_pkt_work(struct work_struct *work) diff --git a/tools/perf/arch/x86/util/evlist.c b/tools/perf/arch/x86/util/evlist.c index f924246eff78..8d9b55959256 100644 --- a/tools/perf/arch/x86/util/evlist.c +++ b/tools/perf/arch/x86/util/evlist.c @@ -29,7 +29,7 @@ struct evsel *arch_evlist__leader(struct list_head *list) __evlist__for_each_entry(list, evsel) { if (evsel->pmu_name && !strcmp(evsel->pmu_name, "cpu") && - evsel->name && strstr(evsel->name, "slots")) + evsel->name && strcasestr(evsel->name, "slots")) return evsel; } return first; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index eaad04e1672a..41a66a48cbdf 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -346,7 +346,7 @@ struct evlist_cpu_iterator evlist__cpu_begin(struct evlist *evlist, struct affin { struct evlist_cpu_iterator itr = { .container = evlist, - .evsel = evlist__first(evlist), + .evsel = NULL, .cpu_map_idx = 0, .evlist_cpu_map_idx = 0, .evlist_cpu_map_nr = perf_cpu_map__nr(evlist->core.all_cpus), @@ -354,16 +354,22 @@ struct evlist_cpu_iterator evlist__cpu_begin(struct evlist *evlist, struct affin .affinity = affinity, }; - if (itr.affinity) { - itr.cpu = perf_cpu_map__cpu(evlist->core.all_cpus, 0); - affinity__set(itr.affinity, itr.cpu.cpu); - itr.cpu_map_idx = perf_cpu_map__idx(itr.evsel->core.cpus, itr.cpu); - /* - * If this CPU isn't in the evsel's cpu map then advance through - * the list. - */ - if (itr.cpu_map_idx == -1) - evlist_cpu_iterator__next(&itr); + if (evlist__empty(evlist)) { + /* Ensure the empty list doesn't iterate. */ + itr.evlist_cpu_map_idx = itr.evlist_cpu_map_nr; + } else { + itr.evsel = evlist__first(evlist); + if (itr.affinity) { + itr.cpu = perf_cpu_map__cpu(evlist->core.all_cpus, 0); + affinity__set(itr.affinity, itr.cpu.cpu); + itr.cpu_map_idx = perf_cpu_map__idx(itr.evsel->core.cpus, itr.cpu); + /* + * If this CPU isn't in the evsel's cpu map then advance + * through the list. + */ + if (itr.cpu_map_idx == -1) + evlist_cpu_iterator__next(&itr); + } } return itr; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b2ed3140a1fa..dfde9eada224 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -231,7 +231,7 @@ void symbols__fixup_end(struct rb_root_cached *symbols) prev = curr; curr = rb_entry(nd, struct symbol, rb_node); - if (prev->end == prev->start && prev->end != curr->start) + if (prev->end == prev->start || prev->end != curr->start) arch__symbols__fixup_end(prev, curr); } diff --git a/tools/testing/selftests/netfilter/nft_nat.sh b/tools/testing/selftests/netfilter/nft_nat.sh index 79fe627b9e81..eb8543b9a5c4 100755 --- a/tools/testing/selftests/netfilter/nft_nat.sh +++ b/tools/testing/selftests/netfilter/nft_nat.sh @@ -880,9 +880,8 @@ EOF return $ksft_skip fi - # test default behaviour. Packet from ns1 to ns0 is not redirected - # due to automatic port translation. - test_port_shadow "default" "ROUTER" + # test default behaviour. Packet from ns1 to ns0 is redirected to ns2. + test_port_shadow "default" "CLIENT" # test packet filter based mitigation: prevent forwarding of # packets claiming to come from the service port. diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index 1607322a112c..a14b5b800897 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 # Makefile for vm selftests +LOCAL_HDRS += $(selfdir)/vm/local_config.h $(top_srcdir)/mm/gup_test.h + include local_config.mk uname_M := $(shell uname -m 2>/dev/null || echo not) @@ -140,10 +142,6 @@ endif $(OUTPUT)/mlock-random-test $(OUTPUT)/memfd_secret: LDLIBS += -lcap -$(OUTPUT)/gup_test: ../../../../mm/gup_test.h - -$(OUTPUT)/hmm-tests: local_config.h - # HMM_EXTRA_LIBS may get set in local_config.mk, or it may be left empty. $(OUTPUT)/hmm-tests: LDLIBS += $(HMM_EXTRA_LIBS) |