Commit 2ae08b36 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input updates from Dmitry Torokhov:

 - changes to input core to properly queue synthetic events (such as
   autorepeat) and to release multitouch contacts when an input device
   is inhibited or suspended

 - reworked quirk handling in i8042 driver that consolidates multiple
   DMI tables into one and adds several quirks for TUXEDO line of
   laptops

 - update to mt6779 keypad to better reflect organization of the
   hardware

 - changes to mtk-pmic-keys driver preparing it to handle more variants

 - facelift of adp5588-keys driver

 - improvements to iqs7222 driver

 - adjustments to various DT binding documents for input devices

 - other assorted driver fixes.

* tag 'input-for-v5.20-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (54 commits)
  Input: adc-joystick - fix ordering in adc_joystick_probe()
  dt-bindings: input: ariel-pwrbutton: use spi-peripheral-props.yaml
  Input: deactivate MT slots when inhibiting or suspending devices
  Input: properly queue synthetic events
  dt-bindings: input: iqs7222: Use central 'linux,code' definition
  Input: i8042 - add dritek quirk for Acer Aspire One AO532
  dt-bindings: input: gpio-keys: accept also interrupt-extended
  dt-bindings: input: gpio-keys: reference input.yaml and document properties
  dt-bindings: input: gpio-keys: enforce node names to match all properties
  dt-bindings: input: Convert adc-keys to DT schema
  dt-bindings: input: Centralize 'linux,input-type' definition
  dt-bindings: input: Use common 'linux,keycodes' definition
  dt-bindings: input: Centralize 'linux,code' definition
  dt-bindings: input: Increase maximum keycode value to 0x2ff
  Input: mt6779-keypad - implement row/column selection
  Input: mt6779-keypad - match hardware matrix organization
  Input: i8042 - add additional TUXEDO devices to i8042 quirk tables
  Input: goodix - switch use of acpi_gpio_get_*_resource() APIs
  Input: i8042 - add TUXEDO devices to i8042 quirk tables
  Input: i8042 - add debug output for quirks
  ...
parents 21f9c8a1 8bb5e7f4
...@@ -45,6 +45,7 @@ additionalProperties: false ...@@ -45,6 +45,7 @@ additionalProperties: false
patternProperties: patternProperties:
"^axis@[0-9a-f]+$": "^axis@[0-9a-f]+$":
type: object type: object
$ref: input.yaml#
description: > description: >
Represents a joystick axis bound to the given ADC channel. Represents a joystick axis bound to the given ADC channel.
For each entry in the io-channels list, one axis subnode with a matching For each entry in the io-channels list, one axis subnode with a matching
...@@ -57,7 +58,6 @@ patternProperties: ...@@ -57,7 +58,6 @@ patternProperties:
description: Index of an io-channels list entry bound to this axis. description: Index of an io-channels list entry bound to this axis.
linux,code: linux,code:
$ref: /schemas/types.yaml#/definitions/uint32
description: EV_ABS specific event code generated by the axis. description: EV_ABS specific event code generated by the axis.
abs-range: abs-range:
......
ADC attached resistor ladder buttons
------------------------------------
Required properties:
- compatible: "adc-keys"
- io-channels: Phandle to an ADC channel
- io-channel-names = "buttons";
- keyup-threshold-microvolt: Voltage above or equal to which all the keys are
considered up.
Optional properties:
- poll-interval: Poll interval time in milliseconds
- autorepeat: Boolean, Enable auto repeat feature of Linux input
subsystem.
Each button (key) is represented as a sub-node of "adc-keys":
Required subnode-properties:
- label: Descriptive name of the key.
- linux,code: Keycode to emit.
- press-threshold-microvolt: voltage above or equal to which this key is
considered pressed.
No two values of press-threshold-microvolt may be the same.
All values of press-threshold-microvolt must be less than
keyup-threshold-microvolt.
Example:
#include <dt-bindings/input/input.h>
adc-keys {
compatible = "adc-keys";
io-channels = <&lradc 0>;
io-channel-names = "buttons";
keyup-threshold-microvolt = <2000000>;
button-up {
label = "Volume Up";
linux,code = <KEY_VOLUMEUP>;
press-threshold-microvolt = <1500000>;
};
button-down {
label = "Volume Down";
linux,code = <KEY_VOLUMEDOWN>;
press-threshold-microvolt = <1000000>;
};
button-enter {
label = "Enter";
linux,code = <KEY_ENTER>;
press-threshold-microvolt = <500000>;
};
};
+--------------------------------+------------------------+
| 2.000.000 <= value | no key pressed |
+--------------------------------+------------------------+
| 1.500.000 <= value < 2.000.000 | KEY_VOLUMEUP pressed |
+--------------------------------+------------------------+
| 1.000.000 <= value < 1.500.000 | KEY_VOLUMEDOWN pressed |
+--------------------------------+------------------------+
| 500.000 <= value < 1.000.000 | KEY_ENTER pressed |
+--------------------------------+------------------------+
| value < 500.000 | no key pressed |
+--------------------------------+------------------------+
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/adc-keys.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ADC attached resistor ladder buttons
maintainers:
- Alexandre Belloni <alexandre.belloni@bootlin.com>
allOf:
- $ref: input.yaml#
properties:
compatible:
const: adc-keys
io-channels:
maxItems: 1
io-channel-names:
const: buttons
keyup-threshold-microvolt:
description:
Voltage above or equal to which all the keys are considered up.
poll-interval: true
autorepeat: true
patternProperties:
'^button-':
type: object
$ref: input.yaml#
additionalProperties: false
description:
Each button (key) is represented as a sub-node.
properties:
label: true
linux,code: true
press-threshold-microvolt:
description:
Voltage above or equal to which this key is considered pressed. No
two values of press-threshold-microvolt may be the same. All values
of press-threshold-microvolt must be less than
keyup-threshold-microvolt.
required:
- linux,code
- press-threshold-microvolt
required:
- compatible
- io-channels
- io-channel-names
- keyup-threshold-microvolt
additionalProperties: false
examples:
- |
#include <dt-bindings/input/input.h>
// +--------------------------------+------------------------+
// | 2.000.000 <= value | no key pressed |
// +--------------------------------+------------------------+
// | 1.500.000 <= value < 2.000.000 | KEY_VOLUMEUP pressed |
// +--------------------------------+------------------------+
// | 1.000.000 <= value < 1.500.000 | KEY_VOLUMEDOWN pressed |
// +--------------------------------+------------------------+
// | 500.000 <= value < 1.000.000 | KEY_ENTER pressed |
// +--------------------------------+------------------------+
// | value < 500.000 | no key pressed |
// +--------------------------------+------------------------+
adc-keys {
compatible = "adc-keys";
io-channels = <&lradc 0>;
io-channel-names = "buttons";
keyup-threshold-microvolt = <2000000>;
button-up {
label = "Volume Up";
linux,code = <KEY_VOLUMEUP>;
press-threshold-microvolt = <1500000>;
};
button-down {
label = "Volume Down";
linux,code = <KEY_VOLUMEDOWN>;
press-threshold-microvolt = <1000000>;
};
button-enter {
label = "Enter";
linux,code = <KEY_ENTER>;
press-threshold-microvolt = <500000>;
};
};
...
...@@ -44,14 +44,13 @@ properties: ...@@ -44,14 +44,13 @@ properties:
patternProperties: patternProperties:
"^button-[0-9]+$": "^button-[0-9]+$":
type: object type: object
$ref: input.yaml#
properties: properties:
label: label:
$ref: /schemas/types.yaml#/definitions/string $ref: /schemas/types.yaml#/definitions/string
description: Descriptive name of the key description: Descriptive name of the key
linux,code: linux,code: true
$ref: /schemas/types.yaml#/definitions/uint32
description: Keycode to emit
channel: channel:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
......
...@@ -17,6 +17,7 @@ description: | ...@@ -17,6 +17,7 @@ description: |
allOf: allOf:
- $ref: input.yaml# - $ref: input.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties: properties:
compatible: compatible:
......
...@@ -37,10 +37,6 @@ properties: ...@@ -37,10 +37,6 @@ properties:
device is temporarily held in hardware reset prior to initialization if device is temporarily held in hardware reset prior to initialization if
this property is present. this property is present.
azoteq,rf-filt-enable:
type: boolean
description: Enables the device's internal RF filter.
azoteq,max-counts: azoteq,max-counts:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3] enum: [0, 1, 2, 3]
...@@ -421,6 +417,7 @@ patternProperties: ...@@ -421,6 +417,7 @@ patternProperties:
patternProperties: patternProperties:
"^event-(prox|touch)$": "^event-(prox|touch)$":
type: object type: object
$ref: input.yaml#
description: description:
Represents a proximity or touch event reported by the channel. Represents a proximity or touch event reported by the channel.
...@@ -467,14 +464,9 @@ patternProperties: ...@@ -467,14 +464,9 @@ patternProperties:
The IQS7222B does not feature channel-specific timeouts; the time- The IQS7222B does not feature channel-specific timeouts; the time-
out specified for any one channel applies to all channels. out specified for any one channel applies to all channels.
linux,code: linux,code: true
$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: linux,input-type:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 5] enum: [1, 5]
default: 1 default: 1
description: description:
...@@ -537,9 +529,8 @@ patternProperties: ...@@ -537,9 +529,8 @@ patternProperties:
azoteq,bottom-speed: azoteq,bottom-speed:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
multipleOf: 4
minimum: 0 minimum: 0
maximum: 1020 maximum: 255
description: description:
Specifies the speed of movement after which coordinate filtering is Specifies the speed of movement after which coordinate filtering is
linearly reduced. linearly reduced.
...@@ -575,14 +566,13 @@ patternProperties: ...@@ -575,14 +566,13 @@ patternProperties:
patternProperties: patternProperties:
"^event-(press|tap|(swipe|flick)-(pos|neg))$": "^event-(press|tap|(swipe|flick)-(pos|neg))$":
type: object type: object
$ref: input.yaml#
description: description:
Represents a press or gesture (IQS7222A only) event reported by Represents a press or gesture (IQS7222A only) event reported by
the slider. the slider.
properties: properties:
linux,code: linux,code: true
$ref: /schemas/types.yaml#/definitions/uint32
description: Numeric key code associated with the event.
azoteq,gesture-max-ms: azoteq,gesture-max-ms:
multipleOf: 4 multipleOf: 4
...@@ -616,16 +606,15 @@ patternProperties: ...@@ -616,16 +606,15 @@ patternProperties:
azoteq,gpio-select: azoteq,gpio-select:
$ref: /schemas/types.yaml#/definitions/uint32-array $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1 minItems: 1
maxItems: 1 maxItems: 3
items: items:
minimum: 0 minimum: 0
maximum: 0 maximum: 2
description: | description: |
Specifies an individual GPIO mapped to a tap, swipe or flick Specifies one or more GPIO mapped to the event as follows:
gesture as follows:
0: GPIO0 0: GPIO0
1: GPIO3 (reserved) 1: GPIO3 (IQS7222C only)
2: GPIO4 (reserved) 2: GPIO4 (IQS7222C only)
Note that although multiple events can be mapped to a single Note that although multiple events can be mapped to a single
GPIO, they must all be of the same type (proximity, touch or GPIO, they must all be of the same type (proximity, touch or
...@@ -710,6 +699,14 @@ allOf: ...@@ -710,6 +699,14 @@ allOf:
multipleOf: 4 multipleOf: 4
maximum: 1020 maximum: 1020
patternProperties:
"^event-(press|tap|(swipe|flick)-(pos|neg))$":
properties:
azoteq,gpio-select:
maxItems: 1
items:
maximum: 0
else: else:
patternProperties: patternProperties:
"^channel-([0-9]|1[0-9])$": "^channel-([0-9]|1[0-9])$":
...@@ -726,8 +723,6 @@ allOf: ...@@ -726,8 +723,6 @@ allOf:
azoteq,gesture-dist: false azoteq,gesture-dist: false
azoteq,gpio-select: false
required: required:
- compatible - compatible
- reg - reg
......
...@@ -57,7 +57,7 @@ examples: ...@@ -57,7 +57,7 @@ examples:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
mpr121@5a { touchkey@5a {
compatible = "fsl,mpr121-touchkey"; compatible = "fsl,mpr121-touchkey";
reg = <0x5a>; reg = <0x5a>;
interrupt-parent = <&gpio1>; interrupt-parent = <&gpio1>;
...@@ -77,7 +77,7 @@ examples: ...@@ -77,7 +77,7 @@ examples:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
mpr121@5a { touchkey@5a {
compatible = "fsl,mpr121-touchkey"; compatible = "fsl,mpr121-touchkey";
reg = <0x5a>; reg = <0x5a>;
poll-interval = <20>; poll-interval = <20>;
......
...@@ -15,11 +15,15 @@ properties: ...@@ -15,11 +15,15 @@ properties:
- gpio-keys - gpio-keys
- gpio-keys-polled - gpio-keys-polled
autorepeat: true
label:
description: Name of entire device
poll-interval: true
patternProperties: patternProperties:
".*": "^(button|event|key|switch|(button|event|key|switch)-[a-z0-9-]+|[a-z0-9-]+-(button|event|key|switch))$":
if:
type: object
then:
$ref: input.yaml# $ref: input.yaml#
properties: properties:
...@@ -34,15 +38,9 @@ patternProperties: ...@@ -34,15 +38,9 @@ patternProperties:
linux,code: linux,code:
description: Key / Axis code to emit. description: Key / Axis code to emit.
$ref: /schemas/types.yaml#/definitions/uint32
linux,input-type: linux,input-type:
description: default: 1 # EV_KEY
Specify event type this button/key generates. If not specified defaults to
<1> == EV_KEY.
$ref: /schemas/types.yaml#/definitions/uint32
default: 1
linux,input-value: linux,input-value:
description: | description: |
...@@ -94,6 +92,8 @@ patternProperties: ...@@ -94,6 +92,8 @@ patternProperties:
anyOf: anyOf:
- required: - required:
- interrupts - interrupts
- required:
- interrupts-extended
- required: - required:
- gpios - gpios
...@@ -103,19 +103,18 @@ patternProperties: ...@@ -103,19 +103,18 @@ patternProperties:
unevaluatedProperties: false unevaluatedProperties: false
if: allOf:
- $ref: input.yaml#
- if:
properties: properties:
compatible: compatible:
const: gpio-keys-polled const: gpio-keys-polled
then: then:
properties:
poll-interval:
description:
Poll interval time in milliseconds
$ref: /schemas/types.yaml#/definitions/uint32
required: required:
- poll-interval - poll-interval
else:
properties:
poll-interval: false
additionalProperties: false additionalProperties: false
...@@ -127,13 +126,13 @@ examples: ...@@ -127,13 +126,13 @@ examples:
compatible = "gpio-keys"; compatible = "gpio-keys";
autorepeat; autorepeat;
up { key-up {
label = "GPIO Key UP"; label = "GPIO Key UP";
linux,code = <103>; linux,code = <103>;
gpios = <&gpio1 0 1>; gpios = <&gpio1 0 1>;
}; };
down { key-down {
label = "GPIO Key DOWN"; label = "GPIO Key DOWN";
linux,code = <108>; linux,code = <108>;
interrupts = <1 IRQ_TYPE_EDGE_FALLING>; interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
......
...@@ -21,7 +21,26 @@ properties: ...@@ -21,7 +21,26 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32-array $ref: /schemas/types.yaml#/definitions/uint32-array
items: items:
minimum: 0 minimum: 0
maximum: 0xff maximum: 0x2ff
linux,code:
description:
Specifies a single numeric keycode value to be used for reporting
button/switch events. Specify KEY_RESERVED (0) to opt out of event
reporting.
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 0x2ff
linux,input-type:
$ref: /schemas/types.yaml#/definitions/uint32
enum:
- 1 # EV_KEY
- 2 # EV_REL
- 3 # EV_ABS
- 5 # EV_SW
description:
Specifies whether the event is to be interpreted as a key, relative,
absolute, or switch.
poll-interval: poll-interval:
description: Poll interval time in milliseconds. description: Poll interval time in milliseconds.
...@@ -39,4 +58,7 @@ properties: ...@@ -39,4 +58,7 @@ properties:
reset automatically. Device with key pressed reset feature can specify reset automatically. Device with key pressed reset feature can specify
this property. this property.
dependencies:
linux,input-type: [ "linux,code" ]
additionalProperties: true additionalProperties: true
...@@ -370,6 +370,7 @@ patternProperties: ...@@ -370,6 +370,7 @@ patternProperties:
patternProperties: patternProperties:
"^event-prox(-alt)?$": "^event-prox(-alt)?$":
type: object type: object
$ref: input.yaml#
description: description:
Represents a proximity event reported by the channel in response to Represents a proximity event reported by the channel in response to
a decrease in counts. Node names suffixed with '-alt' instead corre- a decrease in counts. Node names suffixed with '-alt' instead corre-
...@@ -396,14 +397,13 @@ patternProperties: ...@@ -396,14 +397,13 @@ patternProperties:
default: 10 default: 10
description: Specifies the threshold for the event. description: Specifies the threshold for the event.
linux,code: linux,code: true
$ref: /schemas/types.yaml#/definitions/uint32
description: Numeric key or switch code associated with the event.
additionalProperties: false additionalProperties: false
"^event-touch(-alt)?$": "^event-touch(-alt)?$":
type: object type: object
$ref: input.yaml#
description: Represents a touch event reported by the channel. description: Represents a touch event reported by the channel.
properties: properties:
...@@ -421,14 +421,13 @@ patternProperties: ...@@ -421,14 +421,13 @@ patternProperties:
default: 4 default: 4
description: Specifies the hysteresis for the event. description: Specifies the hysteresis for the event.
linux,code: linux,code: true
$ref: /schemas/types.yaml#/definitions/uint32
description: Numeric key or switch code associated with the event.
additionalProperties: false additionalProperties: false
"^event-deep(-alt)?$": "^event-deep(-alt)?$":
type: object type: object
$ref: input.yaml#
description: Represents a deep-touch event reported by the channel. description: Represents a deep-touch event reported by the channel.
properties: properties:
...@@ -446,9 +445,7 @@ patternProperties: ...@@ -446,9 +445,7 @@ patternProperties:
default: 0 default: 0
description: Specifies the hysteresis for the event. description: Specifies the hysteresis for the event.
linux,code: linux,code: true
$ref: /schemas/types.yaml#/definitions/uint32
description: Numeric key or switch code associated with the event.
additionalProperties: false additionalProperties: false
...@@ -475,7 +472,7 @@ examples: ...@@ -475,7 +472,7 @@ examples:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
iqs269a@44 { touch@44 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
...@@ -449,6 +449,7 @@ patternProperties: ...@@ -449,6 +449,7 @@ patternProperties:
patternProperties: patternProperties:
"^event-(prox|touch|deep)(-alt)?$": "^event-(prox|touch|deep)(-alt)?$":
type: object type: object
$ref: input.yaml#
description: description:
Represents a proximity, touch or deep-touch event reported by the Represents a proximity, touch or deep-touch event reported by the
channel in response to a decrease in counts. Node names suffixed with channel in response to a decrease in counts. Node names suffixed with
...@@ -487,21 +488,15 @@ patternProperties: ...@@ -487,21 +488,15 @@ patternProperties:
Specifies the hysteresis for the event (touch and deep-touch Specifies the hysteresis for the event (touch and deep-touch
events only). events only).
linux,code: linux,code: true
$ref: /schemas/types.yaml#/definitions/uint32
description: Numeric key or switch code associated with the event.
linux,input-type: linux,input-type:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 5] enum: [1, 5]
description: description:
Specifies whether the event is to be interpreted as a key (1) or Specifies whether the event is to be interpreted as a key (1) or
a switch (5). By default, Hall-channel events are interpreted as a switch (5). By default, Hall-channel events are interpreted as
switches and all others are interpreted as keys. switches and all others are interpreted as keys.
dependencies:
linux,input-type: ["linux,code"]
additionalProperties: false additionalProperties: false
dependencies: dependencies:
...@@ -511,6 +506,7 @@ patternProperties: ...@@ -511,6 +506,7 @@ patternProperties:
"^trackpad-3x[2-3]$": "^trackpad-3x[2-3]$":
type: object type: object
$ref: input.yaml#
description: description:
Represents all channels associated with the trackpad. The channels are Represents all channels associated with the trackpad. The channels are
collectively active if the trackpad is defined and inactive otherwise. collectively active if the trackpad is defined and inactive otherwise.
...@@ -679,7 +675,6 @@ patternProperties: ...@@ -679,7 +675,6 @@ patternProperties:
Specifies the raw count filter strength during low-power mode. Specifies the raw count filter strength during low-power mode.
linux,keycodes: linux,keycodes:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1 minItems: 1
maxItems: 6 maxItems: 6
description: | description: |
...@@ -751,7 +746,7 @@ examples: ...@@ -751,7 +746,7 @@ examples:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
iqs626a@44 { touch@44 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
...@@ -9,6 +9,9 @@ title: Azoteq IQS620A/621/622/624/625 Keys and Switches ...@@ -9,6 +9,9 @@ title: Azoteq IQS620A/621/622/624/625 Keys and Switches
maintainers: maintainers:
- Jeff LaBundy <jeff@labundy.com> - Jeff LaBundy <jeff@labundy.com>
allOf:
- $ref: input.yaml#
description: | description: |
The Azoteq IQS620A, IQS621, IQS622, IQS624 and IQS625 multi-function sensors The Azoteq IQS620A, IQS621, IQS622, IQS624 and IQS625 multi-function sensors
feature a variety of self-capacitive, mutual-inductive and Hall-effect sens- feature a variety of self-capacitive, mutual-inductive and Hall-effect sens-
...@@ -30,7 +33,6 @@ properties: ...@@ -30,7 +33,6 @@ properties:
- azoteq,iqs625-keys - azoteq,iqs625-keys
linux,keycodes: linux,keycodes:
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1 minItems: 1
maxItems: 16 maxItems: 16
description: | description: |
...@@ -89,15 +91,14 @@ properties: ...@@ -89,15 +91,14 @@ properties:
patternProperties: patternProperties:
"^hall-switch-(north|south)$": "^hall-switch-(north|south)$":
type: object type: object
$ref: input.yaml#
description: description:
Represents north/south-field Hall-effect sensor touch or proximity Represents north/south-field Hall-effect sensor touch or proximity
events. Note that north/south-field orientation is reversed on the events. Note that north/south-field orientation is reversed on the
IQS620AXzCSR device due to its flip-chip package. IQS620AXzCSR device due to its flip-chip package.
properties: properties:
linux,code: linux,code: true
$ref: /schemas/types.yaml#/definitions/uint32
description: Numeric switch code associated with the event.
azoteq,use-prox: azoteq,use-prox:
$ref: /schemas/types.yaml#/definitions/flag $ref: /schemas/types.yaml#/definitions/flag
......
...@@ -16,15 +16,15 @@ description: | ...@@ -16,15 +16,15 @@ description: |
The onkey controller is represented as a sub-node of the PMIC node on The onkey controller is represented as a sub-node of the PMIC node on
the device tree. the device tree.
allOf:
- $ref: input.yaml#
properties: properties:
compatible: compatible:
const: maxim,max77650-onkey const: maxim,max77650-onkey
linux,code: linux,code:
$ref: /schemas/types.yaml#/definitions/uint32 default: 116 # KEY_POWER
description:
The key-code to be reported when the key is pressed. Defaults
to KEY_POWER.
maxim,onkey-slide: maxim,onkey-slide:
$ref: /schemas/types.yaml#/definitions/flag $ref: /schemas/types.yaml#/definitions/flag
......
...@@ -112,7 +112,7 @@ examples: ...@@ -112,7 +112,7 @@ examples:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
cap1188@28 { touch@28 {
compatible = "microchip,cap1188"; compatible = "microchip,cap1188";
interrupt-parent = <&gpio1>; interrupt-parent = <&gpio1>;
interrupts = <0 0>; interrupts = <0 0>;
......
...@@ -85,6 +85,14 @@ properties: ...@@ -85,6 +85,14 @@ properties:
minimum: 0 minimum: 0
maximum: 80 maximum: 80
report-rate-hz:
description: |
Allows setting the scan rate in Hertz.
M06 supports range from 30 to 140 Hz.
M12 supports range from 1 to 255 Hz.
minimum: 1
maximum: 255
touchscreen-size-x: true touchscreen-size-x: true
touchscreen-size-y: true touchscreen-size-y: true
touchscreen-fuzz-x: true touchscreen-fuzz-x: true
......
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _INPUT_CORE_PRIVATE_H
#define _INPUT_CORE_PRIVATE_H
/*
* Functions and definitions that are private to input core,
* should not be used by input drivers or handlers.
*/
struct input_dev;
void input_mt_release_slots(struct input_dev *dev);
void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value);
#endif /* _INPUT_CORE_PRIVATE_H */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "input-core-private.h"
#define TRKID_SGN ((TRKID_MAX + 1) >> 1) #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
...@@ -259,10 +260,13 @@ static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt) ...@@ -259,10 +260,13 @@ static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
{ {
int i; int i;
lockdep_assert_held(&dev->event_lock);
for (i = 0; i < mt->num_slots; i++) { for (i = 0; i < mt->num_slots; i++) {
if (!input_mt_is_used(mt, &mt->slots[i])) { if (input_mt_is_active(&mt->slots[i]) &&
input_mt_slot(dev, i); !input_mt_is_used(mt, &mt->slots[i])) {
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); input_handle_event(dev, EV_ABS, ABS_MT_SLOT, i);
input_handle_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
} }
} }
} }
...@@ -278,12 +282,43 @@ void input_mt_drop_unused(struct input_dev *dev) ...@@ -278,12 +282,43 @@ void input_mt_drop_unused(struct input_dev *dev)
struct input_mt *mt = dev->mt; struct input_mt *mt = dev->mt;
if (mt) { if (mt) {
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
__input_mt_drop_unused(dev, mt); __input_mt_drop_unused(dev, mt);
mt->frame++; mt->frame++;
spin_unlock_irqrestore(&dev->event_lock, flags);
} }
} }
EXPORT_SYMBOL(input_mt_drop_unused); EXPORT_SYMBOL(input_mt_drop_unused);
/**
* input_mt_release_slots() - Deactivate all slots
* @dev: input device with allocated MT slots
*
* Lift all active slots.
*/
void input_mt_release_slots(struct input_dev *dev)
{
struct input_mt *mt = dev->mt;
lockdep_assert_held(&dev->event_lock);
if (mt) {
/* This will effectively mark all slots unused. */
mt->frame++;
__input_mt_drop_unused(dev, mt);
if (test_bit(ABS_PRESSURE, dev->absbit))
input_handle_event(dev, EV_ABS, ABS_PRESSURE, 0);
mt->frame++;
}
}
/** /**
* input_mt_sync_frame() - synchronize mt frame * input_mt_sync_frame() - synchronize mt frame
* @dev: input device with allocated MT slots * @dev: input device with allocated MT slots
...@@ -300,8 +335,13 @@ void input_mt_sync_frame(struct input_dev *dev) ...@@ -300,8 +335,13 @@ void input_mt_sync_frame(struct input_dev *dev)
if (!mt) if (!mt)
return; return;
if (mt->flags & INPUT_MT_DROP_UNUSED) if (mt->flags & INPUT_MT_DROP_UNUSED) {
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
__input_mt_drop_unused(dev, mt); __input_mt_drop_unused(dev, mt);
spin_unlock_irqrestore(&dev->event_lock, flags);
}
if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT)) if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
use_count = true; use_count = true;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include "input-compat.h" #include "input-compat.h"
#include "input-core-private.h"
#include "input-poller.h" #include "input-poller.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
...@@ -142,6 +143,8 @@ static void input_pass_values(struct input_dev *dev, ...@@ -142,6 +143,8 @@ static void input_pass_values(struct input_dev *dev,
struct input_handle *handle; struct input_handle *handle;
struct input_value *v; struct input_value *v;
lockdep_assert_held(&dev->event_lock);
if (!count) if (!count)
return; return;
...@@ -174,44 +177,6 @@ static void input_pass_values(struct input_dev *dev, ...@@ -174,44 +177,6 @@ static void input_pass_values(struct input_dev *dev,
} }
} }
static void input_pass_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct input_value vals[] = { { type, code, value } };
input_pass_values(dev, vals, ARRAY_SIZE(vals));
}
/*
* Generate software autorepeat event. Note that we take
* dev->event_lock here to avoid racing with input_event
* which may cause keys get "stuck".
*/
static void input_repeat_key(struct timer_list *t)
{
struct input_dev *dev = from_timer(dev, t, timer);
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
if (test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
struct input_value vals[] = {
{ EV_KEY, dev->repeat_key, 2 },
input_value_sync
};
input_set_timestamp(dev, ktime_get());
input_pass_values(dev, vals, ARRAY_SIZE(vals));
if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
#define INPUT_IGNORE_EVENT 0 #define INPUT_IGNORE_EVENT 0
#define INPUT_PASS_TO_HANDLERS 1 #define INPUT_PASS_TO_HANDLERS 1
#define INPUT_PASS_TO_DEVICE 2 #define INPUT_PASS_TO_DEVICE 2
...@@ -275,6 +240,10 @@ static int input_get_disposition(struct input_dev *dev, ...@@ -275,6 +240,10 @@ static int input_get_disposition(struct input_dev *dev,
int disposition = INPUT_IGNORE_EVENT; int disposition = INPUT_IGNORE_EVENT;
int value = *pval; int value = *pval;
/* filter-out events from inhibited devices */
if (dev->inhibited)
return INPUT_IGNORE_EVENT;
switch (type) { switch (type) {
case EV_SYN: case EV_SYN:
...@@ -375,19 +344,9 @@ static int input_get_disposition(struct input_dev *dev, ...@@ -375,19 +344,9 @@ static int input_get_disposition(struct input_dev *dev,
return disposition; return disposition;
} }
static void input_handle_event(struct input_dev *dev, static void input_event_dispose(struct input_dev *dev, int disposition,
unsigned int type, unsigned int code, int value) unsigned int type, unsigned int code, int value)
{ {
int disposition;
/* filter-out events from inhibited devices */
if (dev->inhibited)
return;
disposition = input_get_disposition(dev, type, code, &value);
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
add_input_randomness(type, code, value);
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value); dev->event(dev, type, code, value);
...@@ -426,7 +385,22 @@ static void input_handle_event(struct input_dev *dev, ...@@ -426,7 +385,22 @@ static void input_handle_event(struct input_dev *dev,
input_pass_values(dev, dev->vals, dev->num_vals); input_pass_values(dev, dev->vals, dev->num_vals);
dev->num_vals = 0; dev->num_vals = 0;
} }
}
void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
int disposition;
lockdep_assert_held(&dev->event_lock);
disposition = input_get_disposition(dev, type, code, &value);
if (disposition != INPUT_IGNORE_EVENT) {
if (type != EV_SYN)
add_input_randomness(type, code, value);
input_event_dispose(dev, disposition, type, code, value);
}
} }
/** /**
...@@ -613,7 +587,7 @@ static void __input_release_device(struct input_handle *handle) ...@@ -613,7 +587,7 @@ static void __input_release_device(struct input_handle *handle)
lockdep_is_held(&dev->mutex)); lockdep_is_held(&dev->mutex));
if (grabber == handle) { if (grabber == handle) {
rcu_assign_pointer(dev->grab, NULL); rcu_assign_pointer(dev->grab, NULL);
/* Make sure input_pass_event() notices that grab is gone */ /* Make sure input_pass_values() notices that grab is gone */
synchronize_rcu(); synchronize_rcu();
list_for_each_entry(handle, &dev->h_list, d_node) list_for_each_entry(handle, &dev->h_list, d_node)
...@@ -736,7 +710,7 @@ void input_close_device(struct input_handle *handle) ...@@ -736,7 +710,7 @@ void input_close_device(struct input_handle *handle)
if (!--handle->open) { if (!--handle->open) {
/* /*
* synchronize_rcu() makes sure that input_pass_event() * synchronize_rcu() makes sure that input_pass_values()
* completed and that no more input events are delivered * completed and that no more input events are delivered
* through this handle * through this handle
*/ */
...@@ -751,22 +725,21 @@ EXPORT_SYMBOL(input_close_device); ...@@ -751,22 +725,21 @@ EXPORT_SYMBOL(input_close_device);
* Simulate keyup events for all keys that are marked as pressed. * Simulate keyup events for all keys that are marked as pressed.
* The function must be called with dev->event_lock held. * The function must be called with dev->event_lock held.
*/ */
static void input_dev_release_keys(struct input_dev *dev) static bool input_dev_release_keys(struct input_dev *dev)
{ {
bool need_sync = false; bool need_sync = false;
int code; int code;
lockdep_assert_held(&dev->event_lock);
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
for_each_set_bit(code, dev->key, KEY_CNT) { for_each_set_bit(code, dev->key, KEY_CNT) {
input_pass_event(dev, EV_KEY, code, 0); input_handle_event(dev, EV_KEY, code, 0);
need_sync = true; need_sync = true;
} }
if (need_sync)
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
memset(dev->key, 0, sizeof(dev->key));
} }
return need_sync;
} }
/* /*
...@@ -793,7 +766,8 @@ static void input_disconnect_device(struct input_dev *dev) ...@@ -793,7 +766,8 @@ static void input_disconnect_device(struct input_dev *dev)
* generate events even after we done here but they will not * generate events even after we done here but they will not
* reach any handlers. * reach any handlers.
*/ */
input_dev_release_keys(dev); if (input_dev_release_keys(dev))
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
list_for_each_entry(handle, &dev->h_list, d_node) list_for_each_entry(handle, &dev->h_list, d_node)
handle->open = 0; handle->open = 0;
...@@ -1004,12 +978,16 @@ int input_set_keycode(struct input_dev *dev, ...@@ -1004,12 +978,16 @@ int input_set_keycode(struct input_dev *dev,
} else if (test_bit(EV_KEY, dev->evbit) && } else if (test_bit(EV_KEY, dev->evbit) &&
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) && !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(old_keycode, dev->key)) { __test_and_clear_bit(old_keycode, dev->key)) {
struct input_value vals[] = { /*
{ EV_KEY, old_keycode, 0 }, * We have to use input_event_dispose() here directly instead
input_value_sync * of input_handle_event() because the key we want to release
}; * here is considered no longer supported by the device and
* input_handle_event() will ignore it.
input_pass_values(dev, vals, ARRAY_SIZE(vals)); */
input_event_dispose(dev, INPUT_PASS_TO_HANDLERS,
EV_KEY, old_keycode, 0);
input_event_dispose(dev, INPUT_PASS_TO_HANDLERS | INPUT_FLUSH,
EV_SYN, SYN_REPORT, 1);
} }
out: out:
...@@ -1784,7 +1762,8 @@ void input_reset_device(struct input_dev *dev) ...@@ -1784,7 +1762,8 @@ void input_reset_device(struct input_dev *dev)
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
input_dev_toggle(dev, true); input_dev_toggle(dev, true);
input_dev_release_keys(dev); if (input_dev_release_keys(dev))
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
...@@ -1806,7 +1785,9 @@ static int input_inhibit_device(struct input_dev *dev) ...@@ -1806,7 +1785,9 @@ static int input_inhibit_device(struct input_dev *dev)
} }
spin_lock_irq(&dev->event_lock); spin_lock_irq(&dev->event_lock);
input_mt_release_slots(dev);
input_dev_release_keys(dev); input_dev_release_keys(dev);
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
input_dev_toggle(dev, false); input_dev_toggle(dev, false);
spin_unlock_irq(&dev->event_lock); spin_unlock_irq(&dev->event_lock);
...@@ -1857,7 +1838,8 @@ static int input_dev_suspend(struct device *dev) ...@@ -1857,7 +1838,8 @@ static int input_dev_suspend(struct device *dev)
* Keys that are pressed now are unlikely to be * Keys that are pressed now are unlikely to be
* still pressed when we resume. * still pressed when we resume.
*/ */
input_dev_release_keys(input_dev); if (input_dev_release_keys(input_dev))
input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
/* Turn off LEDs and sounds, if any are active. */ /* Turn off LEDs and sounds, if any are active. */
input_dev_toggle(input_dev, false); input_dev_toggle(input_dev, false);
...@@ -1891,7 +1873,8 @@ static int input_dev_freeze(struct device *dev) ...@@ -1891,7 +1873,8 @@ static int input_dev_freeze(struct device *dev)
* Keys that are pressed now are unlikely to be * Keys that are pressed now are unlikely to be
* still pressed when we resume. * still pressed when we resume.
*/ */
input_dev_release_keys(input_dev); if (input_dev_release_keys(input_dev))
input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
spin_unlock_irq(&input_dev->event_lock); spin_unlock_irq(&input_dev->event_lock);
...@@ -2259,6 +2242,34 @@ static void devm_input_device_unregister(struct device *dev, void *res) ...@@ -2259,6 +2242,34 @@ static void devm_input_device_unregister(struct device *dev, void *res)
__input_unregister_device(input); __input_unregister_device(input);
} }
/*
* Generate software autorepeat event. Note that we take
* dev->event_lock here to avoid racing with input_event
* which may cause keys get "stuck".
*/
static void input_repeat_key(struct timer_list *t)
{
struct input_dev *dev = from_timer(dev, t, timer);
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
if (!dev->inhibited &&
test_bit(dev->repeat_key, dev->key) &&
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
input_set_timestamp(dev, ktime_get());
input_handle_event(dev, EV_KEY, dev->repeat_key, 2);
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
if (dev->rep[REP_PERIOD])
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
/** /**
* input_enable_softrepeat - enable software autorepeat * input_enable_softrepeat - enable software autorepeat
* @dev: input device * @dev: input device
......
...@@ -222,13 +222,6 @@ static int adc_joystick_probe(struct platform_device *pdev) ...@@ -222,13 +222,6 @@ static int adc_joystick_probe(struct platform_device *pdev)
if (error) if (error)
return error; return error;
input_set_drvdata(input, joy);
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device\n");
return error;
}
joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle, joy); joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle, joy);
if (IS_ERR(joy->buffer)) { if (IS_ERR(joy->buffer)) {
dev_err(dev, "Unable to allocate callback buffer\n"); dev_err(dev, "Unable to allocate callback buffer\n");
...@@ -241,6 +234,14 @@ static int adc_joystick_probe(struct platform_device *pdev) ...@@ -241,6 +234,14 @@ static int adc_joystick_probe(struct platform_device *pdev)
return error; return error;
} }
input_set_drvdata(input, joy);
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device\n");
return error;
}
return 0; return 0;
} }
......
...@@ -98,10 +98,8 @@ static int sensehat_joystick_probe(struct platform_device *pdev) ...@@ -98,10 +98,8 @@ static int sensehat_joystick_probe(struct platform_device *pdev)
} }
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0)
dev_err(&pdev->dev, "Could not retrieve interrupt request");
return irq; return irq;
}
error = devm_request_threaded_irq(&pdev->dev, irq, error = devm_request_threaded_irq(&pdev->dev, irq,
NULL, sensehat_joystick_report, NULL, sensehat_joystick_report,
......
...@@ -795,7 +795,7 @@ config KEYBOARD_MT6779 ...@@ -795,7 +795,7 @@ config KEYBOARD_MT6779
config KEYBOARD_MTK_PMIC config KEYBOARD_MTK_PMIC
tristate "MediaTek PMIC keys support" tristate "MediaTek PMIC keys support"
depends on MFD_MT6397 depends on MFD_MT6397 || COMPILE_TEST
help help
Say Y here if you want to use the pmic keys (powerkey/homekey). Say Y here if you want to use the pmic keys (powerkey/homekey).
......
...@@ -8,17 +8,19 @@ ...@@ -8,17 +8,19 @@
* Copyright (C) 2008-2010 Analog Devices Inc. * Copyright (C) 2008-2010 Analog Devices Inc.
*/ */
#include <linux/module.h> #include <linux/delay.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/workqueue.h> #include <linux/ktime.h>
#include <linux/errno.h> #include <linux/module.h>
#include <linux/pm.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/input.h> #include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/timekeeping.h>
#include <linux/platform_data/adp5588.h> #include <linux/platform_data/adp5588.h>
...@@ -36,18 +38,18 @@ ...@@ -36,18 +38,18 @@
* asserted. * asserted.
*/ */
#define WA_DELAYED_READOUT_REVID(rev) ((rev) < 4) #define WA_DELAYED_READOUT_REVID(rev) ((rev) < 4)
#define WA_DELAYED_READOUT_TIME 25
struct adp5588_kpad { struct adp5588_kpad {
struct i2c_client *client; struct i2c_client *client;
struct input_dev *input; struct input_dev *input;
struct delayed_work work; ktime_t irq_time;
unsigned long delay; unsigned long delay;
unsigned short keycode[ADP5588_KEYMAPSIZE]; unsigned short keycode[ADP5588_KEYMAPSIZE];
const struct adp5588_gpi_map *gpimap; const struct adp5588_gpi_map *gpimap;
unsigned short gpimapsize; unsigned short gpimapsize;
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
unsigned char gpiomap[ADP5588_MAXGPIO]; unsigned char gpiomap[ADP5588_MAXGPIO];
bool export_gpio;
struct gpio_chip gc; struct gpio_chip gc;
struct mutex gpio_lock; /* Protect cached dir, dat_out */ struct mutex gpio_lock; /* Protect cached dir, dat_out */
u8 dat_out[3]; u8 dat_out[3];
...@@ -179,6 +181,21 @@ static int adp5588_build_gpiomap(struct adp5588_kpad *kpad, ...@@ -179,6 +181,21 @@ static int adp5588_build_gpiomap(struct adp5588_kpad *kpad,
return n_unused; return n_unused;
} }
static void adp5588_gpio_do_teardown(void *_kpad)
{
struct adp5588_kpad *kpad = _kpad;
struct device *dev = &kpad->client->dev;
const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev);
const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
int error;
error = gpio_data->teardown(kpad->client,
kpad->gc.base, kpad->gc.ngpio,
gpio_data->context);
if (error)
dev_warn(&kpad->client->dev, "teardown failed %d\n", error);
}
static int adp5588_gpio_add(struct adp5588_kpad *kpad) static int adp5588_gpio_add(struct adp5588_kpad *kpad)
{ {
struct device *dev = &kpad->client->dev; struct device *dev = &kpad->client->dev;
...@@ -195,8 +212,6 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) ...@@ -195,8 +212,6 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
return 0; return 0;
} }
kpad->export_gpio = true;
kpad->gc.direction_input = adp5588_gpio_direction_input; kpad->gc.direction_input = adp5588_gpio_direction_input;
kpad->gc.direction_output = adp5588_gpio_direction_output; kpad->gc.direction_output = adp5588_gpio_direction_output;
kpad->gc.get = adp5588_gpio_get_value; kpad->gc.get = adp5588_gpio_get_value;
...@@ -210,9 +225,9 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) ...@@ -210,9 +225,9 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
mutex_init(&kpad->gpio_lock); mutex_init(&kpad->gpio_lock);
error = gpiochip_add_data(&kpad->gc, kpad); error = devm_gpiochip_add_data(dev, &kpad->gc, kpad);
if (error) { if (error) {
dev_err(dev, "gpiochip_add failed, err: %d\n", error); dev_err(dev, "gpiochip_add failed: %d\n", error);
return error; return error;
} }
...@@ -227,41 +242,24 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) ...@@ -227,41 +242,24 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
kpad->gc.base, kpad->gc.ngpio, kpad->gc.base, kpad->gc.ngpio,
gpio_data->context); gpio_data->context);
if (error) if (error)
dev_warn(dev, "setup failed, %d\n", error); dev_warn(dev, "setup failed: %d\n", error);
} }
return 0;
}
static void adp5588_gpio_remove(struct adp5588_kpad *kpad)
{
struct device *dev = &kpad->client->dev;
const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev);
const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
int error;
if (!kpad->export_gpio)
return;
if (gpio_data->teardown) { if (gpio_data->teardown) {
error = gpio_data->teardown(kpad->client, error = devm_add_action(dev, adp5588_gpio_do_teardown, kpad);
kpad->gc.base, kpad->gc.ngpio,
gpio_data->context);
if (error) if (error)
dev_warn(dev, "teardown failed %d\n", error); dev_warn(dev, "failed to schedule teardown: %d\n",
error);
} }
gpiochip_remove(&kpad->gc); return 0;
} }
#else #else
static inline int adp5588_gpio_add(struct adp5588_kpad *kpad) static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
{ {
return 0; return 0;
} }
static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad)
{
}
#endif #endif
static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt) static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
...@@ -289,13 +287,36 @@ static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt) ...@@ -289,13 +287,36 @@ static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
} }
} }
static void adp5588_work(struct work_struct *work) static irqreturn_t adp5588_hard_irq(int irq, void *handle)
{ {
struct adp5588_kpad *kpad = container_of(work, struct adp5588_kpad *kpad = handle;
struct adp5588_kpad, work.work);
kpad->irq_time = ktime_get();
return IRQ_WAKE_THREAD;
}
static irqreturn_t adp5588_thread_irq(int irq, void *handle)
{
struct adp5588_kpad *kpad = handle;
struct i2c_client *client = kpad->client; struct i2c_client *client = kpad->client;
ktime_t target_time, now;
unsigned long delay;
int status, ev_cnt; int status, ev_cnt;
/*
* Readout needs to wait for at least 25ms after the notification
* for REVID < 4.
*/
if (kpad->delay) {
target_time = ktime_add_ms(kpad->irq_time, kpad->delay);
now = ktime_get();
if (ktime_before(now, target_time)) {
delay = ktime_to_us(ktime_sub(target_time, now));
usleep_range(delay, delay + 1000);
}
}
status = adp5588_read(client, INT_STAT); status = adp5588_read(client, INT_STAT);
if (status & ADP5588_OVR_FLOW_INT) /* Unlikely and should never happen */ if (status & ADP5588_OVR_FLOW_INT) /* Unlikely and should never happen */
...@@ -308,20 +329,8 @@ static void adp5588_work(struct work_struct *work) ...@@ -308,20 +329,8 @@ static void adp5588_work(struct work_struct *work)
input_sync(kpad->input); input_sync(kpad->input);
} }
} }
adp5588_write(client, INT_STAT, status); /* Status is W1C */
}
static irqreturn_t adp5588_irq(int irq, void *handle)
{
struct adp5588_kpad *kpad = handle;
/* adp5588_write(client, INT_STAT, status); /* Status is W1C */
* use keventd context to read the event fifo registers
* Schedule readout at least 25ms after notification for
* REVID < 4
*/
schedule_delayed_work(&kpad->work, kpad->delay);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -496,30 +505,27 @@ static int adp5588_probe(struct i2c_client *client, ...@@ -496,30 +505,27 @@ static int adp5588_probe(struct i2c_client *client,
return -EINVAL; return -EINVAL;
} }
kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); kpad = devm_kzalloc(&client->dev, sizeof(*kpad), GFP_KERNEL);
input = input_allocate_device(); if (!kpad)
if (!kpad || !input) { return -ENOMEM;
error = -ENOMEM;
goto err_free_mem; input = devm_input_allocate_device(&client->dev);
} if (!input)
return -ENOMEM;
kpad->client = client; kpad->client = client;
kpad->input = input; kpad->input = input;
INIT_DELAYED_WORK(&kpad->work, adp5588_work);
ret = adp5588_read(client, DEV_ID); ret = adp5588_read(client, DEV_ID);
if (ret < 0) { if (ret < 0)
error = ret; return ret;
goto err_free_mem;
}
revid = (u8) ret & ADP5588_DEVICE_ID_MASK; revid = (u8) ret & ADP5588_DEVICE_ID_MASK;
if (WA_DELAYED_READOUT_REVID(revid)) if (WA_DELAYED_READOUT_REVID(revid))
kpad->delay = msecs_to_jiffies(30); kpad->delay = msecs_to_jiffies(WA_DELAYED_READOUT_TIME);
input->name = client->name; input->name = client->name;
input->phys = "adp5588-keys/input0"; input->phys = "adp5588-keys/input0";
input->dev.parent = &client->dev;
input_set_drvdata(input, kpad); input_set_drvdata(input, kpad);
...@@ -556,95 +562,63 @@ static int adp5588_probe(struct i2c_client *client, ...@@ -556,95 +562,63 @@ static int adp5588_probe(struct i2c_client *client,
error = input_register_device(input); error = input_register_device(input);
if (error) { if (error) {
dev_err(&client->dev, "unable to register input device\n"); dev_err(&client->dev, "unable to register input device: %d\n",
goto err_free_mem; error);
return error;
} }
error = request_irq(client->irq, adp5588_irq, error = devm_request_threaded_irq(&client->dev, client->irq,
IRQF_TRIGGER_FALLING, adp5588_hard_irq, adp5588_thread_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->dev.driver->name, kpad); client->dev.driver->name, kpad);
if (error) { if (error) {
dev_err(&client->dev, "irq %d busy?\n", client->irq); dev_err(&client->dev, "failed to request irq %d: %d\n",
goto err_unreg_dev; client->irq, error);
return error;
} }
error = adp5588_setup(client); error = adp5588_setup(client);
if (error) if (error)
goto err_free_irq; return error;
if (kpad->gpimapsize) if (kpad->gpimapsize)
adp5588_report_switch_state(kpad); adp5588_report_switch_state(kpad);
error = adp5588_gpio_add(kpad); error = adp5588_gpio_add(kpad);
if (error) if (error)
goto err_free_irq; return error;
device_init_wakeup(&client->dev, 1);
i2c_set_clientdata(client, kpad);
dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq); dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
return 0; return 0;
err_free_irq:
free_irq(client->irq, kpad);
cancel_delayed_work_sync(&kpad->work);
err_unreg_dev:
input_unregister_device(input);
input = NULL;
err_free_mem:
input_free_device(input);
kfree(kpad);
return error;
} }
static int adp5588_remove(struct i2c_client *client) static int adp5588_remove(struct i2c_client *client)
{ {
struct adp5588_kpad *kpad = i2c_get_clientdata(client);
adp5588_write(client, CFG, 0); adp5588_write(client, CFG, 0);
free_irq(client->irq, kpad);
cancel_delayed_work_sync(&kpad->work);
input_unregister_device(kpad->input);
adp5588_gpio_remove(kpad);
kfree(kpad);
/* all resources will be freed by devm */
return 0; return 0;
} }
#ifdef CONFIG_PM static int __maybe_unused adp5588_suspend(struct device *dev)
static int adp5588_suspend(struct device *dev)
{ {
struct adp5588_kpad *kpad = dev_get_drvdata(dev); struct i2c_client *client = to_i2c_client(dev);
struct i2c_client *client = kpad->client;
disable_irq(client->irq); disable_irq(client->irq);
cancel_delayed_work_sync(&kpad->work);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
return 0; return 0;
} }
static int adp5588_resume(struct device *dev) static int __maybe_unused adp5588_resume(struct device *dev)
{ {
struct adp5588_kpad *kpad = dev_get_drvdata(dev); struct i2c_client *client = to_i2c_client(dev);
struct i2c_client *client = kpad->client;
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
enable_irq(client->irq); enable_irq(client->irq);
return 0; return 0;
} }
static const struct dev_pm_ops adp5588_dev_pm_ops = { static SIMPLE_DEV_PM_OPS(adp5588_dev_pm_ops, adp5588_suspend, adp5588_resume);
.suspend = adp5588_suspend,
.resume = adp5588_resume,
};
#endif
static const struct i2c_device_id adp5588_id[] = { static const struct i2c_device_id adp5588_id[] = {
{ "adp5588-keys", 0 }, { "adp5588-keys", 0 },
...@@ -656,9 +630,7 @@ MODULE_DEVICE_TABLE(i2c, adp5588_id); ...@@ -656,9 +630,7 @@ MODULE_DEVICE_TABLE(i2c, adp5588_id);
static struct i2c_driver adp5588_driver = { static struct i2c_driver adp5588_driver = {
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
#ifdef CONFIG_PM
.pm = &adp5588_dev_pm_ops, .pm = &adp5588_dev_pm_ops,
#endif
}, },
.probe = adp5588_probe, .probe = adp5588_probe,
.remove = adp5588_remove, .remove = adp5588_remove,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
// expensive. // expensive.
#include <linux/module.h> #include <linux/module.h>
#include <linux/acpi.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/input.h> #include <linux/input.h>
...@@ -518,6 +519,50 @@ static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev, ...@@ -518,6 +519,50 @@ static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev,
return 0; return 0;
} }
static void cros_ec_keyb_parse_vivaldi_physmap(struct cros_ec_keyb *ckdev)
{
u32 *physmap = ckdev->vdata.function_row_physmap;
unsigned int row, col, scancode;
int n_physmap;
int error;
int i;
n_physmap = device_property_count_u32(ckdev->dev,
"function-row-physmap");
if (n_physmap <= 0)
return;
if (n_physmap >= VIVALDI_MAX_FUNCTION_ROW_KEYS) {
dev_warn(ckdev->dev,
"only up to %d top row keys is supported (%d specified)\n",
VIVALDI_MAX_FUNCTION_ROW_KEYS, n_physmap);
n_physmap = VIVALDI_MAX_FUNCTION_ROW_KEYS;
}
error = device_property_read_u32_array(ckdev->dev,
"function-row-physmap",
physmap, n_physmap);
if (error) {
dev_warn(ckdev->dev,
"failed to parse function-row-physmap property: %d\n",
error);
return;
}
/*
* Convert (in place) from row/column encoding to matrix "scancode"
* used by the driver.
*/
for (i = 0; i < n_physmap; i++) {
row = KEY_ROW(physmap[i]);
col = KEY_COL(physmap[i]);
scancode = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
physmap[i] = scancode;
}
ckdev->vdata.num_function_row_keys = n_physmap;
}
/** /**
* cros_ec_keyb_register_matrix - Register matrix keys * cros_ec_keyb_register_matrix - Register matrix keys
* *
...@@ -534,11 +579,6 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) ...@@ -534,11 +579,6 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
struct input_dev *idev; struct input_dev *idev;
const char *phys; const char *phys;
int err; int err;
struct property *prop;
const __be32 *p;
u32 *physmap;
u32 key_pos;
unsigned int row, col, scancode, n_physmap;
err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols); err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols);
if (err) if (err)
...@@ -573,7 +613,7 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) ...@@ -573,7 +613,7 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
idev->id.product = 0; idev->id.product = 0;
idev->dev.parent = dev; idev->dev.parent = dev;
ckdev->ghost_filter = of_property_read_bool(dev->of_node, ckdev->ghost_filter = device_property_read_bool(dev,
"google,needs-ghost-filter"); "google,needs-ghost-filter");
err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols,
...@@ -589,22 +629,7 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) ...@@ -589,22 +629,7 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
input_set_drvdata(idev, ckdev); input_set_drvdata(idev, ckdev);
ckdev->idev = idev; ckdev->idev = idev;
cros_ec_keyb_compute_valid_keys(ckdev); cros_ec_keyb_compute_valid_keys(ckdev);
cros_ec_keyb_parse_vivaldi_physmap(ckdev);
physmap = ckdev->vdata.function_row_physmap;
n_physmap = 0;
of_property_for_each_u32(dev->of_node, "function-row-physmap",
prop, p, key_pos) {
if (n_physmap == VIVALDI_MAX_FUNCTION_ROW_KEYS) {
dev_warn(dev, "Only support up to %d top row keys\n",
VIVALDI_MAX_FUNCTION_ROW_KEYS);
break;
}
row = KEY_ROW(key_pos);
col = KEY_COL(key_pos);
scancode = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
physmap[n_physmap++] = scancode;
}
ckdev->vdata.num_function_row_keys = n_physmap;
err = input_register_device(ckdev->idev); err = input_register_device(ckdev->idev);
if (err) { if (err) {
...@@ -653,14 +678,19 @@ static const struct attribute_group cros_ec_keyb_attr_group = { ...@@ -653,14 +678,19 @@ static const struct attribute_group cros_ec_keyb_attr_group = {
static int cros_ec_keyb_probe(struct platform_device *pdev) static int cros_ec_keyb_probe(struct platform_device *pdev)
{ {
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); struct cros_ec_device *ec;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct cros_ec_keyb *ckdev; struct cros_ec_keyb *ckdev;
bool buttons_switches_only = device_get_match_data(dev); bool buttons_switches_only = device_get_match_data(dev);
int err; int err;
if (!dev->of_node) /*
return -ENODEV; * If the parent ec device has not been probed yet, defer the probe of
* this keyboard/button driver until later.
*/
ec = dev_get_drvdata(pdev->dev.parent);
if (!ec)
return -EPROBE_DEFER;
ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL); ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL);
if (!ckdev) if (!ckdev)
...@@ -713,6 +743,14 @@ static int cros_ec_keyb_remove(struct platform_device *pdev) ...@@ -713,6 +743,14 @@ static int cros_ec_keyb_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_ACPI
static const struct acpi_device_id cros_ec_keyb_acpi_match[] = {
{ "GOOG0007", true },
{ }
};
MODULE_DEVICE_TABLE(acpi, cros_ec_keyb_acpi_match);
#endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id cros_ec_keyb_of_match[] = { static const struct of_device_id cros_ec_keyb_of_match[] = {
{ .compatible = "google,cros-ec-keyb" }, { .compatible = "google,cros-ec-keyb" },
...@@ -730,6 +768,7 @@ static struct platform_driver cros_ec_keyb_driver = { ...@@ -730,6 +768,7 @@ static struct platform_driver cros_ec_keyb_driver = {
.driver = { .driver = {
.name = "cros-ec-keyb", .name = "cros-ec-keyb",
.of_match_table = of_match_ptr(cros_ec_keyb_of_match), .of_match_table = of_match_ptr(cros_ec_keyb_of_match),
.acpi_match_table = ACPI_PTR(cros_ec_keyb_acpi_match),
.pm = &cros_ec_keyb_pm_ops, .pm = &cros_ec_keyb_pm_ops,
}, },
}; };
......
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
#define MTK_KPD_DEBOUNCE 0x0018 #define MTK_KPD_DEBOUNCE 0x0018
#define MTK_KPD_DEBOUNCE_MASK GENMASK(13, 0) #define MTK_KPD_DEBOUNCE_MASK GENMASK(13, 0)
#define MTK_KPD_DEBOUNCE_MAX_MS 256 #define MTK_KPD_DEBOUNCE_MAX_MS 256
#define MTK_KPD_SEL 0x0020
#define MTK_KPD_SEL_COL GENMASK(15, 10)
#define MTK_KPD_SEL_ROW GENMASK(9, 4)
#define MTK_KPD_SEL_COLMASK(c) GENMASK((c) + 9, 10)
#define MTK_KPD_SEL_ROWMASK(r) GENMASK((r) + 3, 4)
#define MTK_KPD_NUM_MEMS 5 #define MTK_KPD_NUM_MEMS 5
#define MTK_KPD_NUM_BITS 136 /* 4*32+8 MEM5 only use 8 BITS */ #define MTK_KPD_NUM_BITS 136 /* 4*32+8 MEM5 only use 8 BITS */
...@@ -42,7 +47,7 @@ static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id) ...@@ -42,7 +47,7 @@ static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id)
const unsigned short *keycode = keypad->input_dev->keycode; const unsigned short *keycode = keypad->input_dev->keycode;
DECLARE_BITMAP(new_state, MTK_KPD_NUM_BITS); DECLARE_BITMAP(new_state, MTK_KPD_NUM_BITS);
DECLARE_BITMAP(change, MTK_KPD_NUM_BITS); DECLARE_BITMAP(change, MTK_KPD_NUM_BITS);
unsigned int bit_nr; unsigned int bit_nr, key;
unsigned int row, col; unsigned int row, col;
unsigned int scancode; unsigned int scancode;
unsigned int row_shift = get_count_order(keypad->n_cols); unsigned int row_shift = get_count_order(keypad->n_cols);
...@@ -61,8 +66,10 @@ static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id) ...@@ -61,8 +66,10 @@ static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id)
if (bit_nr % 32 >= 16) if (bit_nr % 32 >= 16)
continue; continue;
row = bit_nr / 32; key = bit_nr / 32 * 16 + bit_nr % 32;
col = bit_nr % 32; row = key / 9;
col = key % 9;
scancode = MATRIX_SCAN_CODE(row, col, row_shift); scancode = MATRIX_SCAN_CODE(row, col, row_shift);
/* 1: not pressed, 0: pressed */ /* 1: not pressed, 0: pressed */
pressed = !test_bit(bit_nr, new_state); pressed = !test_bit(bit_nr, new_state);
...@@ -159,6 +166,11 @@ static int mt6779_keypad_pdrv_probe(struct platform_device *pdev) ...@@ -159,6 +166,11 @@ static int mt6779_keypad_pdrv_probe(struct platform_device *pdev)
regmap_write(keypad->regmap, MTK_KPD_DEBOUNCE, regmap_write(keypad->regmap, MTK_KPD_DEBOUNCE,
(debounce * (1 << 5)) & MTK_KPD_DEBOUNCE_MASK); (debounce * (1 << 5)) & MTK_KPD_DEBOUNCE_MASK);
regmap_update_bits(keypad->regmap, MTK_KPD_SEL, MTK_KPD_SEL_ROW,
MTK_KPD_SEL_ROWMASK(keypad->n_rows));
regmap_update_bits(keypad->regmap, MTK_KPD_SEL, MTK_KPD_SEL_COL,
MTK_KPD_SEL_COLMASK(keypad->n_cols));
keypad->clk = devm_clk_get(&pdev->dev, "kpd"); keypad->clk = devm_clk_get(&pdev->dev, "kpd");
if (IS_ERR(keypad->clk)) if (IS_ERR(keypad->clk))
return PTR_ERR(keypad->clk); return PTR_ERR(keypad->clk);
......
...@@ -18,17 +18,9 @@ ...@@ -18,17 +18,9 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#define MTK_PMIC_PWRKEY_RST_EN_MASK 0x1 #define MTK_PMIC_RST_DU_MASK GENMASK(9, 8)
#define MTK_PMIC_PWRKEY_RST_EN_SHIFT 6 #define MTK_PMIC_PWRKEY_RST BIT(6)
#define MTK_PMIC_HOMEKEY_RST_EN_MASK 0x1 #define MTK_PMIC_HOMEKEY_RST BIT(5)
#define MTK_PMIC_HOMEKEY_RST_EN_SHIFT 5
#define MTK_PMIC_RST_DU_MASK 0x3
#define MTK_PMIC_RST_DU_SHIFT 8
#define MTK_PMIC_PWRKEY_RST \
(MTK_PMIC_PWRKEY_RST_EN_MASK << MTK_PMIC_PWRKEY_RST_EN_SHIFT)
#define MTK_PMIC_HOMEKEY_RST \
(MTK_PMIC_HOMEKEY_RST_EN_MASK << MTK_PMIC_HOMEKEY_RST_EN_SHIFT)
#define MTK_PMIC_PWRKEY_INDEX 0 #define MTK_PMIC_PWRKEY_INDEX 0
#define MTK_PMIC_HOMEKEY_INDEX 1 #define MTK_PMIC_HOMEKEY_INDEX 1
...@@ -39,50 +31,58 @@ struct mtk_pmic_keys_regs { ...@@ -39,50 +31,58 @@ struct mtk_pmic_keys_regs {
u32 deb_mask; u32 deb_mask;
u32 intsel_reg; u32 intsel_reg;
u32 intsel_mask; u32 intsel_mask;
u32 rst_en_mask;
}; };
#define MTK_PMIC_KEYS_REGS(_deb_reg, _deb_mask, \ #define MTK_PMIC_KEYS_REGS(_deb_reg, _deb_mask, \
_intsel_reg, _intsel_mask) \ _intsel_reg, _intsel_mask, _rst_mask) \
{ \ { \
.deb_reg = _deb_reg, \ .deb_reg = _deb_reg, \
.deb_mask = _deb_mask, \ .deb_mask = _deb_mask, \
.intsel_reg = _intsel_reg, \ .intsel_reg = _intsel_reg, \
.intsel_mask = _intsel_mask, \ .intsel_mask = _intsel_mask, \
.rst_en_mask = _rst_mask, \
} }
struct mtk_pmic_regs { struct mtk_pmic_regs {
const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT]; const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT];
u32 pmic_rst_reg; u32 pmic_rst_reg;
u32 rst_lprst_mask; /* Long-press reset timeout bitmask */
}; };
static const struct mtk_pmic_regs mt6397_regs = { static const struct mtk_pmic_regs mt6397_regs = {
.keys_regs[MTK_PMIC_PWRKEY_INDEX] = .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6397_CHRSTATUS, MTK_PMIC_KEYS_REGS(MT6397_CHRSTATUS,
0x8, MT6397_INT_RSV, 0x10), 0x8, MT6397_INT_RSV, 0x10, MTK_PMIC_PWRKEY_RST),
.keys_regs[MTK_PMIC_HOMEKEY_INDEX] = .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6397_OCSTATUS2, MTK_PMIC_KEYS_REGS(MT6397_OCSTATUS2,
0x10, MT6397_INT_RSV, 0x8), 0x10, MT6397_INT_RSV, 0x8, MTK_PMIC_HOMEKEY_RST),
.pmic_rst_reg = MT6397_TOP_RST_MISC, .pmic_rst_reg = MT6397_TOP_RST_MISC,
.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
}; };
static const struct mtk_pmic_regs mt6323_regs = { static const struct mtk_pmic_regs mt6323_regs = {
.keys_regs[MTK_PMIC_PWRKEY_INDEX] = .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS, MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS,
0x2, MT6323_INT_MISC_CON, 0x10), 0x2, MT6323_INT_MISC_CON, 0x10, MTK_PMIC_PWRKEY_RST),
.keys_regs[MTK_PMIC_HOMEKEY_INDEX] = .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS, MTK_PMIC_KEYS_REGS(MT6323_CHRSTATUS,
0x4, MT6323_INT_MISC_CON, 0x8), 0x4, MT6323_INT_MISC_CON, 0x8, MTK_PMIC_HOMEKEY_RST),
.pmic_rst_reg = MT6323_TOP_RST_MISC, .pmic_rst_reg = MT6323_TOP_RST_MISC,
.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
}; };
static const struct mtk_pmic_regs mt6358_regs = { static const struct mtk_pmic_regs mt6358_regs = {
.keys_regs[MTK_PMIC_PWRKEY_INDEX] = .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS, MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS,
0x2, MT6358_PSC_TOP_INT_CON0, 0x5), 0x2, MT6358_PSC_TOP_INT_CON0, 0x5,
MTK_PMIC_PWRKEY_RST),
.keys_regs[MTK_PMIC_HOMEKEY_INDEX] = .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS, MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS,
0x8, MT6358_PSC_TOP_INT_CON0, 0xa), 0x8, MT6358_PSC_TOP_INT_CON0, 0xa,
MTK_PMIC_HOMEKEY_RST),
.pmic_rst_reg = MT6358_TOP_RST_MISC, .pmic_rst_reg = MT6358_TOP_RST_MISC,
.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
}; };
struct mtk_pmic_keys_info { struct mtk_pmic_keys_info {
...@@ -108,53 +108,49 @@ enum mtk_pmic_keys_lp_mode { ...@@ -108,53 +108,49 @@ enum mtk_pmic_keys_lp_mode {
}; };
static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys, static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys,
u32 pmic_rst_reg) const struct mtk_pmic_regs *regs)
{ {
int ret; const struct mtk_pmic_keys_regs *kregs_home, *kregs_pwr;
u32 long_press_mode, long_press_debounce; u32 long_press_mode, long_press_debounce;
u32 value, mask;
int error;
kregs_home = keys->keys[MTK_PMIC_HOMEKEY_INDEX].regs;
kregs_pwr = keys->keys[MTK_PMIC_PWRKEY_INDEX].regs;
ret = of_property_read_u32(keys->dev->of_node, error = of_property_read_u32(keys->dev->of_node, "power-off-time-sec",
"power-off-time-sec", &long_press_debounce); &long_press_debounce);
if (ret) if (error)
long_press_debounce = 0; long_press_debounce = 0;
regmap_update_bits(keys->regmap, pmic_rst_reg, mask = regs->rst_lprst_mask;
MTK_PMIC_RST_DU_MASK << MTK_PMIC_RST_DU_SHIFT, value = long_press_debounce << (ffs(regs->rst_lprst_mask) - 1);
long_press_debounce << MTK_PMIC_RST_DU_SHIFT);
ret = of_property_read_u32(keys->dev->of_node, error = of_property_read_u32(keys->dev->of_node,
"mediatek,long-press-mode", &long_press_mode); "mediatek,long-press-mode",
if (ret) &long_press_mode);
if (error)
long_press_mode = LP_DISABLE; long_press_mode = LP_DISABLE;
switch (long_press_mode) { switch (long_press_mode) {
case LP_ONEKEY:
regmap_update_bits(keys->regmap, pmic_rst_reg,
MTK_PMIC_PWRKEY_RST,
MTK_PMIC_PWRKEY_RST);
regmap_update_bits(keys->regmap, pmic_rst_reg,
MTK_PMIC_HOMEKEY_RST,
0);
break;
case LP_TWOKEY: case LP_TWOKEY:
regmap_update_bits(keys->regmap, pmic_rst_reg, value |= kregs_home->rst_en_mask;
MTK_PMIC_PWRKEY_RST, fallthrough;
MTK_PMIC_PWRKEY_RST);
regmap_update_bits(keys->regmap, pmic_rst_reg, case LP_ONEKEY:
MTK_PMIC_HOMEKEY_RST, value |= kregs_pwr->rst_en_mask;
MTK_PMIC_HOMEKEY_RST); fallthrough;
break;
case LP_DISABLE: case LP_DISABLE:
regmap_update_bits(keys->regmap, pmic_rst_reg, mask |= kregs_home->rst_en_mask;
MTK_PMIC_PWRKEY_RST, mask |= kregs_pwr->rst_en_mask;
0);
regmap_update_bits(keys->regmap, pmic_rst_reg,
MTK_PMIC_HOMEKEY_RST,
0);
break; break;
default: default:
break; break;
} }
regmap_update_bits(keys->regmap, regs->pmic_rst_reg, mask, value);
} }
static irqreturn_t mtk_pmic_keys_irq_handler_thread(int irq, void *data) static irqreturn_t mtk_pmic_keys_irq_handler_thread(int irq, void *data)
...@@ -358,7 +354,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) ...@@ -358,7 +354,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
return error; return error;
} }
mtk_pmic_keys_lp_reset_setup(keys, mtk_pmic_regs->pmic_rst_reg); mtk_pmic_keys_lp_reset_setup(keys, mtk_pmic_regs);
platform_set_drvdata(pdev, keys); platform_set_drvdata(pdev, keys);
......
...@@ -179,11 +179,9 @@ static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id) ...@@ -179,11 +179,9 @@ static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
int error; int error;
u64 keys; u64 keys;
error = pm_runtime_get_sync(dev); error = pm_runtime_resume_and_get(dev);
if (error < 0) { if (error)
pm_runtime_put_noidle(dev);
return IRQ_NONE; return IRQ_NONE;
}
low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
...@@ -207,11 +205,9 @@ static int omap4_keypad_open(struct input_dev *input) ...@@ -207,11 +205,9 @@ static int omap4_keypad_open(struct input_dev *input)
struct device *dev = input->dev.parent; struct device *dev = input->dev.parent;
int error; int error;
error = pm_runtime_get_sync(dev); error = pm_runtime_resume_and_get(dev);
if (error < 0) { if (error)
pm_runtime_put_noidle(dev);
return error; return error;
}
disable_irq(keypad_data->irq); disable_irq(keypad_data->irq);
...@@ -254,9 +250,10 @@ static void omap4_keypad_close(struct input_dev *input) ...@@ -254,9 +250,10 @@ static void omap4_keypad_close(struct input_dev *input)
struct device *dev = input->dev.parent; struct device *dev = input->dev.parent;
int error; int error;
error = pm_runtime_get_sync(dev); error = pm_runtime_resume_and_get(dev);
if (error < 0) if (error)
pm_runtime_put_noidle(dev); dev_err(dev, "%s: pm_runtime_resume_and_get() failed: %d\n",
__func__, error);
disable_irq(keypad_data->irq); disable_irq(keypad_data->irq);
omap4_keypad_stop(keypad_data); omap4_keypad_stop(keypad_data);
...@@ -392,10 +389,9 @@ static int omap4_keypad_probe(struct platform_device *pdev) ...@@ -392,10 +389,9 @@ static int omap4_keypad_probe(struct platform_device *pdev)
* Enable clocks for the keypad module so that we can read * Enable clocks for the keypad module so that we can read
* revision register. * revision register.
*/ */
error = pm_runtime_get_sync(dev); error = pm_runtime_resume_and_get(dev);
if (error < 0) { if (error) {
dev_err(dev, "pm_runtime_get_sync() failed\n"); dev_err(dev, "pm_runtime_resume_and_get() failed\n");
pm_runtime_put_noidle(dev);
return error; return error;
} }
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#define IQS7222_SLDR_SETUP_2_RES_MASK GENMASK(15, 8) #define IQS7222_SLDR_SETUP_2_RES_MASK GENMASK(15, 8)
#define IQS7222_SLDR_SETUP_2_RES_SHIFT 8 #define IQS7222_SLDR_SETUP_2_RES_SHIFT 8
#define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK GENMASK(7, 0) #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_GPIO_SETUP_0_GPIO_EN BIT(0)
...@@ -54,6 +53,9 @@ ...@@ -54,6 +53,9 @@
#define IQS7222_SYS_SETUP_ACK_RESET BIT(0) #define IQS7222_SYS_SETUP_ACK_RESET BIT(0)
#define IQS7222_EVENT_MASK_ATI BIT(12) #define IQS7222_EVENT_MASK_ATI BIT(12)
#define IQS7222_EVENT_MASK_SLDR BIT(10)
#define IQS7222_EVENT_MASK_TOUCH BIT(1)
#define IQS7222_EVENT_MASK_PROX BIT(0)
#define IQS7222_COMMS_HOLD BIT(0) #define IQS7222_COMMS_HOLD BIT(0)
#define IQS7222_COMMS_ERROR 0xEEEE #define IQS7222_COMMS_ERROR 0xEEEE
...@@ -92,11 +94,11 @@ enum iqs7222_reg_key_id { ...@@ -92,11 +94,11 @@ enum iqs7222_reg_key_id {
enum iqs7222_reg_grp_id { enum iqs7222_reg_grp_id {
IQS7222_REG_GRP_STAT, IQS7222_REG_GRP_STAT,
IQS7222_REG_GRP_FILT,
IQS7222_REG_GRP_CYCLE, IQS7222_REG_GRP_CYCLE,
IQS7222_REG_GRP_GLBL, IQS7222_REG_GRP_GLBL,
IQS7222_REG_GRP_BTN, IQS7222_REG_GRP_BTN,
IQS7222_REG_GRP_CHAN, IQS7222_REG_GRP_CHAN,
IQS7222_REG_GRP_FILT,
IQS7222_REG_GRP_SLDR, IQS7222_REG_GRP_SLDR,
IQS7222_REG_GRP_GPIO, IQS7222_REG_GRP_GPIO,
IQS7222_REG_GRP_SYS, IQS7222_REG_GRP_SYS,
...@@ -135,12 +137,12 @@ struct iqs7222_event_desc { ...@@ -135,12 +137,12 @@ struct iqs7222_event_desc {
static const struct iqs7222_event_desc iqs7222_kp_events[] = { static const struct iqs7222_event_desc iqs7222_kp_events[] = {
{ {
.name = "event-prox", .name = "event-prox",
.enable = BIT(0), .enable = IQS7222_EVENT_MASK_PROX,
.reg_key = IQS7222_REG_KEY_PROX, .reg_key = IQS7222_REG_KEY_PROX,
}, },
{ {
.name = "event-touch", .name = "event-touch",
.enable = BIT(1), .enable = IQS7222_EVENT_MASK_TOUCH,
.reg_key = IQS7222_REG_KEY_TOUCH, .reg_key = IQS7222_REG_KEY_TOUCH,
}, },
}; };
...@@ -555,13 +557,6 @@ static const struct iqs7222_prop_desc iqs7222_props[] = { ...@@ -555,13 +557,6 @@ static const struct iqs7222_prop_desc iqs7222_props[] = {
.reg_width = 4, .reg_width = 4,
.label = "current reference trim", .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", .name = "azoteq,max-counts",
.reg_grp = IQS7222_REG_GRP_GLBL, .reg_grp = IQS7222_REG_GRP_GLBL,
...@@ -1272,9 +1267,22 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222) ...@@ -1272,9 +1267,22 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
struct i2c_client *client = iqs7222->client; struct i2c_client *client = iqs7222->client;
ktime_t ati_timeout; ktime_t ati_timeout;
u16 sys_status = 0; u16 sys_status = 0;
u16 sys_setup = iqs7222->sys_setup[0] & ~IQS7222_SYS_SETUP_ACK_RESET; u16 sys_setup;
int error, i; int error, i;
/*
* The reserved fields of the system setup register may have changed
* as a result of other registers having been written. As such, read
* the register's latest value to avoid unexpected behavior when the
* register is written in the loop that follows.
*/
error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup);
if (error)
return error;
sys_setup &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
sys_setup &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
for (i = 0; i < IQS7222_NUM_RETRIES; i++) { for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
/* /*
* Trigger ATI from streaming and normal-power modes so that * Trigger ATI from streaming and normal-power modes so that
...@@ -1299,12 +1307,15 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222) ...@@ -1299,12 +1307,15 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
if (error) if (error)
return error; return error;
if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE) if (sys_status & IQS7222_SYS_STATUS_RESET)
continue; return 0;
if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR) if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR)
break; break;
if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE)
continue;
/* /*
* Use stream-in-touch mode if either slider reports * Use stream-in-touch mode if either slider reports
* absolute position. * absolute position.
...@@ -1321,7 +1332,7 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222) ...@@ -1321,7 +1332,7 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
dev_err(&client->dev, dev_err(&client->dev,
"ATI attempt %d of %d failed with status 0x%02X, %s\n", "ATI attempt %d of %d failed with status 0x%02X, %s\n",
i + 1, IQS7222_NUM_RETRIES, (u8)sys_status, i + 1, IQS7222_NUM_RETRIES, (u8)sys_status,
i < IQS7222_NUM_RETRIES ? "retrying..." : "stopping"); i + 1 < IQS7222_NUM_RETRIES ? "retrying" : "stopping");
} }
return -ETIMEDOUT; return -ETIMEDOUT;
...@@ -1333,6 +1344,34 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir) ...@@ -1333,6 +1344,34 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
int comms_offset = dev_desc->comms_offset; int comms_offset = dev_desc->comms_offset;
int error, i, j, k; int error, i, j, k;
/*
* Acknowledge reset before writing any registers in case the device
* suffers a spurious reset during initialization. Because this step
* may change the reserved fields of the second filter beta register,
* its cache must be updated.
*
* Writing the second filter beta register, in turn, may clobber the
* system status register. As such, the filter beta register pair is
* written first to protect against this hazard.
*/
if (dir == WRITE) {
u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1;
u16 filt_setup;
error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
iqs7222->sys_setup[0] |
IQS7222_SYS_SETUP_ACK_RESET);
if (error)
return error;
error = iqs7222_read_word(iqs7222, reg, &filt_setup);
if (error)
return error;
iqs7222->filt_setup[1] &= GENMASK(7, 0);
iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0));
}
/* /*
* Take advantage of the stop-bit disable function, if available, to * Take advantage of the stop-bit disable function, if available, to
* save the trouble of having to reopen a communication window after * save the trouble of having to reopen a communication window after
...@@ -1957,8 +1996,8 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index) ...@@ -1957,8 +1996,8 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index)
int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
int ext_chan = rounddown(num_chan, 10); int ext_chan = rounddown(num_chan, 10);
int count, error, reg_offset, i; int count, error, reg_offset, i;
u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
u16 *sldr_setup = iqs7222->sldr_setup[sldr_index]; u16 *sldr_setup = iqs7222->sldr_setup[sldr_index];
u16 *sys_setup = iqs7222->sys_setup;
unsigned int chan_sel[4], val; unsigned int chan_sel[4], val;
error = iqs7222_parse_props(iqs7222, &sldr_node, sldr_index, error = iqs7222_parse_props(iqs7222, &sldr_node, sldr_index,
...@@ -2003,7 +2042,7 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index) ...@@ -2003,7 +2042,7 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index)
reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1; reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1;
sldr_setup[0] |= count; sldr_setup[0] |= count;
sldr_setup[3 + reg_offset] &= ~IQS7222_SLDR_SETUP_3_CHAN_SEL_MASK; sldr_setup[3 + reg_offset] &= ~GENMASK(ext_chan - 1, 0);
for (i = 0; i < ARRAY_SIZE(chan_sel); i++) { for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
sldr_setup[5 + reg_offset + i] = 0; sldr_setup[5 + reg_offset + i] = 0;
...@@ -2081,17 +2120,19 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index) ...@@ -2081,17 +2120,19 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index)
sldr_setup[0] |= dev_desc->wheel_enable; 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 * The absence of a register offset makes it safe to assume the device
* in the group represent gesture settings. * supports gestures, each of which is first disabled until explicitly
* enabled.
*/ */
if (iqs7222_sl_events[i].enable && !reg_offset) if (!reg_offset)
for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++)
sldr_setup[9] &= ~iqs7222_sl_events[i].enable; sldr_setup[9] &= ~iqs7222_sl_events[i].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;
event_node = fwnode_get_named_child_node(sldr_node, event_name); event_node = fwnode_get_named_child_node(sldr_node, event_name);
if (!event_node) if (!event_node)
continue; continue;
...@@ -2104,6 +2145,22 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index) ...@@ -2104,6 +2145,22 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index)
if (error) if (error)
return error; return error;
/*
* The press/release event does not expose a direct GPIO link,
* but one can be emulated by tying each of the participating
* channels to the same GPIO.
*/
error = iqs7222_gpio_select(iqs7222, event_node,
i ? iqs7222_sl_events[i].enable
: sldr_setup[3 + reg_offset],
i ? 1568 + sldr_index * 30
: sldr_setup[4 + reg_offset]);
if (error)
return error;
if (!reg_offset)
sldr_setup[9] |= iqs7222_sl_events[i].enable;
error = fwnode_property_read_u32(event_node, "linux,code", error = fwnode_property_read_u32(event_node, "linux,code",
&val); &val);
if (error) { if (error) {
...@@ -2115,26 +2172,20 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index) ...@@ -2115,26 +2172,20 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, int sldr_index)
iqs7222->sl_code[sldr_index][i] = val; iqs7222->sl_code[sldr_index][i] = val;
input_set_capability(iqs7222->keypad, EV_KEY, 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) if (!dev_desc->event_offset)
continue; continue;
sys_setup[dev_desc->event_offset] |= BIT(10 + sldr_index); /*
* The press/release event is determined based on whether the
* coordinate field reports 0xFFFF and solely relies on touch
* or proximity interrupts to be unmasked.
*/
if (i && !reg_offset)
*event_mask |= (IQS7222_EVENT_MASK_SLDR << sldr_index);
else if (sldr_setup[4 + reg_offset] == dev_desc->touch_link)
*event_mask |= IQS7222_EVENT_MASK_TOUCH;
else
*event_mask |= IQS7222_EVENT_MASK_PROX;
} }
/* /*
...@@ -2227,11 +2278,6 @@ static int iqs7222_parse_all(struct iqs7222_private *iqs7222) ...@@ -2227,11 +2278,6 @@ static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
return 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, return iqs7222_parse_props(iqs7222, NULL, 0, IQS7222_REG_GRP_SYS,
IQS7222_REG_KEY_NONE); IQS7222_REG_KEY_NONE);
} }
...@@ -2299,29 +2345,37 @@ static int iqs7222_report(struct iqs7222_private *iqs7222) ...@@ -2299,29 +2345,37 @@ static int iqs7222_report(struct iqs7222_private *iqs7222)
input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i], input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i],
sldr_pos); sldr_pos);
for (j = 0; j < ARRAY_SIZE(iqs7222_sl_events); j++) { input_report_key(iqs7222->keypad, iqs7222->sl_code[i][0],
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); sldr_pos < dev_desc->sldr_res);
continue;
}
/* /*
* The remaining offsets represent gesture state, and * A maximum resolution indicates the device does not support
* are discarded in the case of IQS7222C because only * gestures, in which case the remaining fields are ignored.
* absolute position is reported.
*/ */
if (num_stat < IQS7222_MAX_COLS_STAT) if (dev_desc->sldr_res == U16_MAX)
continue; continue;
if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_SLDR << i))
continue;
/*
* Skip the press/release event, as it does not have separate
* status fields and is handled separately.
*/
for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) {
u16 mask = iqs7222_sl_events[j].mask;
u16 val = iqs7222_sl_events[j].val;
input_report_key(iqs7222->keypad, input_report_key(iqs7222->keypad,
iqs7222->sl_code[i][j], iqs7222->sl_code[i][j],
(state & mask) == val); (state & mask) == val);
} }
input_sync(iqs7222->keypad);
for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++)
input_report_key(iqs7222->keypad,
iqs7222->sl_code[i][j], 0);
} }
input_sync(iqs7222->keypad); input_sync(iqs7222->keypad);
......
...@@ -41,7 +41,7 @@ struct gpio_mouse { ...@@ -41,7 +41,7 @@ struct gpio_mouse {
/* /*
* Timer function which is run every scan_ms ms when the device is opened. * Timer function which is run every scan_ms ms when the device is opened.
* The dev input variable is set to the the input_dev pointer. * The dev input variable is set to the input_dev pointer.
*/ */
static void gpio_mouse_scan(struct input_dev *input) static void gpio_mouse_scan(struct input_dev *input)
{ {
......
...@@ -67,612 +67,775 @@ static inline void i8042_write_command(int val) ...@@ -67,612 +67,775 @@ static inline void i8042_write_command(int val)
#include <linux/dmi.h> #include <linux/dmi.h>
static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { #define SERIO_QUIRK_NOKBD BIT(0)
{ #define SERIO_QUIRK_NOAUX BIT(1)
/* #define SERIO_QUIRK_NOMUX BIT(2)
* Arima-Rioworks HDAMB - #define SERIO_QUIRK_FORCEMUX BIT(3)
* AUX LOOP command does not raise AUX IRQ #define SERIO_QUIRK_UNLOCK BIT(4)
#define SERIO_QUIRK_PROBE_DEFER BIT(5)
#define SERIO_QUIRK_RESET_ALWAYS BIT(6)
#define SERIO_QUIRK_RESET_NEVER BIT(7)
#define SERIO_QUIRK_DIECT BIT(8)
#define SERIO_QUIRK_DUMBKBD BIT(9)
#define SERIO_QUIRK_NOLOOP BIT(10)
#define SERIO_QUIRK_NOTIMEOUT BIT(11)
#define SERIO_QUIRK_KBDRESET BIT(12)
#define SERIO_QUIRK_DRITEK BIT(13)
#define SERIO_QUIRK_NOPNP BIT(14)
/* Quirk table for different mainboards. Options similar or identical to i8042
* module parameters.
* ORDERING IS IMPORTANT! The first match will be apllied and the rest ignored.
* This allows entries to overwrite vendor wide quirks on a per device basis.
* Where this is irrelevant, entries are sorted case sensitive by DMI_SYS_VENDOR
* and/or DMI_BOARD_VENDOR to make it easier to avoid dublicate entries.
*/ */
static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
{
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"), DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
DMI_MATCH(DMI_BOARD_NAME, "HDAMB"), DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
DMI_MATCH(DMI_BOARD_VERSION, "Rev E"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* ASUS G1S */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BOARD_NAME, "G1S"), DMI_MATCH(DMI_PRODUCT_NAME, "X750LN"),
DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */ /* Asus X450LCP */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"), DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
DMI_MATCH(DMI_BOARD_VERSION, "REV 2.X"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_NEVER)
}, },
{ {
/* ASUS ZenBook UX425UA */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X750LN"), DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"),
}, },
.driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER)
}, },
{ {
/* ASUS ZenBook UM325UA */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
DMI_MATCH(DMI_PRODUCT_VERSION, "8500"),
}, },
.driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER)
}, },
/*
* On some Asus laptops, just running self tests cause problems.
*/
{ {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_NEVER)
}, },
{ {
/* Dell Embedded Box PC 3000 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"), DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_NEVER)
}, },
{ {
/* OQO Model 01 */ /* ASUS P65UP5 - AUX LOOP command does not raise AUX IRQ */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "OQO"), DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), DMI_MATCH(DMI_BOARD_NAME, "P/I-P65UP5"),
DMI_MATCH(DMI_PRODUCT_VERSION, "00"), DMI_MATCH(DMI_BOARD_VERSION, "REV 2.X"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* ULI EV4873 - AUX LOOP does not work properly */ /* ASUS G1S */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ULI"), DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"), DMI_MATCH(DMI_BOARD_NAME, "G1S"),
DMI_MATCH(DMI_PRODUCT_VERSION, "5a"), DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Microsoft Virtual Machine */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Medion MAM 2070 */ /* Acer Aspire 5710 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"),
DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Medion Akoya E7225 */ /* Acer Aspire 7738 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Medion"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"),
DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Blue FB5601 */ /* Acer Aspire 5536 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "blue"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"),
DMI_MATCH(DMI_PRODUCT_VERSION, "M606"), DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Gigabyte M912 */ /*
* Acer Aspire 5738z
* Touchpad stops working in mux mode when dis- + re-enabled
* with the touchpad enable/disable toggle hotkey
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "M912"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
DMI_MATCH(DMI_PRODUCT_VERSION, "01"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Gigabyte M1022M netbook */ /* Acer Aspire One 150 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_BOARD_NAME, "M1022E"), DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
DMI_MATCH(DMI_BOARD_VERSION, "1.02"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Gigabyte Spring Peak - defines wrong chassis type */ /* Acer Aspire One 532h */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"), DMI_MATCH(DMI_PRODUCT_NAME, "AO532h"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Gigabyte T1005 - defines wrong chassis type ("Other") */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "T1005"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A114-31"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Gigabyte T1005M/P - defines wrong chassis type ("Other") */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A314-31"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-31"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "C15B"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-332"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ }
};
/*
* Some Fujitsu notebooks are having trouble with touchpads if
* active multiplexing mode is activated. Luckily they don't have
* external PS/2 ports so we can safely disable it.
* ... apparently some Toshibas don't like MUX mode either and
* die horrible death on reboot.
*/
static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
{ {
/* Fujitsu Lifebook P7010/P7010D */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "P7010"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-432"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Fujitsu Lifebook P7010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate Spin B118-RN"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
/*
* Some Wistron based laptops need us to explicitly enable the 'Dritek
* keyboard extension' to make their extra keys start generating scancodes.
* Originally, this was just confined to older laptops, but a few Acer laptops
* have turned up in 2007 that also need this again.
*/
{ {
/* Fujitsu Lifebook P5020D */ /* Acer Aspire 5100 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu Lifebook S2000 */ /* Acer Aspire 5610 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu Lifebook S6230 */ /* Acer Aspire 5630 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu Lifebook T725 laptop */ /* Acer Aspire 5650 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu Lifebook U745 */ /* Acer Aspire 5680 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu T70H */ /* Acer Aspire 5720 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu-Siemens Lifebook T3010 */ /* Acer Aspire 9110 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu-Siemens Lifebook E4010 */ /* Acer TravelMate 660 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu-Siemens Amilo Pro 2010 */ /* Acer TravelMate 2490 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* Fujitsu-Siemens Amilo Pro 2030 */ /* Acer TravelMate 4280 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"),
}, },
.driver_data = (void *)(SERIO_QUIRK_DRITEK)
}, },
{ {
/* /* Amoi M636/A737 */
* No data is coming from the touchscreen unless KBC
* is in legacy mode.
*/
/* Panasonic CF-29 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"), DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"), DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/*
* HP Pavilion DV4017EA -
* errors on MUX ports are reported without raising AUXDATA
* causing "spurious NAK" messages.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "ByteSpeed LLC"),
DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"), DMI_MATCH(DMI_PRODUCT_NAME, "ByteSpeed Laptop C15B"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* /* Compal HEL80I */
* HP Pavilion ZT1000 -
* like DV4017EA does not raise AUXERR for errors on MUX ports.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"), DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"),
DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook ZT1000"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/*
* HP Pavilion DV4270ca -
* like DV4017EA does not raise AUXERR for errors on MUX ports.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"), DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant"),
DMI_MATCH(DMI_PRODUCT_VERSION, "8500"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant"),
DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Advent 4211 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"),
DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Dell Embedded Box PC 3000 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"), DMI_MATCH(DMI_PRODUCT_NAME, "Embedded Box PC 3000"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Dell XPS M1530 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"), DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Sharp Actius MM20 */ /* Dell Vostro 1510 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SHARP"), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Sony Vaio FS-115b */ /* Dell Vostro V13 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT)
}, },
{ {
/* /* Dell Vostro 1320 */
* Sony Vaio FZ-240E -
* reset and GET ID commands issued via KBD port are
* sometimes being delivered to AUX3.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"), DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"),
},
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
},
{
/* Dell Vostro 1520 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"),
},
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
},
{
/* Dell Vostro 1720 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Entroware Proteus */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Entroware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"),
DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS)
},
/* /*
* Most (all?) VAIOs do not have external PS/2 ports nor * Some Fujitsu notebooks are having trouble with touchpads if
* they implement active multiplexing properly, and * active multiplexing mode is activated. Luckily they don't have
* MUX discovery usually messes up keyboard/touchpad. * external PS/2 ports so we can safely disable it.
* ... apparently some Toshibas don't like MUX mode either and
* die horrible death on reboot.
*/ */
{
/* Fujitsu Lifebook P7010/P7010D */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_BOARD_NAME, "VAIO"), DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Amoi M636/A737 */ /* Fujitsu Lifebook P5020D */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Lenovo 3000 n100 */ /* Fujitsu Lifebook S2000 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "076804U"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Lenovo XiaoXin Air 12 */ /* Fujitsu Lifebook S6230 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "80UN"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Fujitsu Lifebook T725 laptop */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT)
}, },
{ {
/* Acer Aspire 5710 */ /* Fujitsu Lifebook U745 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Acer Aspire 7738 */ /* Fujitsu T70H */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"), DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Gericom Bellagio */ /* Fujitsu A544 laptop */
/* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Gericom"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
}, },
{ {
/* IBM 2656 */ /* Fujitsu AH544 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IBM"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "2656"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
}, },
{ {
/* Dell XPS M1530 */ /* Fujitsu U574 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "XPS M1530"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
}, },
{ {
/* Compal HEL80I */ /* Fujitsu UH554 laptop */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "COMPAL"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOTIMEOUT)
}, },
{ {
/* Dell Vostro 1510 */ /* Fujitsu Lifebook P7010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro1510"), DMI_MATCH(DMI_PRODUCT_NAME, "0000000000"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Acer Aspire 5536 */ /* Fujitsu-Siemens Lifebook T3010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5536"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"),
DMI_MATCH(DMI_PRODUCT_VERSION, "0100"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Dell Vostro V13 */ /* Fujitsu-Siemens Lifebook E4010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Newer HP Pavilion dv4 models */ /* Fujitsu-Siemens Amilo Pro 2010 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Asus X450LCP */ /* Fujitsu-Siemens Amilo Pro 2030 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Avatar AVIU-145A6 */ /* Gigabyte M912 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel"), DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"), DMI_MATCH(DMI_PRODUCT_NAME, "M912"),
DMI_MATCH(DMI_PRODUCT_VERSION, "01"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* TUXEDO BU1406 */ /* Gigabyte Spring Peak - defines wrong chassis type */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"), DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Lenovo LaVie Z */ /* Gigabyte T1005 - defines wrong chassis type ("Other") */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"), DMI_MATCH(DMI_PRODUCT_NAME, "T1005"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Gigabyte T1005M/P - defines wrong chassis type ("Other") */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"),
},
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
},
/* /*
* Acer Aspire 5738z * Some laptops need keyboard reset before probing for the trackpad to get
* Touchpad stops working in mux mode when dis- + re-enabled * it detected, initialised & finally work.
* with the touchpad enable/disable toggle hotkey
*/ */
{
/* Gigabyte P35 v2 - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"), DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"),
}, },
.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
}, },
{ {
/* Entroware Proteus */ /* Aorus branded Gigabyte X3 Plus - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Entroware"), DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"), DMI_MATCH(DMI_PRODUCT_NAME, "X3"),
DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
}, },
.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
},
{
/* Gigabyte P34 - Elantech touchpad */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
},
.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
},
{
/* Gigabyte P57 - Elantech touchpad */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
},
.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
},
{
/* Gericom Bellagio */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Gericom"),
DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
},
{
/* Gigabyte M1022M netbook */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co.,Ltd."),
DMI_MATCH(DMI_BOARD_NAME, "M1022E"),
DMI_MATCH(DMI_BOARD_VERSION, "1.02"),
},
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
},
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ }
};
static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = {
{ {
/* /*
* Sony Vaio VGN-CS series require MUX or the touch sensor * HP Pavilion DV4017EA -
* buttons will disturb touchpad operation * errors on MUX ports are reported without raising AUXDATA
* causing "spurious NAK" messages.
*/ */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"), DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ } {
}; /*
* HP Pavilion ZT1000 -
/* * like DV4017EA does not raise AUXERR for errors on MUX ports.
* On some Asus laptops, just running self tests cause problems.
*/ */
static const struct dmi_system_id i8042_dmi_noselftest_table[] = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Notebook PC"),
DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook ZT1000"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
},
{ {
/*
* HP Pavilion DV4270ca -
* like DV4017EA does not raise AUXERR for errors on MUX ports.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
}, { {
/* Newer HP Pavilion dv4 models */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_NOTIMEOUT)
}, },
{ }
};
static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
{ {
/* MSI Wind U-100 */ /* IBM 2656 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* LG Electronics X110 */ /* Avatar AVIU-145A6 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "X110"), DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "IC4I"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Acer Aspire One 150 */ /* Intel MBO Desktop D845PESV */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), DMI_MATCH(DMI_BOARD_NAME, "D845PESV"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOPNP)
}, },
{ {
/*
* Intel NUC D54250WYK - does not have i8042 controller but
* declares PS/2 devices in DSDT.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A114-31"), DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOPNP)
}, },
{ {
/* Lenovo 3000 n100 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A314-31"), DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Lenovo XiaoXin Air 12 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-31"), DMI_MATCH(DMI_PRODUCT_NAME, "80UN"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Lenovo LaVie Z */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"), DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo LaVie Z"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Lenovo Ideapad U455 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-332"), DMI_MATCH(DMI_PRODUCT_NAME, "20046"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Lenovo ThinkPad L460 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-432"), DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Lenovo ThinkPad Twist S230u */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate Spin B118-RN"), DMI_MATCH(DMI_PRODUCT_NAME, "33474HU"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Advent 4211 */ /* LG Electronics X110 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "DIXONSXP"), DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Advent 4211"), DMI_MATCH(DMI_BOARD_NAME, "X110"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Medion Akoya Mini E1210 */ /* Medion Akoya Mini E1210 */
...@@ -680,6 +843,7 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { ...@@ -680,6 +843,7 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
DMI_MATCH(DMI_PRODUCT_NAME, "E1210"), DMI_MATCH(DMI_PRODUCT_NAME, "E1210"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Medion Akoya E1222 */ /* Medion Akoya E1222 */
...@@ -687,331 +851,434 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { ...@@ -687,331 +851,434 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
DMI_MATCH(DMI_PRODUCT_NAME, "E122X"), DMI_MATCH(DMI_PRODUCT_NAME, "E122X"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ {
/* Mivvy M310 */ /* MSI Wind U-100 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"), DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
DMI_MATCH(DMI_PRODUCT_NAME, "N10"), DMI_MATCH(DMI_BOARD_NAME, "U-100"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Dell Vostro 1320 */ /*
* No data is coming from the touchscreen unless KBC
* is in legacy mode.
*/
/* Panasonic CF-29 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1320"), DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Dell Vostro 1520 */ /* Medion Akoya E7225 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1520"), DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"),
DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Dell Vostro 1720 */ /* Microsoft Virtual Machine */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1720"), DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
DMI_MATCH(DMI_PRODUCT_VERSION, "VS2005R2"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Lenovo Ideapad U455 */ /* Medion MAM 2070 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
DMI_MATCH(DMI_PRODUCT_NAME, "20046"), DMI_MATCH(DMI_PRODUCT_NAME, "MAM 2070"),
DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Lenovo ThinkPad L460 */ /* TUXEDO BU1406 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"), DMI_MATCH(DMI_PRODUCT_NAME, "N24_25BU"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */ /* OQO Model 01 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"), DMI_MATCH(DMI_SYS_VENDOR, "OQO"),
DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"), DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "00"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
{ {
/* Lenovo ThinkPad Twist S230u */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
DMI_MATCH(DMI_PRODUCT_NAME, "33474HU"), DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
},
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
},
{
/* Acer Aspire 5 A515 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "PK"),
DMI_MATCH(DMI_BOARD_NAME, "Grumpy_PK"),
},
.driver_data = (void *)(SERIO_QUIRK_NOPNP)
},
{
/* ULI EV4873 - AUX LOOP does not work properly */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ULI"),
DMI_MATCH(DMI_PRODUCT_NAME, "EV4873"),
DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
},
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
},
{
/*
* Arima-Rioworks HDAMB -
* AUX LOOP command does not raise AUX IRQ
*/
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "RIOWORKS"),
DMI_MATCH(DMI_BOARD_NAME, "HDAMB"),
DMI_MATCH(DMI_BOARD_VERSION, "Rev E"),
},
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
},
{
/* Sharp Actius MM20 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
},
{
/*
* Sony Vaio FZ-240E -
* reset and GET ID commands issued via KBD port are
* sometimes being delivered to AUX3.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ240E"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Entroware Proteus */ /*
* Most (all?) VAIOs do not have external PS/2 ports nor
* they implement active multiplexing properly, and
* MUX discovery usually messes up keyboard/touchpad.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Entroware"), DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Proteus"), DMI_MATCH(DMI_BOARD_NAME, "VAIO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "EL07R4"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ }
};
#ifdef CONFIG_PNP
static const struct dmi_system_id __initconst i8042_dmi_nopnp_table[] = {
{ {
/* Intel MBO Desktop D845PESV */ /* Sony Vaio FS-115b */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "D845PESV"), DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* /*
* Intel NUC D54250WYK - does not have i8042 controller but * Sony Vaio VGN-CS series require MUX or the touch sensor
* declares PS/2 devices in DSDT. * buttons will disturb touchpad operation
*/ */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "D54250WYK"), DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
}, },
.driver_data = (void *)(SERIO_QUIRK_FORCEMUX)
}, },
{ {
/* MSI Wind U-100 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "U-100"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ {
/* Acer Aspire 5 A515 */
.matches = { .matches = {
DMI_MATCH(DMI_BOARD_NAME, "Grumpy_PK"), DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_BOARD_VENDOR, "PK"), DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
{ }
};
static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = {
{ {
.matches = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE C850D"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
}, },
/*
* A lot of modern Clevo barebones have touchpad and/or keyboard issues
* after suspend fixable with nomux + reset + noloop + nopnp. Luckily,
* none of them have an external PS/2 port so this can safely be set for
* all of them. These two are based on a Clevo design, but have the
* board_name changed.
*/
{ {
.matches = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */ DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
.matches = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Mivvy M310 */
.matches = { .matches = {
DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */ DMI_MATCH(DMI_SYS_VENDOR, "VIOOO"),
DMI_MATCH(DMI_PRODUCT_NAME, "N10"),
}, },
.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
}, },
{ } /*
}; * Some laptops need keyboard reset before probing for the trackpad to get
#endif * it detected, initialised & finally work.
*/
static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
{ {
/* Dell Vostro V13 */ /* Schenker XMG C504 - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "XMG"),
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), DMI_MATCH(DMI_PRODUCT_NAME, "C504"),
}, },
.driver_data = (void *)(SERIO_QUIRK_KBDRESET)
}, },
{ {
/* Newer HP Pavilion dv4 models */ /* Blue FB5601 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "blue"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), DMI_MATCH(DMI_PRODUCT_NAME, "FB5601"),
DMI_MATCH(DMI_PRODUCT_VERSION, "M606"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
/*
* A lot of modern Clevo barebones have touchpad and/or keyboard issues
* after suspend fixable with nomux + reset + noloop + nopnp. Luckily,
* none of them have an external PS/2 port so this can safely be set for
* all of them.
* Clevo barebones come with board_vendor and/or system_vendor set to
* either the very generic string "Notebook" and/or a different value
* for each individual reseller. The only somewhat universal way to
* identify them is by board_name.
*/
{ {
/* Fujitsu A544 laptop */
/* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Fujitsu AH544 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Fujitsu Lifebook T725 laptop */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_BOARD_NAME, "N140CU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T725"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Fujitsu U574 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_BOARD_NAME, "N141CU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U574"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Fujitsu UH554 laptop */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK UH544"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ }
};
/*
* Some Wistron based laptops need us to explicitly enable the 'Dritek
* keyboard extension' to make their extra keys start generating scancodes.
* Originally, this was just confined to older laptops, but a few Acer laptops
* have turned up in 2007 that also need this again.
*/
static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
{ {
/* Acer Aspire 5100 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
/*
* At least one modern Clevo barebone has the touchpad connected both
* via PS/2 and i2c interface. This causes a race condition between the
* psmouse and i2c-hid driver. Since the full capability of the touchpad
* is available via the i2c interface and the device has no external
* PS/2 port, it is safe to just ignore all ps2 mouses here to avoid
* this issue. The known affected device is the
* TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU which comes with one of
* the two different dmi strings below. NS50MU is not a typo!
*/
{ {
/* Acer Aspire 5610 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_BOARD_NAME, "NS50MU"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX |
SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer Aspire 5630 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_BOARD_NAME, "NS50_70MU"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX |
SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer Aspire 5650 */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_BOARD_NAME, "NJ50_70CU"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer Aspire 5680 */ /*
* This is only a partial board_name and might be followed by
* another letter or number. DMI_MATCH however does do partial
* matching.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "P65xH"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer Aspire 5720 */ /* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer Aspire 9110 */ /*
* This is only a partial board_name and might be followed by
* another letter or number. DMI_MATCH however does do partial
* matching.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "P65_P67H"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer TravelMate 660 */ /*
* This is only a partial board_name and might be followed by
* another letter or number. DMI_MATCH however does do partial
* matching.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "P65_67RP"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer TravelMate 2490 */ /*
* This is only a partial board_name and might be followed by
* another letter or number. DMI_MATCH however does do partial
* matching.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "P65_67RS"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Acer TravelMate 4280 */ /*
* This is only a partial board_name and might be followed by
* another letter or number. DMI_MATCH however does do partial
* matching.
*/
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_NAME, "P67xRP"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ }
};
/*
* Some laptops need keyboard reset before probing for the trackpad to get
* it detected, initialised & finally work.
*/
static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
{ {
/* Gigabyte P35 v2 - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_BOARD_NAME, "PB50_70DFx,DDx"),
DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Aorus branded Gigabyte X3 Plus - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_BOARD_NAME, "X170SM"),
DMI_MATCH(DMI_PRODUCT_NAME, "X3"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ {
/* Gigabyte P34 - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_BOARD_NAME, "X170KM-G"),
DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
}, },
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
}, },
{ }
};
#ifdef CONFIG_PNP
static const struct dmi_system_id i8042_dmi_laptop_table[] __initconst = {
{ {
/* Gigabyte P57 - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
}, },
}, },
{ {
/* Schenker XMG C504 - Elantech touchpad */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "XMG"), DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
DMI_MATCH(DMI_PRODUCT_NAME, "C504"),
}, },
}, },
{ }
};
static const struct dmi_system_id i8042_dmi_probe_defer_table[] __initconst = {
{ {
/* ASUS ZenBook UX425UA */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX425UA"),
}, },
}, },
{ {
/* ASUS ZenBook UM325UA */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
}, },
}, },
{ } { }
}; };
#endif
#endif /* CONFIG_X86 */ #endif /* CONFIG_X86 */
...@@ -1167,11 +1434,6 @@ static int __init i8042_pnp_init(void) ...@@ -1167,11 +1434,6 @@ static int __init i8042_pnp_init(void)
bool pnp_data_busted = false; bool pnp_data_busted = false;
int err; int err;
#ifdef CONFIG_X86
if (dmi_check_system(i8042_dmi_nopnp_table))
i8042_nopnp = true;
#endif
if (i8042_nopnp) { if (i8042_nopnp) {
pr_info("PNP detection disabled\n"); pr_info("PNP detection disabled\n");
return 0; return 0;
...@@ -1275,6 +1537,59 @@ static inline int i8042_pnp_init(void) { return 0; } ...@@ -1275,6 +1537,59 @@ static inline int i8042_pnp_init(void) { return 0; }
static inline void i8042_pnp_exit(void) { } static inline void i8042_pnp_exit(void) { }
#endif /* CONFIG_PNP */ #endif /* CONFIG_PNP */
#ifdef CONFIG_X86
static void __init i8042_check_quirks(void)
{
const struct dmi_system_id *device_quirk_info;
uintptr_t quirks;
device_quirk_info = dmi_first_match(i8042_dmi_quirk_table);
if (!device_quirk_info)
return;
quirks = (uintptr_t)device_quirk_info->driver_data;
if (quirks & SERIO_QUIRK_NOKBD)
i8042_nokbd = true;
if (quirks & SERIO_QUIRK_NOAUX)
i8042_noaux = true;
if (quirks & SERIO_QUIRK_NOMUX)
i8042_nomux = true;
if (quirks & SERIO_QUIRK_FORCEMUX)
i8042_nomux = false;
if (quirks & SERIO_QUIRK_UNLOCK)
i8042_unlock = true;
if (quirks & SERIO_QUIRK_PROBE_DEFER)
i8042_probe_defer = true;
/* Honor module parameter when value is not default */
if (i8042_reset == I8042_RESET_DEFAULT) {
if (quirks & SERIO_QUIRK_RESET_ALWAYS)
i8042_reset = I8042_RESET_ALWAYS;
if (quirks & SERIO_QUIRK_RESET_NEVER)
i8042_reset = I8042_RESET_NEVER;
}
if (quirks & SERIO_QUIRK_DIECT)
i8042_direct = true;
if (quirks & SERIO_QUIRK_DUMBKBD)
i8042_dumbkbd = true;
if (quirks & SERIO_QUIRK_NOLOOP)
i8042_noloop = true;
if (quirks & SERIO_QUIRK_NOTIMEOUT)
i8042_notimeout = true;
if (quirks & SERIO_QUIRK_KBDRESET)
i8042_kbdreset = true;
if (quirks & SERIO_QUIRK_DRITEK)
i8042_dritek = true;
#ifdef CONFIG_PNP
if (quirks & SERIO_QUIRK_NOPNP)
i8042_nopnp = true;
#endif
}
#else
static inline void i8042_check_quirks(void) {}
#endif
static int __init i8042_platform_init(void) static int __init i8042_platform_init(void)
{ {
int retval; int retval;
...@@ -1297,45 +1612,42 @@ static int __init i8042_platform_init(void) ...@@ -1297,45 +1612,42 @@ static int __init i8042_platform_init(void)
i8042_kbd_irq = I8042_MAP_IRQ(1); i8042_kbd_irq = I8042_MAP_IRQ(1);
i8042_aux_irq = I8042_MAP_IRQ(12); i8042_aux_irq = I8042_MAP_IRQ(12);
retval = i8042_pnp_init();
if (retval)
return retval;
#if defined(__ia64__) #if defined(__ia64__)
i8042_reset = I8042_RESET_ALWAYS; i8042_reset = I8042_RESET_ALWAYS;
#endif #endif
i8042_check_quirks();
pr_debug("Active quirks (empty means none):%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
i8042_nokbd ? " nokbd" : "",
i8042_noaux ? " noaux" : "",
i8042_nomux ? " nomux" : "",
i8042_unlock ? " unlock" : "",
i8042_probe_defer ? "probe_defer" : "",
i8042_reset == I8042_RESET_DEFAULT ?
"" : i8042_reset == I8042_RESET_ALWAYS ?
" reset_always" : " reset_never",
i8042_direct ? " direct" : "",
i8042_dumbkbd ? " dumbkbd" : "",
i8042_noloop ? " noloop" : "",
i8042_notimeout ? " notimeout" : "",
i8042_kbdreset ? " kbdreset" : "",
#ifdef CONFIG_X86 #ifdef CONFIG_X86
/* Honor module parameter when value is not default */ i8042_dritek ? " dritek" : "",
if (i8042_reset == I8042_RESET_DEFAULT) { #else
if (dmi_check_system(i8042_dmi_reset_table)) "",
i8042_reset = I8042_RESET_ALWAYS; #endif
#ifdef CONFIG_PNP
if (dmi_check_system(i8042_dmi_noselftest_table)) i8042_nopnp ? " nopnp" : "");
i8042_reset = I8042_RESET_NEVER; #else
} "");
#endif
if (dmi_check_system(i8042_dmi_noloop_table))
i8042_noloop = true;
if (dmi_check_system(i8042_dmi_nomux_table))
i8042_nomux = true;
if (dmi_check_system(i8042_dmi_forcemux_table))
i8042_nomux = false;
if (dmi_check_system(i8042_dmi_notimeout_table))
i8042_notimeout = true;
if (dmi_check_system(i8042_dmi_dritek_table))
i8042_dritek = true;
if (dmi_check_system(i8042_dmi_kbdreset_table))
i8042_kbdreset = true;
if (dmi_check_system(i8042_dmi_probe_defer_table)) retval = i8042_pnp_init();
i8042_probe_defer = true; if (retval)
return retval;
#ifdef CONFIG_X86
/* /*
* A20 was already enabled during early kernel init. But some buggy * A20 was already enabled during early kernel init. But some buggy
* BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/property.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -47,6 +48,8 @@ ...@@ -47,6 +48,8 @@
#define M09_REGISTER_NUM_X 0x94 #define M09_REGISTER_NUM_X 0x94
#define M09_REGISTER_NUM_Y 0x95 #define M09_REGISTER_NUM_Y 0x95
#define M12_REGISTER_REPORT_RATE 0x88
#define EV_REGISTER_THRESHOLD 0x40 #define EV_REGISTER_THRESHOLD 0x40
#define EV_REGISTER_GAIN 0x41 #define EV_REGISTER_GAIN 0x41
#define EV_REGISTER_OFFSET_Y 0x45 #define EV_REGISTER_OFFSET_Y 0x45
...@@ -127,9 +130,12 @@ struct edt_ft5x06_ts_data { ...@@ -127,9 +130,12 @@ struct edt_ft5x06_ts_data {
int max_support_points; int max_support_points;
char name[EDT_NAME_LEN]; char name[EDT_NAME_LEN];
char fw_version[EDT_NAME_LEN];
struct edt_reg_addr reg_addr; struct edt_reg_addr reg_addr;
enum edt_ver version; enum edt_ver version;
unsigned int crc_errors;
unsigned int header_errors;
}; };
struct edt_i2c_chip_data { struct edt_i2c_chip_data {
...@@ -178,6 +184,7 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, ...@@ -178,6 +184,7 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
crc ^= buf[i]; crc ^= buf[i];
if (crc != buf[buflen-1]) { if (crc != buf[buflen-1]) {
tsdata->crc_errors++;
dev_err_ratelimited(&tsdata->client->dev, dev_err_ratelimited(&tsdata->client->dev,
"crc error: 0x%02x expected, got 0x%02x\n", "crc error: 0x%02x expected, got 0x%02x\n",
crc, buf[buflen-1]); crc, buf[buflen-1]);
...@@ -235,6 +242,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) ...@@ -235,6 +242,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
if (tsdata->version == EDT_M06) { if (tsdata->version == EDT_M06) {
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
rdbuf[2] != datalen) { rdbuf[2] != datalen) {
tsdata->header_errors++;
dev_err_ratelimited(dev, dev_err_ratelimited(dev,
"Unexpected header: %02x%02x%02x!\n", "Unexpected header: %02x%02x%02x!\n",
rdbuf[0], rdbuf[1], rdbuf[2]); rdbuf[0], rdbuf[1], rdbuf[2]);
...@@ -523,9 +531,55 @@ static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, ...@@ -523,9 +531,55 @@ static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255);
/* m06: range 3 to 14, m12: (0x64: 100Hz) */ /* m06: range 3 to 14, m12: range 1 to 255 */
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
NO_REGISTER, NO_REGISTER, 0, 255); M12_REGISTER_REPORT_RATE, NO_REGISTER, 0, 255);
static ssize_t model_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
return sysfs_emit(buf, "%s\n", tsdata->name);
}
static DEVICE_ATTR_RO(model);
static ssize_t fw_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
return sysfs_emit(buf, "%s\n", tsdata->fw_version);
}
static DEVICE_ATTR_RO(fw_version);
/* m06 only */
static ssize_t header_errors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
return sysfs_emit(buf, "%d\n", tsdata->header_errors);
}
static DEVICE_ATTR_RO(header_errors);
/* m06 only */
static ssize_t crc_errors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
return sysfs_emit(buf, "%d\n", tsdata->crc_errors);
}
static DEVICE_ATTR_RO(crc_errors);
static struct attribute *edt_ft5x06_attrs[] = { static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_gain.dattr.attr, &edt_ft5x06_attr_gain.dattr.attr,
...@@ -534,6 +588,10 @@ static struct attribute *edt_ft5x06_attrs[] = { ...@@ -534,6 +588,10 @@ static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_offset_y.dattr.attr, &edt_ft5x06_attr_offset_y.dattr.attr,
&edt_ft5x06_attr_threshold.dattr.attr, &edt_ft5x06_attr_threshold.dattr.attr,
&edt_ft5x06_attr_report_rate.dattr.attr, &edt_ft5x06_attr_report_rate.dattr.attr,
&dev_attr_model.attr,
&dev_attr_fw_version.attr,
&dev_attr_header_errors.attr,
&dev_attr_crc_errors.attr,
NULL NULL
}; };
...@@ -820,13 +878,13 @@ static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) ...@@ -820,13 +878,13 @@ static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
#endif /* CONFIG_DEBUGFS */ #endif /* CONFIG_DEBUGFS */
static int edt_ft5x06_ts_identify(struct i2c_client *client, static int edt_ft5x06_ts_identify(struct i2c_client *client,
struct edt_ft5x06_ts_data *tsdata, struct edt_ft5x06_ts_data *tsdata)
char *fw_version)
{ {
u8 rdbuf[EDT_NAME_LEN]; u8 rdbuf[EDT_NAME_LEN];
char *p; char *p;
int error; int error;
char *model_name = tsdata->name; char *model_name = tsdata->name;
char *fw_version = tsdata->fw_version;
/* see what we find if we assume it is a M06 * /* see what we find if we assume it is a M06 *
* if we get less than EDT_NAME_LEN, we don't want * if we get less than EDT_NAME_LEN, we don't want
...@@ -1030,7 +1088,8 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) ...@@ -1030,7 +1088,8 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
case EDT_M09: case EDT_M09:
case EDT_M12: case EDT_M12:
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
reg_addr->reg_report_rate = NO_REGISTER; reg_addr->reg_report_rate = tsdata->version == EDT_M12 ?
M12_REGISTER_REPORT_RATE : NO_REGISTER;
reg_addr->reg_gain = M09_REGISTER_GAIN; reg_addr->reg_gain = M09_REGISTER_GAIN;
reg_addr->reg_offset = M09_REGISTER_OFFSET; reg_addr->reg_offset = M09_REGISTER_OFFSET;
reg_addr->reg_offset_x = NO_REGISTER; reg_addr->reg_offset_x = NO_REGISTER;
...@@ -1081,7 +1140,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -1081,7 +1140,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
struct input_dev *input; struct input_dev *input;
unsigned long irq_flags; unsigned long irq_flags;
int error; int error;
char fw_version[EDT_NAME_LEN]; u32 report_rate;
dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
...@@ -1194,7 +1253,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -1194,7 +1253,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
tsdata->input = input; tsdata->input = input;
tsdata->factory_mode = false; tsdata->factory_mode = false;
error = edt_ft5x06_ts_identify(client, tsdata, fw_version); error = edt_ft5x06_ts_identify(client, tsdata);
if (error) { if (error) {
dev_err(&client->dev, "touchscreen probe failed\n"); dev_err(&client->dev, "touchscreen probe failed\n");
return error; return error;
...@@ -1210,9 +1269,30 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -1210,9 +1269,30 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
edt_ft5x06_ts_get_defaults(&client->dev, tsdata); edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
edt_ft5x06_ts_get_parameters(tsdata); edt_ft5x06_ts_get_parameters(tsdata);
if (tsdata->reg_addr.reg_report_rate != NO_REGISTER &&
!device_property_read_u32(&client->dev,
"report-rate-hz", &report_rate)) {
if (tsdata->version == EDT_M06)
tsdata->report_rate = clamp_val(report_rate, 30, 140);
else
tsdata->report_rate = clamp_val(report_rate, 1, 255);
if (report_rate != tsdata->report_rate)
dev_warn(&client->dev,
"report-rate %dHz is unsupported, use %dHz\n",
report_rate, tsdata->report_rate);
if (tsdata->version == EDT_M06)
tsdata->report_rate /= 10;
edt_ft5x06_register_write(tsdata,
tsdata->reg_addr.reg_report_rate,
tsdata->report_rate);
}
dev_dbg(&client->dev, dev_dbg(&client->dev,
"Model \"%s\", Rev. \"%s\", %dx%d sensors\n", "Model \"%s\", Rev. \"%s\", %dx%d sensors\n",
tsdata->name, fw_version, tsdata->num_x, tsdata->num_y); tsdata->name, tsdata->fw_version, tsdata->num_x, tsdata->num_y);
input->name = tsdata->name; input->name = tsdata->name;
input->id.bustype = BUS_I2C; input->id.bustype = BUS_I2C;
......
...@@ -220,6 +220,7 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request, ...@@ -220,6 +220,7 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request,
{ {
u8 buf[EXC3000_LEN_VENDOR_REQUEST] = { 0x67, 0x00, 0x42, 0x00, 0x03 }; u8 buf[EXC3000_LEN_VENDOR_REQUEST] = { 0x67, 0x00, 0x42, 0x00, 0x03 };
int ret; int ret;
unsigned long time_left;
mutex_lock(&data->query_lock); mutex_lock(&data->query_lock);
...@@ -233,9 +234,9 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request, ...@@ -233,9 +234,9 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request,
goto out_unlock; goto out_unlock;
if (response) { if (response) {
ret = wait_for_completion_timeout(&data->wait_event, time_left = wait_for_completion_timeout(&data->wait_event,
timeout * HZ); timeout * HZ);
if (ret <= 0) { if (time_left == 0) {
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto out_unlock; goto out_unlock;
} }
......
...@@ -822,22 +822,16 @@ static int goodix_resource(struct acpi_resource *ares, void *data) ...@@ -822,22 +822,16 @@ static int goodix_resource(struct acpi_resource *ares, void *data)
struct device *dev = &ts->client->dev; struct device *dev = &ts->client->dev;
struct acpi_resource_gpio *gpio; struct acpi_resource_gpio *gpio;
switch (ares->type) { if (acpi_gpio_get_irq_resource(ares, &gpio)) {
case ACPI_RESOURCE_TYPE_GPIO:
gpio = &ares->data.gpio;
if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) {
if (ts->gpio_int_idx == -1) { if (ts->gpio_int_idx == -1) {
ts->gpio_int_idx = ts->gpio_count; ts->gpio_int_idx = ts->gpio_count;
} else { } else {
dev_err(dev, "More then one GpioInt resource, ignoring ACPI GPIO resources\n"); dev_err(dev, "More then one GpioInt resource, ignoring ACPI GPIO resources\n");
ts->gpio_int_idx = -2; ts->gpio_int_idx = -2;
} }
}
ts->gpio_count++; ts->gpio_count++;
break; } else if (acpi_gpio_get_io_resource(ares, &gpio))
default: ts->gpio_count++;
break;
}
return 0; return 0;
} }
......
...@@ -15,75 +15,75 @@ ...@@ -15,75 +15,75 @@
/* Register Map */ /* Register Map */
#define BT541_SWRESET_CMD 0x0000 #define ZINITIX_SWRESET_CMD 0x0000
#define BT541_WAKEUP_CMD 0x0001 #define ZINITIX_WAKEUP_CMD 0x0001
#define BT541_IDLE_CMD 0x0004 #define ZINITIX_IDLE_CMD 0x0004
#define BT541_SLEEP_CMD 0x0005 #define ZINITIX_SLEEP_CMD 0x0005
#define BT541_CLEAR_INT_STATUS_CMD 0x0003 #define ZINITIX_CLEAR_INT_STATUS_CMD 0x0003
#define BT541_CALIBRATE_CMD 0x0006 #define ZINITIX_CALIBRATE_CMD 0x0006
#define BT541_SAVE_STATUS_CMD 0x0007 #define ZINITIX_SAVE_STATUS_CMD 0x0007
#define BT541_SAVE_CALIBRATION_CMD 0x0008 #define ZINITIX_SAVE_CALIBRATION_CMD 0x0008
#define BT541_RECALL_FACTORY_CMD 0x000f #define ZINITIX_RECALL_FACTORY_CMD 0x000f
#define BT541_THRESHOLD 0x0020 #define ZINITIX_THRESHOLD 0x0020
#define BT541_LARGE_PALM_REJECT_AREA_TH 0x003F #define ZINITIX_LARGE_PALM_REJECT_AREA_TH 0x003F
#define BT541_DEBUG_REG 0x0115 /* 0~7 */ #define ZINITIX_DEBUG_REG 0x0115 /* 0~7 */
#define BT541_TOUCH_MODE 0x0010 #define ZINITIX_TOUCH_MODE 0x0010
#define BT541_CHIP_REVISION 0x0011 #define ZINITIX_CHIP_REVISION 0x0011
#define BT541_FIRMWARE_VERSION 0x0012 #define ZINITIX_FIRMWARE_VERSION 0x0012
#define ZINITIX_USB_DETECT 0x116 #define ZINITIX_USB_DETECT 0x116
#define BT541_MINOR_FW_VERSION 0x0121 #define ZINITIX_MINOR_FW_VERSION 0x0121
#define BT541_VENDOR_ID 0x001C #define ZINITIX_VENDOR_ID 0x001C
#define BT541_HW_ID 0x0014 #define ZINITIX_HW_ID 0x0014
#define BT541_DATA_VERSION_REG 0x0013 #define ZINITIX_DATA_VERSION_REG 0x0013
#define BT541_SUPPORTED_FINGER_NUM 0x0015 #define ZINITIX_SUPPORTED_FINGER_NUM 0x0015
#define BT541_EEPROM_INFO 0x0018 #define ZINITIX_EEPROM_INFO 0x0018
#define BT541_INITIAL_TOUCH_MODE 0x0019 #define ZINITIX_INITIAL_TOUCH_MODE 0x0019
#define BT541_TOTAL_NUMBER_OF_X 0x0060 #define ZINITIX_TOTAL_NUMBER_OF_X 0x0060
#define BT541_TOTAL_NUMBER_OF_Y 0x0061 #define ZINITIX_TOTAL_NUMBER_OF_Y 0x0061
#define BT541_DELAY_RAW_FOR_HOST 0x007f #define ZINITIX_DELAY_RAW_FOR_HOST 0x007f
#define BT541_BUTTON_SUPPORTED_NUM 0x00B0 #define ZINITIX_BUTTON_SUPPORTED_NUM 0x00B0
#define BT541_BUTTON_SENSITIVITY 0x00B2 #define ZINITIX_BUTTON_SENSITIVITY 0x00B2
#define BT541_DUMMY_BUTTON_SENSITIVITY 0X00C8 #define ZINITIX_DUMMY_BUTTON_SENSITIVITY 0X00C8
#define BT541_X_RESOLUTION 0x00C0 #define ZINITIX_X_RESOLUTION 0x00C0
#define BT541_Y_RESOLUTION 0x00C1 #define ZINITIX_Y_RESOLUTION 0x00C1
#define BT541_POINT_STATUS_REG 0x0080 #define ZINITIX_POINT_STATUS_REG 0x0080
#define BT541_ICON_STATUS_REG 0x00AA #define ZINITIX_ICON_STATUS_REG 0x00AA
#define BT541_POINT_COORD_REG (BT541_POINT_STATUS_REG + 2) #define ZINITIX_POINT_COORD_REG (ZINITIX_POINT_STATUS_REG + 2)
#define BT541_AFE_FREQUENCY 0x0100 #define ZINITIX_AFE_FREQUENCY 0x0100
#define BT541_DND_N_COUNT 0x0122 #define ZINITIX_DND_N_COUNT 0x0122
#define BT541_DND_U_COUNT 0x0135 #define ZINITIX_DND_U_COUNT 0x0135
#define BT541_RAWDATA_REG 0x0200 #define ZINITIX_RAWDATA_REG 0x0200
#define BT541_EEPROM_INFO_REG 0x0018 #define ZINITIX_EEPROM_INFO_REG 0x0018
#define BT541_INT_ENABLE_FLAG 0x00f0 #define ZINITIX_INT_ENABLE_FLAG 0x00f0
#define BT541_PERIODICAL_INTERRUPT_INTERVAL 0x00f1 #define ZINITIX_PERIODICAL_INTERRUPT_INTERVAL 0x00f1
#define BT541_BTN_WIDTH 0x016d #define ZINITIX_BTN_WIDTH 0x016d
#define BT541_CHECKSUM_RESULT 0x012c #define ZINITIX_CHECKSUM_RESULT 0x012c
#define BT541_INIT_FLASH 0x01d0 #define ZINITIX_INIT_FLASH 0x01d0
#define BT541_WRITE_FLASH 0x01d1 #define ZINITIX_WRITE_FLASH 0x01d1
#define BT541_READ_FLASH 0x01d2 #define ZINITIX_READ_FLASH 0x01d2
#define ZINITIX_INTERNAL_FLAG_02 0x011e #define ZINITIX_INTERNAL_FLAG_02 0x011e
#define ZINITIX_INTERNAL_FLAG_03 0x011f #define ZINITIX_INTERNAL_FLAG_03 0x011f
...@@ -196,13 +196,13 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541) ...@@ -196,13 +196,13 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
int i; int i;
int error; int error;
error = zinitix_write_cmd(client, BT541_SWRESET_CMD); error = zinitix_write_cmd(client, ZINITIX_SWRESET_CMD);
if (error) { if (error) {
dev_err(&client->dev, "Failed to write reset command\n"); dev_err(&client->dev, "Failed to write reset command\n");
return error; return error;
} }
error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG, 0x0); error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, 0x0);
if (error) { if (error) {
dev_err(&client->dev, dev_err(&client->dev,
"Failed to reset interrupt enable flag\n"); "Failed to reset interrupt enable flag\n");
...@@ -210,32 +210,32 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541) ...@@ -210,32 +210,32 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
} }
/* initialize */ /* initialize */
error = zinitix_write_u16(client, BT541_X_RESOLUTION, error = zinitix_write_u16(client, ZINITIX_X_RESOLUTION,
bt541->prop.max_x); bt541->prop.max_x);
if (error) if (error)
return error; return error;
error = zinitix_write_u16(client, BT541_Y_RESOLUTION, error = zinitix_write_u16(client, ZINITIX_Y_RESOLUTION,
bt541->prop.max_y); bt541->prop.max_y);
if (error) if (error)
return error; return error;
error = zinitix_write_u16(client, BT541_SUPPORTED_FINGER_NUM, error = zinitix_write_u16(client, ZINITIX_SUPPORTED_FINGER_NUM,
MAX_SUPPORTED_FINGER_NUM); MAX_SUPPORTED_FINGER_NUM);
if (error) if (error)
return error; return error;
error = zinitix_write_u16(client, BT541_INITIAL_TOUCH_MODE, error = zinitix_write_u16(client, ZINITIX_INITIAL_TOUCH_MODE,
bt541->zinitix_mode); bt541->zinitix_mode);
if (error) if (error)
return error; return error;
error = zinitix_write_u16(client, BT541_TOUCH_MODE, error = zinitix_write_u16(client, ZINITIX_TOUCH_MODE,
bt541->zinitix_mode); bt541->zinitix_mode);
if (error) if (error)
return error; return error;
error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG, error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG,
BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE | BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE |
BIT_UP); BIT_UP);
if (error) if (error)
...@@ -243,7 +243,7 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541) ...@@ -243,7 +243,7 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
/* clear queue */ /* clear queue */
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
zinitix_write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); zinitix_write_cmd(client, ZINITIX_CLEAR_INT_STATUS_CMD);
udelay(10); udelay(10);
} }
...@@ -361,7 +361,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) ...@@ -361,7 +361,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
memset(&touch_event, 0, sizeof(struct touch_event)); memset(&touch_event, 0, sizeof(struct touch_event));
error = zinitix_read_data(bt541->client, BT541_POINT_STATUS_REG, error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
&touch_event, sizeof(struct touch_event)); &touch_event, sizeof(struct touch_event));
if (error) { if (error) {
dev_err(&client->dev, "Failed to read in touchpoint struct\n"); dev_err(&client->dev, "Failed to read in touchpoint struct\n");
...@@ -381,7 +381,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) ...@@ -381,7 +381,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
input_sync(bt541->input_dev); input_sync(bt541->input_dev);
out: out:
zinitix_write_cmd(bt541->client, BT541_CLEAR_INT_STATUS_CMD); zinitix_write_cmd(bt541->client, ZINITIX_CLEAR_INT_STATUS_CMD);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment